From 6f8bc0038ccf20fceaf363d36c22b731e0a998e3 Mon Sep 17 00:00:00 2001 From: patriot1burke Date: Tue, 22 Jan 2008 16:02:55 +0000 Subject: [PATCH] * configurable ignored packages * ability to xref meta-annotations * CrossRefException is now checked --- pom.xml | 2 +- .../java/org/scannotation/AnnotationDB.java | 144 +++++++++++++++--- .../test/AnnotationWithMetaAnnotation.java | 15 ++ .../test/CrossRefMetaAnnotaiton.java | 10 ++ .../org/scannotation/test/MetaAnnotation.java | 14 ++ .../java/org/scannotation/test/TestSmoke.java | 13 ++ 6 files changed, 173 insertions(+), 25 deletions(-) create mode 100644 src/test/java/org/scannotation/test/AnnotationWithMetaAnnotation.java create mode 100644 src/test/java/org/scannotation/test/CrossRefMetaAnnotaiton.java create mode 100644 src/test/java/org/scannotation/test/MetaAnnotation.java diff --git a/pom.xml b/pom.xml index 4b32de2..1c1141b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.scannotation scannotation jar - 1.0 + 1.0.1 scannotation http://maven.apache.org diff --git a/src/main/java/org/scannotation/AnnotationDB.java b/src/main/java/org/scannotation/AnnotationDB.java index 2c062f2..92e28c6 100644 --- a/src/main/java/org/scannotation/AnnotationDB.java +++ b/src/main/java/org/scannotation/AnnotationDB.java @@ -26,7 +26,8 @@ import java.util.Set; /** * The class allows you to scan an arbitrary set of "archives" for .class files. These class files - * are parsed to see what annotations they use. Two indexes are created. + * are parsed to see what annotations they use. Two indexes are created. The javax, java, sun, com.sun, and javassist + * packages will not be scanned by default. * * One is a map of annotations and what classes * use those annotations. This could be used, for example, by an EJB deployer to find all the EJBs contained @@ -47,22 +48,105 @@ public class AnnotationDB implements Serializable protected transient boolean scanMethodAnnotations = true; protected transient boolean scanParameterAnnotations = true; protected transient boolean scanFieldAnnotations = true; + protected transient String[] ignoredPackages = {"javax", "java", "sun", "com.sun", "javassist"}; - public class CrossReferenceException extends RuntimeException + public class CrossReferenceException extends Exception { - private Map> unresolved; + private Set unresolved; - public CrossReferenceException(Map> unresolved) + public CrossReferenceException(Set unresolved) { this.unresolved = unresolved; } - public Map> getUnresolved() + public Set getUnresolved() { return unresolved; } } + public String[] getIgnoredPackages() + { + return ignoredPackages; + } + + /** + * Override/overwrite any ignored packages + * + * @param ignoredPackages cannot be null + */ + public void setIgnoredPackages(String[] ignoredPackages) + { + this.ignoredPackages = ignoredPackages; + } + + public void addIgnoredPackages(String... ignored) + { + String[] tmp = new String[ignoredPackages.length + ignored.length]; + int i = 0; + for (String ign : ignoredPackages) tmp[i++] = ign; + for (String ign : ignored) tmp[i++] = ign; + } + + /** + * This method will cross reference annotations in the annotation index with any meta-annotations that they have + * and create additional entries as needed. For example: + * + * @HttpMethod("GET") + * public @interface GET {} + * + * The HttpMethod index will have additional classes added to it for any classes annotated with annotations that + * have the HttpMethod meta-annotation. + * + * WARNING: If the annotation class has not already been scaned, this method will load all annotation classes indexed + * as a resource so they must be in your classpath + * + * + */ + public void crossReferenceMetaAnnotations() throws CrossReferenceException + { + Set unresolved = new HashSet(); + + Set index = new HashSet(); + index.addAll(annotationIndex.keySet()); + + for (String annotation : index) + { + if (ignoreScan(annotation)) + { + continue; + } + if (classIndex.containsKey(annotation)) + { + for (String xref : classIndex.get(annotation)) + { + annotationIndex.get(xref).addAll(annotationIndex.get(annotation)); + } + continue; + } + InputStream bits = Thread.currentThread().getContextClassLoader().getResourceAsStream(annotation.replace('.', '/') + ".class"); + if (bits == null) + { + unresolved.add(annotation); + continue; + } + try + { + scanClass(bits); + } + catch (IOException e) + { + unresolved.add(annotation); + } + for (String xref : classIndex.get(annotation)) + { + annotationIndex.get(xref).addAll(annotationIndex.get(annotation)); + } + + } + if (unresolved.size() > 0) throw new CrossReferenceException(unresolved); + } + /** * Sometimes you want to see if a particular class implements an interface with certain annotations * After you have loaded all your classpaths with the scanArchive() method, call this method to cross reference @@ -70,34 +154,22 @@ public class AnnotationDB implements Serializable * classIndex indexes * * @param ignoredPackages var arg list of packages to ignore - * @throws CrossReferenceException a RuntimeException thrown if referenced interfaces haven't been scanned + * @throws CrossReferenceException an Exception thrown if referenced interfaces haven't been scanned */ - public void crossReferenceImplementedInterfaces(String... ignoredPackages) throws CrossReferenceException + public void crossReferenceImplementedInterfaces() throws CrossReferenceException { - Map> unresolved = new HashMap>(); + Set unresolved = new HashSet(); for (String clazz : implementsIndex.keySet()) { Set intfs = implementsIndex.get(clazz); for (String intf : intfs) { - if (intf.startsWith("java.") || intf.startsWith("javax.")) continue; - boolean ignoreInterface = false; - for (String ignored : ignoredPackages) - { - if (intf.startsWith(ignored + ".")) - { - ignoreInterface = true; - break; - } - } - if (ignoreInterface) continue; + if (ignoreScan(intf)) continue; - Set unresolvedInterfaces = new HashSet(); Set xrefAnnotations = classIndex.get(intf); if (xrefAnnotations == null) { - unresolvedInterfaces.add(intf); - unresolved.put(clazz, unresolvedInterfaces); + unresolved.add(intf); } Set classAnnotations = classIndex.get(clazz); classAnnotations.addAll(xrefAnnotations); @@ -108,9 +180,26 @@ public class AnnotationDB implements Serializable } } } + if (unresolved.size() > 0) throw new CrossReferenceException(unresolved); } + private boolean ignoreScan(String intf) + { + for (String ignored : ignoredPackages) + { + if (intf.startsWith(ignored + ".")) + { + return true; + } + else + { + //System.out.println("NOT IGNORING: " + intf); + } + } + return false; + } + /** * returns a map keyed by the fully qualified string name of a annotation class. The Set returne is * a list of classes that use that annotation somehow. @@ -173,6 +262,7 @@ public class AnnotationDB implements Serializable } + /** * Scan a url that represents an "archive" this is a classpath directory or jar file * @@ -187,7 +277,13 @@ public class AnnotationDB implements Serializable { public boolean accepts(String filename) { - return filename.endsWith(".class"); + if (filename.endsWith(".class")) + { + if (filename.startsWith("/")) filename = filename.substring(1); + if (!ignoreScan(filename.replace('/', '.'))) return true; + //System.out.println("IGNORED: " + filename); + } + return false; } }; @@ -299,9 +395,9 @@ public class AnnotationDB implements Serializable if (visible != null) populate(visible.getAnnotations(), cf.getName()); if (invisible != null) populate(invisible.getAnnotations(), cf.getName()); - } + } protected void populate(Annotation[] annotations, String className) diff --git a/src/test/java/org/scannotation/test/AnnotationWithMetaAnnotation.java b/src/test/java/org/scannotation/test/AnnotationWithMetaAnnotation.java new file mode 100644 index 0000000..3c5dbef --- /dev/null +++ b/src/test/java/org/scannotation/test/AnnotationWithMetaAnnotation.java @@ -0,0 +1,15 @@ +package org.scannotation.test; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@MetaAnnotation +public @interface AnnotationWithMetaAnnotation +{ +} diff --git a/src/test/java/org/scannotation/test/CrossRefMetaAnnotaiton.java b/src/test/java/org/scannotation/test/CrossRefMetaAnnotaiton.java new file mode 100644 index 0000000..8176e82 --- /dev/null +++ b/src/test/java/org/scannotation/test/CrossRefMetaAnnotaiton.java @@ -0,0 +1,10 @@ +package org.scannotation.test; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@AnnotationWithMetaAnnotation +public class CrossRefMetaAnnotaiton +{ +} diff --git a/src/test/java/org/scannotation/test/MetaAnnotation.java b/src/test/java/org/scannotation/test/MetaAnnotation.java new file mode 100644 index 0000000..95f04a3 --- /dev/null +++ b/src/test/java/org/scannotation/test/MetaAnnotation.java @@ -0,0 +1,14 @@ +package org.scannotation.test; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public @interface MetaAnnotation +{ +} diff --git a/src/test/java/org/scannotation/test/TestSmoke.java b/src/test/java/org/scannotation/test/TestSmoke.java index 8a9331d..cb8b842 100644 --- a/src/test/java/org/scannotation/test/TestSmoke.java +++ b/src/test/java/org/scannotation/test/TestSmoke.java @@ -7,6 +7,7 @@ import org.scannotation.AnnotationDB; import org.scannotation.ClasspathUrlFinder; import java.io.IOException; +import java.io.PrintWriter; import java.net.URL; import java.util.Map; import java.util.Set; @@ -108,6 +109,18 @@ public class TestSmoke } + @Test + public void testCrossRefMetaAnnotations() throws Exception + { + URL url = ClasspathUrlFinder.findClassBase(TestSmoke.class); + AnnotationDB db = new AnnotationDB(); + db.scanArchives(url); + db.crossReferenceMetaAnnotations(); + + Assert.assertTrue(db.getAnnotationIndex().get(MetaAnnotation.class.getName()).contains(CrossRefMetaAnnotaiton.class.getName())); + } + + @Test public void testByClass() throws Exception { -- 2.20.1