You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xbean-scm@geronimo.apache.org by db...@apache.org on 2012/02/26 21:20:10 UTC

svn commit: r1293927 - in /geronimo/xbean/trunk/xbean-finder/src: main/java/org/apache/xbean/finder/ main/java/org/apache/xbean/finder/archive/ test/java/org/apache/xbean/finder/

Author: dblevins
Date: Sun Feb 26 20:20:10 2012
New Revision: 1293927

URL: http://svn.apache.org/viewvc?rev=1293927&view=rev
Log:
XBEAN-202: AnnotationFinder.select(String... classnames) allows narrowing of finder scope
XBEAN-201: JarArchive and FileArchive cache results so re-iterating is cheap

Added:
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/FinderSelectTest.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SelectMetaAnnotatedClassTest.java
      - copied, changed from r1291554, geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/MetaAnnotatedClassTest.java
Modified:
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/FileArchive.java
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java

Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java?rev=1293927&r1=1293926&r2=1293927&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java Sun Feb 26 20:20:10 2012
@@ -43,9 +43,11 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -72,6 +74,80 @@ public class AnnotationFinder implements
     private final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES;
     private final Archive archive;
 
+    private AnnotationFinder(AnnotationFinder parent, Iterable<String> classNames) {
+        this.archive = new SubArchive(classNames);
+        this.metaroots.addAll(parent.metaroots);
+        for (Class<? extends Annotation> metaroot : metaroots) {
+            final ClassInfo info = parent.classInfos.get(metaroot.getName());
+            if (info == null) continue;
+            readClassDef(info);
+        }
+        for (String name : classNames) {
+            final ClassInfo info = parent.classInfos.get(name);
+            if (info == null) continue;
+            readClassDef(info);
+        }
+
+        resolveAnnotations(parent, new ArrayList<String>());
+        for (ClassInfo classInfo : classInfos.values()) {
+            if (isMetaRoot(classInfo)) {
+                try {
+                    metaroots.add((Class<? extends Annotation>) classInfo.get());
+                } catch (ClassNotFoundException e) {
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+
+        for (Class<? extends Annotation> metaroot : metaroots) {
+            List<Info> infoList = annotated.get(metaroot.getName());
+            for (Info info : infoList) {
+                final String className = info.getName() + "$$";
+                final ClassInfo i = parent.classInfos.get(className);
+                if (i == null) continue;
+                readClassDef(i);
+            }
+        }
+    }
+
+    private void readClassDef(ClassInfo info) {
+        classInfos.put(info.name, info);
+        index(info);
+        index(info.constructors);
+        index(info.methods);
+        index(info.fields);
+    }
+
+    private void resolveAnnotations(AnnotationFinder parent, List<String> scanned) {
+        // Get a list of the annotations that exist before we start
+        final List<String> annotations = new ArrayList<String>(annotated.keySet());
+
+        for (String annotation : annotations) {
+            if (scanned.contains(annotation)) continue;
+            final ClassInfo info = parent.classInfos.get(annotation);
+            if (info == null) continue;
+            readClassDef(info);
+        }
+
+        // If the "annotated" list has grown, then we must scan those
+        if (annotated.keySet().size() != annotations.size()) {
+            resolveAnnotations(parent, annotations);
+        }
+    }
+
+
+    private void index(List<? extends Info> infos) {
+        for (Info i : infos) {
+            index(i);
+        }
+    }
+
+    private void index(Info i) {
+        for (AnnotationInfo annotationInfo : i.getAnnotations()) {
+            index(annotationInfo, i);
+        }
+    }
+
     public AnnotationFinder(Archive archive) {
         this.archive = archive;
 
@@ -832,6 +908,12 @@ public class AnnotationFinder implements
     }
 
     protected List<Info> getAnnotationInfos(String name) {
+        final List<Info> infos = annotated.get(name);
+        if (infos != null) return infos;
+        return Collections.EMPTY_LIST;
+    }
+
+    protected List<Info> initAnnotationInfos(String name) {
         List<Info> infos = annotated.get(name);
         if (infos == null) {
             infos = new SingleLinkedList<Info>();
@@ -862,7 +944,7 @@ public class AnnotationFinder implements
         if (aPackage != null) {
             final PackageInfo info = new PackageInfo(aPackage);
             for (AnnotationInfo annotation : info.getAnnotations()) {
-                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
+                List<Info> annotationInfos = initAnnotationInfos(annotation.getName());
                 if (!annotationInfos.contains(info)) {
                     annotationInfos.add(info);
                 }
@@ -886,12 +968,56 @@ public class AnnotationFinder implements
 
         for (Info info : infos) {
             for (AnnotationInfo annotation : info.getAnnotations()) {
-                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
+                List<Info> annotationInfos = initAnnotationInfos(annotation.getName());
                 annotationInfos.add(info);
             }
         }
     }
 
+    public AnnotationFinder select(Class<?>... clazz) {
+        String[] names = new String[clazz.length];
+        int i = 0;
+        for (Class<?> name : clazz) {
+            names[i++] = name.getName();
+        }
+
+        return new AnnotationFinder(this, Arrays.asList(names));
+    }
+
+    public AnnotationFinder select(String... clazz) {
+        return new AnnotationFinder(this, Arrays.asList(clazz));
+    }
+
+    public AnnotationFinder select(Iterable<String> clazz) {
+        return new AnnotationFinder(this, clazz);
+    }
+
+    public class SubArchive implements Archive {
+        private List<String> classes = new ArrayList<String>();
+
+        public SubArchive(String... classes) {
+            Collections.addAll(this.classes, classes);
+        }
+
+        public SubArchive(Iterable<String> classes) {
+            for (String name : classes) {
+                this.classes.add(name);
+            }
+        }
+
+        public InputStream getBytecode(String className) throws IOException, ClassNotFoundException {
+            return archive.getBytecode(className);
+        }
+
+        public Class<?> loadClass(String className) throws ClassNotFoundException {
+            return archive.loadClass(className);
+        }
+
+        public Iterator<String> iterator() {
+            return classes.iterator();
+        }
+    }
+
     public class Annotatable {
         private final List<AnnotationInfo> annotations = new ArrayList<AnnotationInfo>();
 
@@ -1305,6 +1431,10 @@ public class AnnotationFinder implements
         }
     }
 
+    private void index(AnnotationInfo annotationInfo, Info info) {
+        initAnnotationInfos(annotationInfo.getName()).add(info);
+    }
+
     public class InfoBuildingVisitor extends EmptyVisitor {
         private Info info;
 
@@ -1355,7 +1485,7 @@ public class AnnotationFinder implements
         public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
             AnnotationInfo annotationInfo = new AnnotationInfo(desc);
             info.getAnnotations().add(annotationInfo);
-            getAnnotationInfos(annotationInfo.getName()).add(info);
+            index(annotationInfo, info);
             return new InfoBuildingVisitor(annotationInfo);
         }
 

Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/FileArchive.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/FileArchive.java?rev=1293927&r1=1293926&r2=1293927&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/FileArchive.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/FileArchive.java Sun Feb 26 20:20:10 2012
@@ -33,6 +33,7 @@ public class FileArchive implements Arch
 
     private final ClassLoader loader;
     private final File dir;
+    private List<String> list;
 
     public FileArchive(ClassLoader loader, URL url) {
         this.loader = loader;
@@ -44,6 +45,10 @@ public class FileArchive implements Arch
         this.dir = dir;
     }
 
+    public File getDir() {
+        return dir;
+    }
+
     public InputStream getBytecode(String className) throws IOException, ClassNotFoundException {
         int pos = className.indexOf("<");
         if (pos > -1) {
@@ -69,7 +74,10 @@ public class FileArchive implements Arch
     }
 
     public Iterator<String> iterator() {
-        return file(dir).iterator();
+        if (list != null) return list.iterator();
+
+        list = file(dir);
+        return list.iterator();
     }
 
     private List<String> file(File dir) {

Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java?rev=1293927&r1=1293926&r2=1293927&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java Sun Feb 26 20:20:10 2012
@@ -35,13 +35,18 @@ public class JarArchive implements Archi
 
     private final ClassLoader loader;
     private final URL url;
+    private List<String> list;
 
     public JarArchive(ClassLoader loader, URL url) {
-        if (!"jar".equals(url.getProtocol())) throw new IllegalArgumentException("not a file url: " + url);
+        if (!"jar".equals(url.getProtocol())) throw new IllegalArgumentException("not a jar url: " + url);
         this.loader = loader;
         this.url = url;
     }
 
+    public URL getUrl() {
+        return url;
+    }
+
     public InputStream getBytecode(String className) throws IOException, ClassNotFoundException {
         int pos = className.indexOf("<");
         if (pos > -1) {
@@ -67,8 +72,11 @@ public class JarArchive implements Archi
     }
 
     public Iterator<String> iterator() {
+        if (list != null) return list.iterator();
+
         try {
-            return jar(url).iterator();
+            list = jar(url);
+            return list.iterator();
         } catch (IOException e) {
             throw new IllegalStateException(e);
         }

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/FinderSelectTest.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/FinderSelectTest.java?rev=1293927&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/FinderSelectTest.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/FinderSelectTest.java Sun Feb 26 20:20:10 2012
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+package org.apache.xbean.finder;
+
+import org.apache.xbean.finder.archive.ClassesArchive;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class FinderSelectTest {
+
+    @Test
+    public void test() throws Exception {
+
+        final AnnotationFinder all = new AnnotationFinder(new ClassesArchive(Red.class, Green.class, Blue.class));
+
+        final AnnotationFinder finder = all.select(Red.class.getName());
+        final List<Class<?>> classes = finder.findAnnotatedClasses(Color.class);
+
+        for (Class<?> aClass : classes) {
+            System.out.println(aClass);
+        }
+
+    }
+
+
+
+    @java.lang.annotation.Target(value = {java.lang.annotation.ElementType.TYPE})
+    @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+    public @interface Color {
+    }
+
+
+    @Color
+    public static class Red {
+
+    }
+
+    @Color
+    public static class Green {
+
+    }
+
+    @Color
+    public static class Blue {
+
+    }
+}

Copied: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SelectMetaAnnotatedClassTest.java (from r1291554, geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/MetaAnnotatedClassTest.java)
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SelectMetaAnnotatedClassTest.java?p2=geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SelectMetaAnnotatedClassTest.java&p1=geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/MetaAnnotatedClassTest.java&r1=1291554&r2=1293927&rev=1293927&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/MetaAnnotatedClassTest.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SelectMetaAnnotatedClassTest.java Sun Feb 26 20:20:10 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.xbean.finder;
 
+import com.sun.xml.internal.txw2.IllegalSignatureException;
 import junit.framework.TestCase;
 import org.apache.xbean.finder.archive.ClassesArchive;
 
@@ -40,30 +41,23 @@ import static java.lang.annotation.Reten
  *
  * @version $Rev$ $Date$
  */
-public class MetaAnnotatedClassTest extends TestCase {
+public class SelectMetaAnnotatedClassTest extends TestCase {
 
-    public void test() throws Exception {
-        AnnotationFinder finder = new AnnotationFinder(new ClassesArchive(Square.class, Circle.class, Triangle.class, Fake.class, Store.class, Farm.class, None.class)).link();
-
-        Map<Class<?>, Annotated<Class<?>>> map = new HashMap<Class<?>, Annotated<Class<?>>>();
+    private AnnotationFinder finder;
+    private Map<Class<?>, Annotated<Class<?>>> map;
 
-        List<Annotated<Class<?>>> metas = finder.findMetaAnnotatedClasses(Color.class);
-        for (Annotated<Class<?>> meta : metas) {
-            Annotated<Class<?>> oldValue = map.put(meta.get(), meta);
-            assertNull("no duplicates allowed", oldValue);
-        }
+    public void test() throws Exception {
+        finder = new AnnotationFinder(new ClassesArchive(Square.class, Circle.class, Triangle.class, Fake.class, Store.class, Farm.class, None.class)).link();
 
         // MetaAnnotation classes themselves are not included
-        assertNull(map.get(Red.class));
-        assertNull(map.get(Crimson.class));
-
-        // Check the negative scenario
-        assertFalse(map.containsKey(None.class));
+        assertNull(get(Red.class));
+        assertNull(get(Crimson.class));
+        assertNull(get(None.class));
 
         // Check the positive scenarios
 
         { // Circle
-            Annotated<Class<?>> target = map.get(Circle.class);
+            Annotated<Class<?>> target = get(Circle.class);
             assertNotNull(target);
 
             assertTrue(target.isAnnotationPresent(Color.class));
@@ -74,7 +68,7 @@ public class MetaAnnotatedClassTest exte
         }
 
         { // Square
-            Annotated<Class<?>> target = map.get(Square.class);
+            Annotated<Class<?>> target = get(Square.class);
             assertNotNull(target);
 
             assertTrue(target.isAnnotationPresent(Color.class));
@@ -90,7 +84,7 @@ public class MetaAnnotatedClassTest exte
         }
 
         { // Triangle
-            Annotated<Class<?>> target = map.get(Triangle.class);
+            Annotated<Class<?>> target = get(Triangle.class);
             assertNotNull(target);
 
             assertTrue(target.isAnnotationPresent(Color.class));
@@ -111,7 +105,7 @@ public class MetaAnnotatedClassTest exte
         }
 
         { // Fake -- should not get more than we asked for
-            Annotated<Class<?>> target = map.get(Fake.class);
+            Annotated<Class<?>> target = get(Fake.class);
             assertNull(target);
 
             List<Annotated<Class<?>>> list = finder.findMetaAnnotatedClasses(NotMeta.class);
@@ -128,7 +122,7 @@ public class MetaAnnotatedClassTest exte
 
 
         { // Circular - Egg wins
-            Annotated<Class<?>> target = map.get(Store.class);
+            Annotated<Class<?>> target = get(Store.class);
             assertNotNull(target);
 
             assertTrue(target.isAnnotationPresent(Color.class));
@@ -149,7 +143,7 @@ public class MetaAnnotatedClassTest exte
         }
 
         { // Circular - Chicken wins
-            Annotated<Class<?>> target = map.get(Farm.class);
+            Annotated<Class<?>> target = get(Farm.class);
             assertNotNull(target);
 
             assertTrue(target.isAnnotationPresent(Color.class));
@@ -171,6 +165,23 @@ public class MetaAnnotatedClassTest exte
 
     }
 
+//    private Annotated<Class<?>> get(Class<?> key) {
+//        return map.get(key);
+//    }
+//
+    private Annotated<Class<?>> get(Class<?> key) {
+        final List<Annotated<Class<?>>> all = finder.findMetaAnnotatedClasses(Color.class);
+        final AnnotationFinder select = finder.select(key);
+        final List<Annotated<Class<?>>> metas = select.findMetaAnnotatedClasses(Color.class);
+
+        assertFalse(all.size() == metas.size());
+        for (Annotated<Class<?>> meta : metas) {
+            if (meta.get() == key) return meta;
+        }
+
+        return null;
+    }
+
     private boolean contains(Class<? extends Annotation> type, Annotation[] annotations) {
         for (Annotation annotation : annotations) {
             if (type.isAssignableFrom(annotation.annotationType())) return true;