You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ch...@apache.org on 2012/07/05 04:48:38 UTC

svn commit: r1357447 [3/4] - in /commons/sandbox/classscan/trunk: ./ api/ api/src/ api/src/main/ api/src/main/java/ api/src/main/java/org/ api/src/main/java/org/apache/ api/src/main/java/org/apache/commons/ api/src/main/java/org/apache/commons/classsca...

Added: commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/NameSet.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/NameSet.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/NameSet.java (added)
+++ commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/NameSet.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,87 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.util;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+
+import org.apache.commons.classscan.HasName;
+import org.apache.commons.classscan.spi.model.HasResolve;
+
+public class NameSet<V extends HasName & HasResolve> extends ResolveSet<V> {
+
+    private final static Comparator<HasName> REVERSE_COMPARE = new Comparator<HasName>() {
+        @Override
+        public int compare(HasName l, HasName r) {
+            String left = l.getName();
+            String right = r.getName();
+            
+            // "quick" compare
+            int diff = left.length() - right.length();
+            if (diff != 0) {
+                return diff;
+            }
+            // compare from end of strings - the names probably have long equivalent prefixes
+            for (int i = left.length(); --i > 0;) {
+                int d = left.charAt(i) - right.charAt(i);
+                if (d != 0) {
+                    return d;
+                }
+            }
+            return 0;
+        }
+    };
+
+    public NameSet(V[] values) {
+        super(values);
+        if(values!=null && values.length>0) {
+            Arrays.sort(values, REVERSE_COMPARE);
+        }
+    }
+
+    public NameSet(Class<V> clss, Collection<? extends V> workValues) {
+        this(collectionToArray(clss, workValues));
+     }
+
+    private static <D extends HasName> D[] collectionToArray(Class<D> collectionType, Collection<? extends D> workValues) {
+        if(workValues.isEmpty()) {
+            return null;
+        }
+        @SuppressWarnings("unchecked")
+        D[] newInstance = (D[]) Array.newInstance(collectionType, workValues.size());
+        return workValues.toArray(newInstance);
+    }
+
+    public V getValue(final String name) {
+        int idx= Arrays.binarySearch(values, new HasName() {
+            @Override
+            public String getName() {
+                return name;
+            }
+        }, REVERSE_COMPARE);
+        return idx<0 ? null : values[idx];
+    }
+
+    private static interface NameResolve extends HasName, HasResolve {};
+	private static NameSet<NameResolve> EMPTY_SET = new NameSet<NameResolve>(new NameResolve[0]);
+    
+	public static <V extends  HasName & HasResolve> NameSet<V> emptyNameSet() {
+		NameSet<?> qrc = (NameSet<?>) EMPTY_SET;
+		@SuppressWarnings("unchecked")
+		NameSet<V> rc = (NameSet<V>) qrc;
+		return rc;
+	}
+}

Added: commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReadOnlySet.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReadOnlySet.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReadOnlySet.java (added)
+++ commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReadOnlySet.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,164 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.util;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * Set of immutable instances.
+ * 
+ * @param <V>
+ *            The contained type
+ */
+public class ReadOnlySet<V> implements Set<V> {
+    
+    protected V[] values;
+
+    public ReadOnlySet(V[] values) {
+        if(values==null) {
+            throw new UnsupportedOperationException();
+        }
+        else {
+            this.values = values;
+        }
+    }
+
+    /**
+     * Subclasses may use this constructor to delay initialization of values.
+     * The derived class must call setValues before general use.
+     */
+    protected ReadOnlySet() {
+    }
+
+    /**
+     * @param values
+     *            The array to view
+     */
+    protected void setValues(V[] values) {
+        this.values = values;
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        for (V t : values) {
+            if (t.equals(o)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> collection) {
+        for (Object single : collection) {
+            if (!contains(single)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return values.length == 0;
+    }
+
+    @Override
+    public Iterator<V> iterator() {
+        return new Iterator<V>() {
+            int i;
+
+            @Override
+            public boolean hasNext() {
+                return i < values.length;
+            }
+
+            @Override
+            public V next() {
+                if (i == values.length) {
+                    throw new NoSuchElementException("Reading past end of iterator");
+                }
+                return values[i++];
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException("Read only iterator");
+            }
+        };
+    }
+
+    @Override
+    public int size() {
+        return values.length;
+    }
+
+    @Override
+    public Object[] toArray() {
+        return values.clone();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        int numberToNull = a.length - values.length;
+        if (numberToNull >= 0) {
+            System.arraycopy(values, 0, a, 0, values.length);
+            if (numberToNull > 0) {
+                Arrays.fill(a, values.length, a.length, null);
+            }
+            return a;
+        }
+
+        @SuppressWarnings("unchecked")
+        T[] rv = (T[]) Array.newInstance(a.getClass().getComponentType(), values.length);
+        System.arraycopy(values, 0, rv, 0, values.length);
+        return rv;
+    }
+
+    @Override
+    final public boolean add(V e) {
+        throw new UnsupportedOperationException("Set is readonly");
+    }
+
+    @Override
+    final public boolean addAll(Collection<? extends V> c) {
+        throw new UnsupportedOperationException("Set is readonly");
+    }
+
+    @Override
+    final public void clear() {
+        throw new UnsupportedOperationException("Set is readonly");
+    }
+
+    @Override
+    final public boolean remove(Object e) {
+        throw new UnsupportedOperationException("Set is readonly");
+    }
+
+    @Override
+    final public boolean removeAll(Collection<?> c) {
+        throw new UnsupportedOperationException("Set is readonly");
+    }
+
+    @Override
+    final public boolean retainAll(Collection<?> c) {
+        throw new UnsupportedOperationException("Set is readonly");
+    }
+
+}

Added: commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReapingHashMap.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReapingHashMap.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReapingHashMap.java (added)
+++ commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ReapingHashMap.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,176 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.util;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public final class ReapingHashMap<K, V> implements Map<K, V> {
+
+    private final ConcurrentMap<HashWeakReference<K>, V> innerMap = new ConcurrentHashMap<HashWeakReference<K>, V>();
+    private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
+    private final Thread reaper = new ReaperThread();
+
+    public ReapingHashMap() {
+        reaper.setDaemon(true);
+        reaper.start();
+    }
+
+    private class ReaperThread extends Thread {
+        ReaperThread() {
+            super("WeakConcurrentHashMap-" + System.identityHashCode(ReapingHashMap.this) + "-reaper");
+        }
+
+        @Override
+        public void run() {
+            for (;;) {
+                try {
+                    Reference<? extends K> ref = queue.remove();
+                    HashWeakReference<? extends K> key = (HashWeakReference<? extends K>) ref;
+                    innerMap.remove(key);
+                }
+                catch (InterruptedException ignore) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public V put(K key, V value) {
+        HashWeakReference<K> innerKey = new HashWeakReference<K>(key, queue);
+        return innerMap.put(innerKey, value);
+    }
+
+    @Override
+    public V get(Object key) {
+        KeyReference<Object> innerKey = new KeyReference<Object>(key);
+        return innerMap.get(innerKey);
+    }
+
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<Map.Entry<K, V>> entrySet() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<K> keySet() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public V remove(Object key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int size() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection<V> values() {
+        throw new UnsupportedOperationException();
+    }
+    
+    static class HashWeakReference<T> extends WeakReference<T> {
+        private final int hashCode;
+
+        HashWeakReference(T referent, ReferenceQueue<? super T> queue) {
+            super(referent, queue);
+            hashCode = System.identityHashCode(referent);
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCode;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+        	if(this==obj) {
+        		return true;
+        	}
+        	if(obj instanceof KeyReference) {
+        		@SuppressWarnings("unchecked")
+    			KeyReference<T> key= (KeyReference<T>)obj;
+        		return key.compare(this);
+        	}
+        	throw new UnsupportedOperationException(obj.getClass().getCanonicalName());
+        }
+    }
+
+    static class KeyReference<T> {
+    	private final T key;
+    	private final int keyHash;
+    	
+    	public KeyReference(T key) {
+    		this.key= key;
+    		keyHash= System.identityHashCode(key);
+    	}
+    	
+    	@Override
+    	public int hashCode() {
+    		return keyHash;
+    	}
+
+    	/**
+    	 * HashMap should only compare KeyReference with HashWeakReference
+    	 */
+    	@Override
+    	public boolean equals(Object obj) {
+    		if(obj instanceof  HashWeakReference) {
+    			@SuppressWarnings("unchecked")
+    			HashWeakReference<T> weakKey = (HashWeakReference<T>)obj;
+    			return compare(weakKey);
+    		}
+        	throw new UnsupportedOperationException(obj.getClass().getCanonicalName());
+    	}
+
+        boolean compare(HashWeakReference<T> ref) {	
+        	T t = ref.get();
+    		return key==t;
+        }
+    }
+}

Added: commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ResolveSet.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ResolveSet.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ResolveSet.java (added)
+++ commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ResolveSet.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,41 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.util;
+
+import org.apache.commons.classscan.spi.model.HasResolve;
+import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
+
+public class ResolveSet<V extends HasResolve> extends ReadOnlySet<V> {
+
+    public ResolveSet(V[] values) {
+        super(values);
+    }
+
+    public boolean resolve(SpiMetaClassLoader mcl) {
+    	for(V value : values) {
+    		if(!value.resolve(mcl)) {
+    			return false;
+    		}
+    	}
+    	return true;
+    }
+
+	private static ResolveSet<HasResolve> EMPTY_SET = new ResolveSet<HasResolve>(new HasResolve[0]);
+    
+	public static <V extends HasResolve> ResolveSet<V> emptyResolveSet() {
+		@SuppressWarnings("unchecked")
+		ResolveSet<V> rc = (ResolveSet<V>) EMPTY_SET;
+		return rc;
+	}
+}

Added: commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ServiceVisitor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ServiceVisitor.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ServiceVisitor.java (added)
+++ commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/ServiceVisitor.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.util;
+
+import java.util.Iterator;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Visit the provider instances specified in the META-INF/services directories
+ * 
+ * @param <T> The type of the provider
+ */
+public abstract class ServiceVisitor<T> {
+
+    private static final Logger logger = LoggerFactory.getLogger(ServiceVisitor.class);
+
+    /**
+     * Visit the service provider available for the given interface and ClassLoader
+     * 
+     * @param serviceInterface The interface of the service
+     * @param classLoader The ClassLoader which will load the service
+     */
+	public void visitProviders(Class<T> factoryClass, ClassLoader classLoader) {
+		Iterator<T> factories = ServiceLoader.load(factoryClass, classLoader).iterator();
+		for(;;) {
+			// this odd loop is due to the possibility of the iterator throwing
+			// ServiceConfigurationError from either hasNext() or next()
+			try {
+				if(!factories.hasNext()) {
+					break;
+				}
+				T factory = factories.next();
+		    	if(!visit(factory)) {
+		    		break;
+		    	}
+			}
+			catch(ServiceConfigurationError error) {
+				logger.warn("Ignoring configuration error", error);
+			}
+		}
+	}
+
+	/**
+	 * The callback method which is invoked upon finding a service provider
+	 * 
+	 * @param serviceProvider An instance of the service provider
+	 * @return true, if additional service providers desired; false, stop the visiting
+	 */
+	abstract protected boolean visit(T serviceProvider);
+}

Added: commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/package-info.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/package-info.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/package-info.java (added)
+++ commons/sandbox/classscan/trunk/api/src/main/java/org/apache/commons/classscan/util/package-info.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * <p>The util package consists of utility collection implementations to support the {@link org.apache.commons.classscan.bcel} package.</p>
+ * <p><b>These classes are subject to change in any release.</b></p>
+ */
+package org.apache.commons.classscan.util;
\ No newline at end of file

Added: commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathElementFactory
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathElementFactory?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathElementFactory (added)
+++ commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathElementFactory Thu Jul  5 02:48:34 2012
@@ -0,0 +1,15 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.commons.classscan.builtin.DefaultClassPathElementFactory

Added: commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathFactory
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathFactory?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathFactory (added)
+++ commons/sandbox/classscan/trunk/api/src/main/resources/META-INF/services/org.apache.commons.classscan.spi.ClassPathFactory Thu Jul  5 02:48:34 2012
@@ -0,0 +1,15 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.commons.classscan.builtin.DefaultClassPathFactory

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/AnnotationAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/AnnotationAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/AnnotationAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/AnnotationAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,22 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface AnnotationAnnotation {
+
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ConstructorAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ConstructorAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ConstructorAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ConstructorAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,22 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.CONSTRUCTOR)
+public @interface ConstructorAnnotation {
+
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/FieldAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/FieldAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/FieldAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/FieldAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,22 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+public @interface FieldAnnotation {
+
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/MethodAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/MethodAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/MethodAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/MethodAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,22 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+public @interface MethodAnnotation {
+
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ParameterAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ParameterAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ParameterAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/ParameterAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,22 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.PARAMETER)
+public @interface ParameterAnnotation {
+
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TestEnum.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TestEnum.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TestEnum.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TestEnum.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+public enum TestEnum {
+	One, Two, Three
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TypeAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TypeAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TypeAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/annotations/TypeAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,48 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+
+@Target(ElementType.TYPE)
+public @interface TypeAnnotation {
+
+	double doubleValue();
+
+	int longValue();
+
+	int shortValue();
+
+	String stringValue();
+
+	boolean booleanValue();
+
+	String[] stringArrayValue();
+
+	Class<Object> classValue();
+
+	AnnotationAnnotation annotationValue();
+
+	float floatValue();
+
+	char charValue();
+
+	int intValue();
+
+	int byteValue();
+
+	TestEnum enumValue();
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/BadPackage.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/BadPackage.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/BadPackage.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/BadPackage.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,30 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.wrong.test.classes;  // intentionally wrong package to force error condition
+
+public class BadPackage  {
+    String field;
+    
+    public BadPackage(String field) {
+        this.field = field;
+    }
+
+    public String getField() {
+        return field;
+    }
+
+    public void setField(String field) {
+        this.field = field;
+    }
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullInterface.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullInterface.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullInterface.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullInterface.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,26 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.classes;
+
+import org.apache.commons.classscan.test.annotations.MethodAnnotation;
+import org.apache.commons.classscan.test.annotations.ParameterAnnotation;
+
+public interface FullInterface {
+
+    @MethodAnnotation
+    int[] getField();
+
+    void setField(@ParameterAnnotation int[] field);
+
+}
\ No newline at end of file

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullyDecorated.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullyDecorated.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullyDecorated.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/FullyDecorated.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,53 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.classes;
+
+import java.io.Serializable;
+
+import org.apache.commons.classscan.test.annotations.AnnotationAnnotation;
+import org.apache.commons.classscan.test.annotations.ConstructorAnnotation;
+import org.apache.commons.classscan.test.annotations.FieldAnnotation;
+import org.apache.commons.classscan.test.annotations.MethodAnnotation;
+import org.apache.commons.classscan.test.annotations.ParameterAnnotation;
+import org.apache.commons.classscan.test.annotations.TestEnum;
+import org.apache.commons.classscan.test.annotations.TypeAnnotation;
+
+@TypeAnnotation(byteValue = 1, charValue = '&', doubleValue = Math.PI, floatValue = (float) Math.E, intValue = 42, longValue = 3360, shortValue = 1895, booleanValue = true, stringValue = "testing", stringArrayValue = {
+        "one", "two" }, enumValue = TestEnum.Three, classValue = Object.class, annotationValue = @AnnotationAnnotation)
+public class FullyDecorated implements Serializable, FullInterface {
+    private static final long serialVersionUID = 1L;
+
+    @FieldAnnotation
+    private int[] field;
+
+    public static long getSerialVersion() {
+        return serialVersionUID;
+    }
+
+    @ConstructorAnnotation
+    public FullyDecorated(int[] field) {
+        this.field = field;
+    }
+
+    @Override
+    @MethodAnnotation
+    public int[] getField() {
+        return field;
+    }
+
+    @Override
+    public void setField(@ParameterAnnotation int[] field) {
+        this.field = field;
+    }
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/ValidateFullyDecorated.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/ValidateFullyDecorated.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/ValidateFullyDecorated.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/test/classes/ValidateFullyDecorated.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,331 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.test.classes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.commons.classscan.model.MetaAnnotation;
+import org.apache.commons.classscan.model.MetaAnnotation.Property;
+import org.apache.commons.classscan.model.MetaArray;
+import org.apache.commons.classscan.model.MetaClass;
+import org.apache.commons.classscan.model.MetaField;
+import org.apache.commons.classscan.model.MetaMethod;
+import org.apache.commons.classscan.model.MetaParameter;
+import org.apache.commons.classscan.model.MetaType;
+import org.apache.commons.classscan.test.annotations.AnnotationAnnotation;
+import org.apache.commons.classscan.test.annotations.ConstructorAnnotation;
+import org.apache.commons.classscan.test.annotations.FieldAnnotation;
+import org.apache.commons.classscan.test.annotations.MethodAnnotation;
+import org.apache.commons.classscan.test.annotations.ParameterAnnotation;
+import org.apache.commons.classscan.test.annotations.TestEnum;
+import org.apache.commons.classscan.test.annotations.TypeAnnotation;
+
+public class ValidateFullyDecorated {
+
+    public ValidateFullyDecorated(MetaClass fdClass) {
+        assertClassParent(fdClass.getParent());
+        assertInterfaces(fdClass.getInterfaces());
+        assertClassAnnotations(fdClass.getAnnotations());
+        assertClassAnnotation(fdClass.getAnnotation(TypeAnnotation.class.getCanonicalName()));
+        assertMethods(fdClass.getMethods());
+        assertFields(fdClass.getFields());
+    }
+
+    private void assertClassParent(MetaClass objectClass) {
+        assertEquals(Object.class.getCanonicalName(), objectClass.getName());
+        assertNull(objectClass.getParent());
+    }
+
+    private void assertInterfaces(Set<? extends MetaClass> set) {
+        assertEquals(2, set.size());
+        for (MetaClass iface : set) {      
+            String interfaceName = iface.getName();
+            if(interfaceName.equals(Serializable.class.getCanonicalName())) {
+                continue;
+            }
+            else if(interfaceName.equals(FullInterface.class.getCanonicalName())) {
+                continue;
+            }
+            else {
+                fail("unexpected interface " + interfaceName);
+            }
+        }
+        assertReadOnlySet(set);
+    }
+
+    private void assertClassAnnotations(Set<? extends MetaAnnotation> collection) {
+        assertEquals(1, collection.size());
+        for (MetaAnnotation annotation : collection) {
+            assertEquals(TypeAnnotation.class.getCanonicalName(), annotation.getName());
+            assertClassAnnotation(annotation);
+        }
+        assertReadOnlySet(collection);
+    }
+
+    private void assertClassAnnotation(MetaAnnotation annotation) {
+        Collection<? extends Property> properties = annotation.getProperties();
+        assertEquals(13, properties.size());
+        for (MetaAnnotation.Property property : properties) {
+            String propertyName = property.getName();
+            if (propertyName.equals("byteValue")) {
+                assertEquals(new Byte((byte) 1), property.getValue());
+            }
+            else if (propertyName.equals("charValue")) {
+                assertEquals(new Character('&'), property.getValue());
+            }
+            else if (propertyName.equals("doubleValue")) {
+                assertEquals(new Double(Math.PI), property.getValue());
+            }
+            else if (propertyName.equals("floatValue")) {
+                assertEquals(new Float(Math.E), property.getValue());
+            }
+            else if (propertyName.equals("intValue")) {
+                assertEquals(new Integer(42), property.getValue());
+            }
+            else if (propertyName.equals("longValue")) {
+                assertEquals(new Long(3360), property.getValue());
+            }
+            else if (propertyName.equals("shortValue")) {
+                assertEquals(new Short((short) 1895), property.getValue());
+            }
+            else if (propertyName.equals("booleanValue")) {
+                assertEquals(Boolean.TRUE, property.getValue());
+            }
+            else if (propertyName.equals("stringValue")) {
+                assertEquals("testing", property.getValue());
+            }
+            else if (propertyName.equals("stringArrayValue")) {
+                assertTrue(Arrays.deepEquals(new String[] { "one", "two" }, (Object[]) property.getValue()));
+            }
+            else if (propertyName.equals("annotationValue")) {
+                MetaAnnotation ma = (MetaAnnotation) property.getValue();
+                assertEquals(AnnotationAnnotation.class.getCanonicalName(), ma.getName());
+            }
+            else if (propertyName.equals("enumValue")) {
+                MetaAnnotation.EnumValue ev = (MetaAnnotation.EnumValue) property.getValue();
+                assertEquals(TestEnum.class.getCanonicalName(), ev.getEnumType().getName());
+                assertEquals("Three", ev.getEnumValue());
+            }
+            else if (propertyName.equals("classValue")) {
+                MetaClass mc = (MetaClass) property.getValue();
+                assertEquals(Object.class.getCanonicalName(), mc.getName());
+            }
+            else {
+                fail("unexpected property " + propertyName);
+            }
+        }
+
+        MetaAnnotation.Property byteValue = annotation.getProperty("byteValue");
+        assertEquals(new Byte((byte) 1), byteValue.getValue());
+        assertNull(annotation.getProperty("freddy"));
+    }
+
+    private void assertFields(Set<? extends MetaField> set) {
+        assertEquals(2, set.size());
+        for (MetaField field : set) {
+            if (field.getName().equals("field")) {
+                assertField(field);
+            }
+            else if (field.getName().equals("serialVersionUID")) {
+                assertSerialVersionField(field);
+            }
+            else {
+                fail("unexpected field " + field.getName());
+            }
+        }
+        assertReadOnlySet(set);
+    }
+
+    private void assertField(MetaField field) {
+        assertEquals(false, field.isStatic());
+        assertIntegerArrayType(field.getType());
+        assertAnnotation(FieldAnnotation.class.getCanonicalName(), field.getAnnotations());
+    }
+
+    private void assertLongType(MetaType mt) {
+        MetaClass mc = (MetaClass)mt;
+        assertEquals(Long.TYPE.getCanonicalName(), mc.getName());
+    }
+
+    private void assertIntegerArrayType(MetaType mt) {
+    	MetaArray ma = (MetaArray)mt;
+        MetaClass mc = (MetaClass)ma.getArrayType();
+        assertEquals(Integer.TYPE.getCanonicalName(), mc.getName());
+    }
+
+    private void assertSerialVersionField(MetaField field) {
+        assertEquals(true, field.isStatic());
+        assertLongType(field.getType());
+        Set<? extends MetaAnnotation> annotations = field.getAnnotations();
+        assertTrue(annotations.isEmpty());
+        assertReadOnlySet(annotations);
+    }
+
+    private void assertMethods(Set<? extends MetaMethod> set) {
+        assertEquals(4, set.size());
+        for (MetaMethod method : set) {
+            String methodName = method.getName();
+            if (methodName.equals("<init>")) {
+                assertConstructor(method);
+            }
+            else if (methodName.equals("getField")) {
+                assertGetFieldMethod(method);
+            }
+            else if (methodName.equals("getSerialVersion")) {
+                assertGetSerialVersionMethod(method);
+            }
+            else if (methodName.equals("setField")) {
+                assertSetFieldMethod(method);
+            }
+            else {
+                fail("unexpected method " + methodName);
+            }
+        }
+        assertReadOnlySet(set);
+    }
+
+    private void assertAnnotation(String annotationName, Set<? extends MetaAnnotation> set) {
+        assertEquals(1, set.size());
+        for (MetaAnnotation annotation : set) {
+            assertEquals(annotationName, annotation.getName());
+        }
+    }
+
+    private void assertGetFieldMethod(MetaMethod method) {
+        assertEquals(false, method.isStatic());
+        assertIntegerArrayType(method.getType());
+        assertAnnotation(MethodAnnotation.class.getCanonicalName(), method.getAnnotations());
+    }
+
+    private void assertGetSerialVersionMethod(MetaMethod method) {
+        assertEquals(true, method.isStatic());
+        assertLongType(method.getType());
+        assertTrue(method.getAnnotations().isEmpty());
+    }
+
+    private void assertConstructor(MetaMethod method) {
+        assertAnnotation(ConstructorAnnotation.class.getCanonicalName(), method.getAnnotations());
+    }
+
+    private void assertSetFieldMethod(MetaMethod method) {
+        Set<? extends MetaParameter> parameters = method.getParameters();
+        assertEquals(1, parameters.size());
+
+        for (MetaParameter parameter : parameters) {
+            assertAnnotation(ParameterAnnotation.class.getCanonicalName(), parameter.getAnnotations());
+            assertIntegerArrayType(parameter.getType());
+        }
+        assertReadOnlySet(parameters);
+    }
+
+    private <T> void assertReadOnlySet(Set<T> collection) {
+        Object[] cpy = collection.toArray();
+        Object[] allocatedArray = new Object[2];
+        Object[] cpy2 = collection.toArray(allocatedArray);
+        if (collection.size() <= 2) {
+            assertSame(allocatedArray, cpy2);
+            if (collection.size() == 1) {
+                assertNull(cpy2[1]);
+            }
+        }
+        int i = 0;
+        for (T element : collection) {
+            assertEquals(element, cpy[i++]);
+        }
+        if(collection.isEmpty()) {
+            return;
+        }
+
+        assertTrue(collection.containsAll(collection));
+        try {
+            collection.clear();
+            fail("Set not acting read-only");
+        }
+        catch (UnsupportedOperationException expected) {
+        }
+        try {
+            collection.addAll(collection);
+            fail("Set not acting read-only");
+        }
+        catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            collection.retainAll(collection);
+            fail("Set not acting read-only");
+        }
+        catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            collection.removeAll(collection);
+            fail("Set not acting read-only");
+        }
+        catch (UnsupportedOperationException expected) {
+        }
+
+        assertFalse(collection.contains(this));
+
+        Iterator<T> iterator = collection.iterator();
+        if (collection.isEmpty()) {
+            assertFalse(iterator.hasNext());
+            try {
+                iterator.next();
+                fail("Iterating past end of elements");
+            }
+            catch (NoSuchElementException expected) {
+            }
+
+            Set<T> singleValueSet = new HashSet<T>(1);
+            singleValueSet.add(null);
+
+            assertFalse(collection.containsAll(singleValueSet));
+        }
+        else {
+            T singleValue = iterator.next();
+            try {
+                iterator.remove();
+                fail("Iterator not acting read-only");
+            }
+            catch (UnsupportedOperationException expected) {
+            }
+            assertTrue(collection.contains(singleValue));
+            try {
+                collection.remove(singleValue);
+                fail("Set not acting read-only");
+            }
+            catch (UnsupportedOperationException expected) {
+            }
+            try {
+                collection.add(singleValue);
+                fail("Set not acting read-only");
+            }
+            catch (UnsupportedOperationException expected) {
+            }
+        }
+    }
+}

Added: commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/util/ReapingHashMapTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/util/ReapingHashMapTest.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/util/ReapingHashMapTest.java (added)
+++ commons/sandbox/classscan/trunk/api/src/test/java/org/apache/commons/classscan/util/ReapingHashMapTest.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,105 @@
+package org.apache.commons.classscan.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+public class ReapingHashMapTest {
+
+	@Test
+	public void testHashWeakReferenceIsCollected() throws InterruptedException {
+		ReferenceQueue<BigObject> queue = new ReferenceQueue<BigObject>();
+		ReapingHashMap.HashWeakReference<BigObject> hwr = new ReapingHashMap.HashWeakReference<BigObject>(new BigObject(2), queue);
+		assertNotNull(hwr.get());
+		forceWeakRefCollection(queue, hwr);
+	}
+
+	@Test
+	public void testNullReferenceIsNotCollected() throws InterruptedException {
+		ReferenceQueue<BigObject> queue = new ReferenceQueue<BigObject>();
+
+		ReapingHashMap.HashWeakReference<BigObject> nullRef = new ReapingHashMap.HashWeakReference<BigObject>(null, queue);
+		assertNull(nullRef.get());
+		
+		ReapingHashMap.HashWeakReference<BigObject> nnRef = new ReapingHashMap.HashWeakReference<BigObject>(new BigObject(2), queue);
+		forceWeakRefCollection(queue, nnRef);
+		
+		assertFalse(nullRef.isEnqueued());
+		assertNull(queue.poll());
+	}
+
+	@Test(timeout=10000)
+	public void testReapingHashMapIsCollected() throws InterruptedException {
+		ReapingHashMap<BigObject, Integer> rhm = new ReapingHashMap<BigObject, Integer>();
+		WeakReference<BigObject> key = notReaped(rhm);
+		do {
+			testHashWeakReferenceIsCollected();
+		}
+		while(key.get()!=null);
+	}
+
+	public WeakReference<BigObject> notReaped(ReapingHashMap<BigObject, Integer> rhm) {
+		BigObject key = new BigObject(2);
+		Integer value = new Integer(2);
+
+		assertNull(rhm.get(null));		
+		assertNull(rhm.get(key));
+
+		rhm.put(key, value);
+		assertEquals(value, rhm.get(key));
+				
+		Integer nullValue = new Integer(0);
+		rhm.put(null, nullValue);
+		assertEquals(nullValue, rhm.get(null));
+		
+		return new WeakReference<BigObject>(key);
+	}
+	
+	static class BigObject {
+		byte[][] lotsOfMemory;
+
+		BigObject(int max) {
+			byte[][] holder= new byte[max][];
+			int power= 1;
+			for(int i= 0; i<holder.length; ++i) {
+				byte[] bytes= new byte[power];
+				holder[i]= bytes;
+				power*= 2;
+			}
+		}
+	};
+	
+	public <T> void forceWeakRefCollection(ReferenceQueue<T> queue, WeakReference<T> ref) throws InterruptedException {
+
+		List<BigObject> list = new ArrayList<BigObject>();
+		for (int i = 0; true; i++) {
+			try {
+				BigObject holder = new BigObject(i);
+				list.add(holder);
+			} catch (OutOfMemoryError oome) {
+				i = 0;
+			}
+			
+			if(ref.isEnqueued()) {
+				assertTrue(ref.isEnqueued());
+				Reference<? extends T> pollRef = queue.remove(1000);
+				assertSame(pollRef, ref);
+				assertEquals(pollRef, ref);
+				assertFalse(ref.isEnqueued());
+				assertNull(ref.get());
+				return;
+			}
+		}
+	}
+}
\ No newline at end of file

Added: commons/sandbox/classscan/trunk/api/src/test/resources/META-INF/services/org.apache.commons.classscan.test.classes.FullInterface
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/resources/META-INF/services/org.apache.commons.classscan.test.classes.FullInterface?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/resources/META-INF/services/org.apache.commons.classscan.test.classes.FullInterface (added)
+++ commons/sandbox/classscan/trunk/api/src/test/resources/META-INF/services/org.apache.commons.classscan.test.classes.FullInterface Thu Jul  5 02:48:34 2012
@@ -0,0 +1,15 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.commons.classcan.test.classes.FullyDecorated

Added: commons/sandbox/classscan/trunk/api/src/test/resources/logback.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/resources/logback.xml?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/resources/logback.xml (added)
+++ commons/sandbox/classscan/trunk/api/src/test/resources/logback.xml Thu Jul  5 02:48:34 2012
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration debug="false">
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">	
+       <layout class="ch.qos.logback.classic.PatternLayout">
+         <pattern>%logger{15} %level: %message %nopex%n</pattern>
+       </layout>
+    </appender>
+    
+    <root>
+        <level value="INFO" />
+        <appender-ref ref="STDOUT" />
+    </root>
+    
+</configuration>
\ No newline at end of file

Added: commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/--InvalidClassName--.class
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/--InvalidClassName--.class?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/--InvalidClassName--.class (added)
+++ commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/--InvalidClassName--.class Thu Jul  5 02:48:34 2012
@@ -0,0 +1,2 @@
+
+This is a file that is not a class.  This file exists to force error condition.
\ No newline at end of file

Added: commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/NotAClass.class
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/NotAClass.class?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/NotAClass.class (added)
+++ commons/sandbox/classscan/trunk/api/src/test/resources/org/apache/commons/classscan/test/classes/NotAClass.class Thu Jul  5 02:48:34 2012
@@ -0,0 +1,2 @@
+
+This is a file that is not a class.  This file exists to force error condition.
\ No newline at end of file

Added: commons/sandbox/classscan/trunk/bcel/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/pom.xml?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/pom.xml (added)
+++ commons/sandbox/classscan/trunk/bcel/pom.xml Thu Jul  5 02:48:34 2012
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  
+  <groupId>org.apache.commons.classscan</groupId>
+  <artifactId>bcel</artifactId>
+  <name>ClassScan BCEL class reader provider</name>
+  <version>0.2-SNAPSHOT</version>
+  <description>The Class Digester using BCEL to read class definitions</description>
+  
+  <parent>
+    <groupId>org.apache.commons.classscan</groupId>
+    <artifactId>parent</artifactId>
+    <version>0.2-SNAPSHOT</version>
+	<relativePath>../parent</relativePath>
+  </parent>
+   
+  <dependencies>
+
+    <dependency>
+       <groupId>org.apache.commons.classscan</groupId>
+       <artifactId>api</artifactId>
+      <version>0.2-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons.classscan</groupId>
+      <artifactId>api</artifactId>
+      <version>0.2-SNAPSHOT</version>
+	  <type>test-jar</type>
+	  <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.bcel</groupId>
+      <artifactId>bcel</artifactId>
+      <version>6.0-SNAPSHOT</version>
+    </dependency>
+
+  </dependencies>
+
+</project>

Added: commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/AnnotationMap.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/AnnotationMap.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/AnnotationMap.java (added)
+++ commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/AnnotationMap.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,42 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.bcel;
+
+import org.apache.bcel.classfile.AnnotationEntry;
+import org.apache.commons.classscan.util.NameSet;
+
+public class AnnotationMap extends NameSet<BcelAnnotation> {
+
+	private static AnnotationMap EMPTY_ANNOTATIONS= new AnnotationMap(new AnnotationEntry[0]);
+	
+	public static AnnotationMap createAnnotations(AnnotationEntry[] annotationEntries) {
+        if(annotationEntries==null || annotationEntries.length==0) {
+        	return EMPTY_ANNOTATIONS;
+        }
+		return new AnnotationMap(annotationEntries);
+	}
+	
+    private AnnotationMap(AnnotationEntry[] entries) {
+        super(transformEntries(entries));
+    }
+
+    static private BcelAnnotation[] transformEntries(AnnotationEntry[] entries) {
+    	        
+    	BcelAnnotation[] annotations = new BcelAnnotation[entries.length];
+        for(int i = 0; i<entries.length; ++i) {
+        	annotations[i]= new BcelAnnotation(entries[i]);
+        }
+        return annotations;
+    }
+}

Added: commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelAnnotation.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelAnnotation.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelAnnotation.java (added)
+++ commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelAnnotation.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,69 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.bcel;
+
+import java.util.Set;
+
+import org.apache.bcel.classfile.AnnotationEntry;
+import org.apache.bcel.classfile.ElementValuePair;
+import org.apache.commons.classscan.builtin.ClassNameHelper;
+import org.apache.commons.classscan.spi.model.SpiMetaAnnotation;
+import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
+import org.apache.commons.classscan.util.NameSet;
+
+public class BcelAnnotation implements SpiMetaAnnotation {
+
+    private final String name;
+    private final NameSet<SpiProperty> properties;
+
+    public BcelAnnotation(AnnotationEntry annotation) {
+        name = ClassNameHelper.internalToCanonicalName(annotation.getAnnotationType());
+
+        ElementValuePair[] elementValuePairs = annotation.getElementValuePairs();
+        if (elementValuePairs.length == 0) {
+            properties = NameSet.emptyNameSet();
+        }
+        else {
+            properties = new NameSet<SpiProperty>(fillMapAndArray(elementValuePairs));
+        }
+    }
+
+	@Override
+	public boolean resolve(SpiMetaClassLoader classLoader) {
+		return properties.resolve(classLoader);
+	}
+
+    private SpiProperty[] fillMapAndArray(ElementValuePair[] evPairs) {
+        SpiProperty[] values = new SpiProperty[evPairs.length];
+        for (int i = 0; i < evPairs.length; ++i) {
+            values[i] = new BcelProperty(evPairs[i]);
+        }
+        return values;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Set<? extends Property> getProperties() {
+        return properties;
+    }
+
+    @Override
+    public Property getProperty(String propertyName) {
+        return properties.getValue(propertyName);
+    }
+}

Added: commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClass.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClass.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClass.java (added)
+++ commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClass.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,239 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.bcel;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.apache.bcel.classfile.ClassFormatException;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+import org.apache.commons.classscan.MetaClassPathElement;
+import org.apache.commons.classscan.model.MetaAnnotation;
+import org.apache.commons.classscan.model.MetaClass;
+import org.apache.commons.classscan.model.MetaField;
+import org.apache.commons.classscan.model.MetaMethod;
+import org.apache.commons.classscan.spi.model.SpiMetaClass;
+import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
+import org.apache.commons.classscan.spi.model.SpiMetaField;
+import org.apache.commons.classscan.spi.model.SpiMetaMethod;
+import org.apache.commons.classscan.util.NameSet;
+import org.apache.commons.classscan.util.ReadOnlySet;
+import org.apache.commons.classscan.util.ResolveSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BcelClass implements SpiMetaClass {
+
+    private static final Logger logger = LoggerFactory.getLogger(BcelClass.class);
+
+    private final MetaClassPathElement location;
+    private final String canonicalName;
+    private String parentName;
+    private MetaClass parent;
+    private String[] interfaceNames;
+    private Set<MetaClass> interfaces;
+    private final AnnotationMap annotations;
+    private final ResolveSet<SpiMetaMethod> methods;
+    private final ResolveSet<SpiMetaField> fields;
+    private Boolean resolutionResult;
+
+	public BcelClass(MetaClassPathElement location, ClassParser parser) throws ClassFormatException, IOException {
+        this.location = location;
+        JavaClass bcelClass = parser.parse();
+        canonicalName = bcelClass.getClassName();
+        parentName = getParentName(bcelClass);
+        interfaceNames = bcelClass.getInterfaceNames();
+        annotations = AnnotationMap.createAnnotations(bcelClass.getAnnotationEntries());
+        methods = createMethods(bcelClass);
+        fields = createFields(bcelClass);
+    }
+
+	@Override
+	public boolean resolve(SpiMetaClassLoader classLoader) {
+		if(resolutionResult == null) {
+			// set result to true to prevent re-resolution of classes involved in cyclic graphs
+			resolutionResult = Boolean.TRUE;
+			resolutionResult= Boolean.valueOf(resolveParent(classLoader)
+					&& resolveInterfaces(classLoader)
+					&& annotations.resolve(classLoader)
+					&& methods.resolve(classLoader)
+					&& fields.resolve(classLoader));
+		}
+		return resolutionResult;
+	}
+
+	private boolean resolveParent(SpiMetaClassLoader classLoader) {
+		boolean success = true;
+		if(parentName == null) {
+			// this is java.lang.Object
+			// parent should remain null
+		}
+		else {
+			parent = classLoader.resolveMetaClass(parentName);
+			if(parent == null) {
+    			logger.info("Cannot find parent "+parentName+" for class "+canonicalName);
+    			success= false;
+			}
+			parentName = null;			
+		}
+		return success;
+	}
+
+    private static final ReadOnlySet<MetaClass> EMPTY_INTERFACES = new ReadOnlySet<MetaClass>(new MetaClass[0]);
+
+    private boolean resolveInterfaces(final SpiMetaClassLoader classLoader) {
+    	boolean success= true;
+        if (interfaceNames==null || interfaceNames.length == 0) {
+        	interfaces= EMPTY_INTERFACES;
+        }
+        else {
+	        MetaClass[] metaClasses = new MetaClass[interfaceNames.length];
+	        int i= 0;
+	        for(String interfaceName : interfaceNames) {
+	            MetaClass mc = classLoader.resolveMetaClass(interfaceName);
+	            if(mc == null) {
+	    			logger.info("Cannot find interface "+interfaceName+" for class "+canonicalName);
+	    			success= false;
+	            }
+	            metaClasses[i++] = mc;
+	        }
+	        interfaces= new ReadOnlySet<MetaClass>(metaClasses);
+        }
+        interfaceNames= null;
+        return success;
+    }
+
+    @Override
+    public MetaClassPathElement getClassLocation() {
+        return location;
+    }
+
+    @Override
+    public String getName() {
+        return canonicalName;
+    }
+
+    @Override
+    public MetaClass getParent() {
+        return parent;
+    }
+
+    private String getParentName(JavaClass bcelClass) {
+        String superclassName = bcelClass.getSuperclassName();
+        if (superclassName.equals(canonicalName)) { // bcel behaves
+                                                    // unexpectedly, Object's
+                                                    // super class is Object
+            return null;
+        }
+        return superclassName;
+    }
+
+    @Override
+    public Set<MetaClass> getInterfaces() {
+        return interfaces;
+    }
+
+    @Override
+    public Set<? extends MetaAnnotation> getAnnotations() {
+        return annotations;
+    }
+
+    @Override
+    public MetaAnnotation getAnnotation(String annotationName) {
+        return annotations.getValue(annotationName);
+    }
+
+    @Override
+    public Set<? extends MetaMethod> getMethods() {
+        return methods;
+    }
+
+    private NameSet<SpiMetaMethod> createMethods(JavaClass bcelClass) {
+        Method[] methods = bcelClass.getMethods();
+        if (methods.length == 0) {
+            return NameSet.emptyNameSet();
+        }
+        
+        SpiMetaMethod[] metaMethods = new SpiMetaMethod[methods.length];
+        for(int i = 0; i<methods.length; ++i) {
+            metaMethods[i]= new BcelMethod(methods[i]);
+        }
+        
+        return new NameSet<SpiMetaMethod>(metaMethods);
+    }
+
+    @Override
+    public Set<? extends MetaField> getFields() {
+        return fields;
+    }
+
+    private ResolveSet<SpiMetaField> createFields(JavaClass bcelClass) {
+        Field[] fields = bcelClass.getFields();
+        if (fields.length == 0) {
+            return NameSet.emptyNameSet();
+        }
+        
+        SpiMetaField[] metaFields = new SpiMetaField[fields.length];
+        for(int i = 0; i<fields.length; ++i) {
+        	metaFields[i]= new BcelField(fields[i]);
+        }
+        
+        return new ResolveSet<SpiMetaField>(metaFields);
+    }
+
+    @Override
+    public boolean isAssignableFrom(MetaClass assignor) {
+        do {
+            if (isAssignableFromAnyInterface(assignor)) {
+                return true;
+            }
+            assignor = assignor.getParent();
+        }
+        while (assignor != null);
+        return false;
+    }
+
+    private boolean isAssignableFromAnyInterface(MetaClass assignor) {
+        if (equals(assignor)) {
+            return true;
+        }
+        for (MetaClass derived : assignor.getInterfaces()) {
+            if (isAssignableFromAnyInterface(derived)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof MetaClass)) {
+            return false;
+        }
+        MetaClass other = (MetaClass) obj;
+        return canonicalName.equals(other.getName()) && location.equals(other.getClassLocation());
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 33;
+        int result = 1;
+        result = prime * result + canonicalName.hashCode();
+        result = prime * result + location.hashCode();
+        return result;
+    }
+}

Added: commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClassDigesterFactory.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClassDigesterFactory.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClassDigesterFactory.java (added)
+++ commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelClassDigesterFactory.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,44 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.bcel;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.commons.classscan.MetaClassPathElement;
+import org.apache.commons.classscan.MetaRegistry;
+import org.apache.commons.classscan.spi.ClassDigesterFactory;
+import org.apache.commons.classscan.spi.model.SpiClassDigester;
+import org.apache.commons.classscan.spi.model.SpiMetaClass;
+
+/**
+ * A ClassDigesterFactory that uses BCEL to digest the class bytes
+ */
+public class BcelClassDigesterFactory implements ClassDigesterFactory {
+
+    // making digester an instance field ensures that BCEL library is loaded.
+    // If load is successful, this factory will produce a usable digester
+    private SpiClassDigester spiClassDigester = new SpiClassDigester() {
+		@Override
+		public SpiMetaClass createMetaClass(MetaClassPathElement location, String className, InputStream byteStream) throws IOException {
+			return new BcelClass(location, new ClassParser(byteStream, className));
+		}
+	};
+
+	@Override
+	public SpiClassDigester createDigester(MetaRegistry metaRegistry) {
+		return spiClassDigester;
+	}
+}

Added: commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelEnumProperty.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelEnumProperty.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelEnumProperty.java (added)
+++ commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelEnumProperty.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,37 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.bcel;
+
+import org.apache.commons.classscan.model.MetaAnnotation;
+import org.apache.commons.classscan.model.MetaClass;
+
+public class BcelEnumProperty implements MetaAnnotation.EnumValue {
+    final private MetaClass enumType;
+    final private String enumValue;
+
+    public BcelEnumProperty(MetaClass enumType, String enumValue) {
+        this.enumType = enumType;
+        this.enumValue = enumValue;
+    }
+
+    @Override
+    public MetaClass getEnumType() {
+        return enumType;
+    }
+
+    @Override
+    public String getEnumValue() {
+        return enumValue;
+    }
+}

Added: commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelField.java
URL: http://svn.apache.org/viewvc/commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelField.java?rev=1357447&view=auto
==============================================================================
--- commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelField.java (added)
+++ commons/sandbox/classscan/trunk/bcel/src/main/java/org/apache/commons/classscan/bcel/BcelField.java Thu Jul  5 02:48:34 2012
@@ -0,0 +1,74 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.classscan.bcel;
+
+import java.util.Set;
+
+import org.apache.bcel.classfile.Field;
+import org.apache.commons.classscan.model.MetaAnnotation;
+import org.apache.commons.classscan.model.MetaType;
+import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
+import org.apache.commons.classscan.spi.model.SpiMetaField;
+
+public class BcelField implements SpiMetaField {
+
+    private final String fieldName;
+    private final boolean isStatic;
+    private String fieldSignature;
+    private MetaType metaType;
+    private final AnnotationMap annotations;
+
+    public BcelField(Field field) {
+        fieldName = field.getName();
+        isStatic = field.isStatic();
+        fieldSignature = field.getSignature();
+        annotations = AnnotationMap.createAnnotations(field.getAnnotationEntries());
+    }
+
+	@Override
+	public boolean resolve(SpiMetaClassLoader classLoader) {
+		metaType = classLoader.resolveTypeForDescriptor(fieldSignature);
+		if(metaType == null) {
+			return false;
+		}
+		fieldSignature = null;
+		
+		return annotations.resolve(classLoader);
+	}
+
+    @Override
+    public String getName() {
+        return fieldName;
+    }
+
+    @Override
+    public Set<? extends MetaAnnotation> getAnnotations() {
+        return annotations;
+    }
+
+    @Override
+    public MetaAnnotation getAnnotation(String annotationName) {
+        return annotations.getValue(annotationName);
+    }
+
+    @Override
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    @Override
+    public MetaType getType() {
+        return metaType;
+    }
+}