--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project relativePaths="true" version="4">
+ <component name="AntConfiguration">
+ <defaultAnt bundledAnt="true" />
+ </component>
+ <component name="BuildJarProjectSettings">
+ <option name="BUILD_JARS_ON_MAKE" value="false" />
+ </component>
+ <component name="CCaseConfig">
+ <option name="checkoutReserved" value="false" />
+ <option name="markExternalChangeAsUpToDate" value="true" />
+ <option name="checkInUseHijack" value="true" />
+ <option name="useUcmModel" value="true" />
+ <option name="isOffline" value="false" />
+ <option name="synchOutside" value="false" />
+ <option name="isHistoryResticted" value="true" />
+ <option name="useIdenticalSwitch" value="true" />
+ <option name="synchActivitiesOnRefresh" value="true" />
+ <option name="lastScr" value="" />
+ <option name="scrTextFileName" value="" />
+ <option name="historyRevisionsNumber" value="4" />
+ </component>
+ <component name="CodeStyleProjectProfileManger">
+ <option name="PROJECT_PROFILE" />
+ <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+ </component>
+ <component name="CodeStyleSettingsManager">
+ <option name="PER_PROJECT_SETTINGS" />
+ <option name="USE_PER_PROJECT_SETTINGS" value="false" />
+ </component>
+ <component name="CompilerConfiguration">
+ <option name="DEFAULT_COMPILER" value="Javac" />
+ <option name="DEPLOY_AFTER_MAKE" value="0" />
+ <resourceExtensions>
+ <entry name=".+\.(properties|xml|html|dtd|tld)" />
+ <entry name=".+\.(gif|png|jpeg|jpg)" />
+ </resourceExtensions>
+ <wildcardResourcePatterns>
+ <entry name="?*.properties" />
+ <entry name="?*.xml" />
+ <entry name="?*.gif" />
+ <entry name="?*.png" />
+ <entry name="?*.jpeg" />
+ <entry name="?*.jpg" />
+ <entry name="?*.html" />
+ <entry name="?*.dtd" />
+ <entry name="?*.tld" />
+ </wildcardResourcePatterns>
+ </component>
+ <component name="DependenciesAnalyzeManager">
+ <option name="myForwardDirection" value="false" />
+ </component>
+ <component name="DependencyValidationManager">
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+ </component>
+ <component name="EclipseCompilerSettings">
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="true" />
+ <option name="DEPRECATION" value="false" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
+ </component>
+ <component name="EclipseEmbeddedCompilerSettings">
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="true" />
+ <option name="DEPRECATION" value="false" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
+ </component>
+ <component name="EntryPointsManager">
+ <entry_points version="2.0" />
+ </component>
+ <component name="ErrorOptionsConfigurable.UI">
+ <option name="proportions">
+ <SplitterProportionsDataImpl />
+ </option>
+ </component>
+ <component name="ExportToHTMLSettings">
+ <option name="PRINT_LINE_NUMBERS" value="false" />
+ <option name="OPEN_IN_BROWSER" value="false" />
+ <option name="OUTPUT_DIRECTORY" />
+ </component>
+ <component name="IdProvider" IDEtalkID="010DDB55D24EE954FEBC2143B5D8470F" />
+ <component name="InspectionProjectProfileManager">
+ <option name="PROJECT_PROFILE" value="Project Default" />
+ <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+ <scopes />
+ <profiles>
+ <profile version="1.0" is_locked="false">
+ <option name="myName" value="Project Default" />
+ <option name="myLocal" value="false" />
+ <inspection_tool class="JavaDoc" level="WARNING" enabled="false">
+ <option name="TOP_LEVEL_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="INNER_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="METHOD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+ </value>
+ </option>
+ <option name="FIELD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="IGNORE_DEPRECATED" value="false" />
+ <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+ <option name="myAdditionalJavadocTags" value="" />
+ </inspection_tool>
+ <inspection_tool class="JavadocReference" level="ERROR" enabled="false" />
+ </profile>
+ </profiles>
+ <list size="0" />
+ </component>
+ <component name="JavacSettings">
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="false" />
+ <option name="DEPRECATION" value="true" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
+ </component>
+ <component name="JavadocGenerationManager">
+ <option name="OUTPUT_DIRECTORY" />
+ <option name="OPTION_SCOPE" value="protected" />
+ <option name="OPTION_HIERARCHY" value="true" />
+ <option name="OPTION_NAVIGATOR" value="true" />
+ <option name="OPTION_INDEX" value="true" />
+ <option name="OPTION_SEPARATE_INDEX" value="true" />
+ <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
+ <option name="OPTION_DEPRECATED_LIST" value="true" />
+ <option name="OTHER_OPTIONS" value="" />
+ <option name="HEAP_SIZE" />
+ <option name="LOCALE" />
+ <option name="OPEN_IN_BROWSER" value="true" />
+ </component>
+ <component name="JikesSettings">
+ <option name="JIKES_PATH" value="" />
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="DEPRECATION" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="false" />
+ <option name="IS_EMACS_ERRORS_MODE" value="true" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ </component>
+ <component name="MavenImporterState">
+ <option name="autoImport">
+ <set>
+ <option value="$PROJECT_DIR$/pom.xml" />
+ </set>
+ </option>
+ </component>
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+ <component name="ProjectFileVersion" converted="true" />
+ <component name="ProjectModuleManager">
+ <modules />
+ </component>
+ <component name="ProjectRootConfigurable.UI">
+ <option name="proportions">
+ <SplitterProportionsDataImpl />
+ </option>
+ </component>
+ <component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+ <component name="ResourceManagerContainer">
+ <option name="myResourceBundles">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </component>
+ <component name="RmicSettings">
+ <option name="IS_EANABLED" value="false" />
+ <option name="DEBUGGING_INFO" value="true" />
+ <option name="GENERATE_NO_WARNINGS" value="false" />
+ <option name="GENERATE_IIOP_STUBS" value="false" />
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+ </component>
+ <component name="ScopeChooserConfigurable.UI">
+ <option name="proportions">
+ <SplitterProportionsDataImpl />
+ </option>
+ </component>
+ <component name="VcsDirectoryMappings">
+ <mapping directory="" vcs="svn" />
+ </component>
+ <component name="VssConfiguration">
+ <option name="CLIENT_PATH" value="" />
+ <option name="SRCSAFEINI_PATH" value="" />
+ <option name="USER_NAME" value="" />
+ <option name="PWD" value="" />
+ <CheckoutOptions>
+ <option name="COMMENT" value="" />
+ <option name="DO_NOT_GET_LATEST_VERSION" value="false" />
+ <option name="REPLACE_WRITABLE" value="false" />
+ <option name="RECURSIVE" value="false" />
+ </CheckoutOptions>
+ <CheckinOptions>
+ <option name="COMMENT" value="" />
+ <option name="KEEP_CHECKED_OUT" value="false" />
+ <option name="RECURSIVE" value="false" />
+ </CheckinOptions>
+ <AddOptions>
+ <option name="STORE_ONLY_LATEST_VERSION" value="false" />
+ <option name="CHECK_OUT_IMMEDIATELY" value="false" />
+ </AddOptions>
+ <UndocheckoutOptions>
+ <option name="MAKE_WRITABLE" value="false" />
+ <option name="REPLACE_LOCAL_COPY" value="0" />
+ <option name="RECURSIVE" value="false" />
+ </UndocheckoutOptions>
+ <GetOptions>
+ <option name="REPLACE_WRITABLE" value="0" />
+ <option name="MAKE_WRITABLE" value="false" />
+ <option name="ANSWER_NEGATIVELY" value="false" />
+ <option name="ANSWER_POSITIVELY" value="false" />
+ <option name="RECURSIVE" value="false" />
+ <option name="VERSION" />
+ </GetOptions>
+ </component>
+ <component name="WebServicesPlugin" addRequiredLibraries="true" />
+ <component name="com.intellij.jsf.UserDefinedFacesConfigs">
+ <option name="USER_DEFINED_CONFIGS">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </component>
+</project>
+
--- /dev/null
+<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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.scannotation</groupId>
+ <artifactId>annotation-db</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0</version>
+ <name>resteasy-jsr311</name>
+ <url>http://maven.apache.org</url>
+ <repositories>
+ <repository>
+ <id>jboss</id>
+ <url>http://repository.jboss.org/maven2</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.resteasy</groupId>
+ <artifactId>titan-cruise</artifactId>
+ <version>1.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.6.0.GA</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+package org.scannotation;
+
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.FieldInfo;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.ParameterAnnotationsAttribute;
+import javassist.bytecode.annotation.Annotation;
+import org.scannotation.classpath.Filter;
+import org.scannotation.classpath.IteratorFactory;
+import org.scannotation.classpath.StreamIterator;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AnnotationDB implements Serializable
+{
+ protected Map<String, Set<String>> annotationIndex = new HashMap<String, Set<String>>();
+ protected Map<String, Set<String>> implementsIndex = new HashMap<String, Set<String>>();
+ protected Map<String, Set<String>> classIndex = new HashMap<String, Set<String>>();
+
+ protected transient boolean scanClassAnnotations = true;
+ protected transient boolean scanMethodAnnotations = true;
+ protected transient boolean scanParameterAnnotations = true;
+ protected transient boolean scanFieldAnnotations = true;
+
+ public class CrossReferenceException extends RuntimeException
+ {
+ private Map<String, Set<String>> unresolved;
+
+ public CrossReferenceException(Map<String, Set<String>> unresolved)
+ {
+ this.unresolved = unresolved;
+ }
+
+ public Map<String, Set<String>> getUnresolved()
+ {
+ return 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
+ * a class's implemented interfaces. The cross references will be added to the annotationIndex and
+ * classIndex indexes
+ *
+ * @param ignoredPackages var arg list of packages to ignore
+ * @throws CrossReferenceException a RuntimeException thrown if referenced interfaces haven't been scanned
+ */
+ public void crossReferenceImplementedInterfaces(String... ignoredPackages) throws CrossReferenceException
+ {
+ Map<String, Set<String>> unresolved = new HashMap<String, Set<String>>();
+ for (String clazz : implementsIndex.keySet())
+ {
+ Set<String> 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;
+
+ Set<String> unresolvedInterfaces = new HashSet<String>();
+ Set<String> xrefAnnotations = classIndex.get(intf);
+ if (xrefAnnotations == null)
+ {
+ unresolvedInterfaces.add(intf);
+ unresolved.put(clazz, unresolvedInterfaces);
+ }
+ Set<String> classAnnotations = classIndex.get(clazz);
+ classAnnotations.addAll(xrefAnnotations);
+ for (String annotation : xrefAnnotations)
+ {
+ Set<String> classes = annotationIndex.get(annotation);
+ classes.add(clazz);
+ }
+ }
+ }
+
+ }
+
+ public Map<String, Set<String>> getAnnotationIndex()
+ {
+ return annotationIndex;
+ }
+
+ public Map<String, Set<String>> getClassIndex()
+ {
+ return classIndex;
+ }
+
+ public void setScanClassAnnotations(boolean scanClassAnnotations)
+ {
+ this.scanClassAnnotations = scanClassAnnotations;
+ }
+
+ public void setScanMethodAnnotations(boolean scanMethodAnnotations)
+ {
+ this.scanMethodAnnotations = scanMethodAnnotations;
+ }
+
+ public void setScanParameterAnnotations(boolean scanParameterAnnotations)
+ {
+ this.scanParameterAnnotations = scanParameterAnnotations;
+ }
+
+ public void setScanFieldAnnotations(boolean scanFieldAnnotations)
+ {
+ this.scanFieldAnnotations = scanFieldAnnotations;
+ }
+
+
+ /**
+ * Scan a url that represents an "archive" this is a classpath directory or jar file
+ *
+ * @param url
+ * @throws IOException
+ */
+ public void scanArchives(URL... urls) throws IOException
+ {
+ for (URL url : urls)
+ {
+ Filter filter = new Filter()
+ {
+ public boolean accepts(String filename)
+ {
+ return filename.endsWith(".class");
+ }
+ };
+
+ StreamIterator it = IteratorFactory.create(url, filter);
+
+ InputStream stream;
+ while ((stream = it.next()) != null) scanClass(stream);
+ }
+
+ }
+
+ /**
+ * Can a .class file for annotations
+ *
+ * @param bits
+ * @throws IOException
+ */
+ public void scanClass(InputStream bits) throws IOException
+ {
+ DataInputStream dstream = new DataInputStream(new BufferedInputStream(bits));
+ ClassFile cf = null;
+ try
+ {
+ cf = new ClassFile(dstream);
+ classIndex.put(cf.getName(), new HashSet<String>());
+ if (scanClassAnnotations) ;
+ scanClass(cf);
+ if (scanMethodAnnotations || scanParameterAnnotations) scanMethods(cf);
+ if (scanFieldAnnotations) scanFields(cf);
+
+ // create an index of interfaces the class implements
+ if (cf.getInterfaces() != null)
+ {
+ Set<String> intfs = new HashSet<String>();
+ for (String intf : cf.getInterfaces()) intfs.add(intf);
+ implementsIndex.put(cf.getName(), intfs);
+ }
+
+ }
+ finally
+ {
+ dstream.close();
+ bits.close();
+ }
+ }
+
+ protected void scanClass(ClassFile cf)
+ {
+ String className = cf.getName();
+ AnnotationsAttribute visible = (AnnotationsAttribute) cf.getAttribute(AnnotationsAttribute.visibleTag);
+ AnnotationsAttribute invisible = (AnnotationsAttribute) cf.getAttribute(AnnotationsAttribute.invisibleTag);
+
+ if (visible != null) populate(visible.getAnnotations(), className);
+ if (invisible != null) populate(invisible.getAnnotations(), className);
+ }
+
+ /**
+ * Scanns both the method and its parameters for annotations.
+ *
+ * @param cf
+ */
+ protected void scanMethods(ClassFile cf)
+ {
+ List methods = cf.getMethods();
+ if (methods == null) return;
+ for (Object obj : methods)
+ {
+ MethodInfo method = (MethodInfo) obj;
+ if (scanMethodAnnotations)
+ {
+ AnnotationsAttribute visible = (AnnotationsAttribute) method.getAttribute(AnnotationsAttribute.visibleTag);
+ AnnotationsAttribute invisible = (AnnotationsAttribute) method.getAttribute(AnnotationsAttribute.invisibleTag);
+
+ if (visible != null) populate(visible.getAnnotations(), cf.getName());
+ if (invisible != null) populate(invisible.getAnnotations(), cf.getName());
+ }
+ if (scanParameterAnnotations)
+ {
+ ParameterAnnotationsAttribute paramsVisible = (ParameterAnnotationsAttribute) method.getAttribute(ParameterAnnotationsAttribute.visibleTag);
+ ParameterAnnotationsAttribute paramsInvisible = (ParameterAnnotationsAttribute) method.getAttribute(ParameterAnnotationsAttribute.invisibleTag);
+
+ if (paramsVisible != null && paramsVisible.getAnnotations() != null)
+ {
+ for (Annotation[] anns : paramsVisible.getAnnotations())
+ {
+ populate(anns, cf.getName());
+ }
+ }
+ if (paramsInvisible != null && paramsInvisible.getAnnotations() != null)
+ {
+ for (Annotation[] anns : paramsInvisible.getAnnotations())
+ {
+ populate(anns, cf.getName());
+ }
+ }
+ }
+ }
+ }
+
+ protected void scanFields(ClassFile cf)
+ {
+ List fields = cf.getFields();
+ if (fields == null) return;
+ for (Object obj : fields)
+ {
+ FieldInfo field = (FieldInfo) obj;
+ AnnotationsAttribute visible = (AnnotationsAttribute) field.getAttribute(AnnotationsAttribute.visibleTag);
+ AnnotationsAttribute invisible = (AnnotationsAttribute) field.getAttribute(AnnotationsAttribute.invisibleTag);
+
+ if (visible != null) populate(visible.getAnnotations(), cf.getName());
+ if (invisible != null) populate(invisible.getAnnotations(), cf.getName());
+
+ }
+
+ }
+
+ protected void populate(Annotation[] annotations, String className)
+ {
+ if (annotations == null) return;
+ Set<String> classAnnotations = classIndex.get(className);
+ for (Annotation ann : annotations)
+ {
+ Set<String> classes = annotationIndex.get(ann.getTypeName());
+ if (classes == null)
+ {
+ classes = new HashSet<String>();
+ annotationIndex.put(ann.getTypeName(), classes);
+ }
+ classes.add(className);
+ classAnnotations.add(ann.getTypeName());
+ }
+ }
+
+ public void outputAnnotationDB(PrintWriter writer)
+ {
+ for (String ann : annotationIndex.keySet())
+ {
+ writer.print(ann);
+ writer.print(": ");
+ Set<String> classes = annotationIndex.get(ann);
+ Iterator<String> it = classes.iterator();
+ while (it.hasNext())
+ {
+ writer.print(it.next());
+ if (it.hasNext()) writer.print(", ");
+ }
+ writer.println();
+ }
+ }
+
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Various functions to locate URLs to scan
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClasspathUrlFinder
+{
+
+ /**
+ * Find the classpath URLs for a specific classpath resource. The classpath URL is extracted
+ * from loader.getResources() using the baseResource.
+ *
+ * @param baseResource
+ * @return
+ */
+ public static URL[] findResourceBases(String baseResource, ClassLoader loader)
+ {
+ ArrayList<URL> list = new ArrayList<URL>();
+ try
+ {
+ Enumeration<URL> urls = loader.getResources(baseResource);
+ while (urls.hasMoreElements())
+ {
+ URL url = urls.nextElement();
+ list.add(findResourceBase(url, baseResource));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ return list.toArray(new URL[list.size()]);
+ }
+
+ /**
+ * Find the classpath URLs for a specific classpath resource. The classpath URL is extracted
+ * from loader.getResources() using the baseResource.
+ *
+ * @param baseResource
+ * @return
+ */
+ public static URL[] findResourceBases(String baseResource)
+ {
+ return findResourceBases(baseResource, Thread.currentThread().getContextClassLoader());
+ }
+
+ private static URL findResourceBase(URL url, String baseResource)
+ {
+ String urlString = url.toString();
+ int idx = urlString.lastIndexOf(baseResource);
+ urlString = urlString.substring(0, idx);
+ URL deployUrl = null;
+ try
+ {
+ deployUrl = new URL(urlString);
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ return deployUrl;
+ }
+
+ /**
+ * Find the classpath URL for a specific classpath resource. The classpath URL is extracted
+ * from Thread.currentThread().getContextClassLoader().getResource() using the baseResource.
+ *
+ * @param baseResource
+ * @return
+ */
+ public static URL findResourceBase(String baseResource)
+ {
+ return findResourceBase(baseResource, Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * Find the classpath URL for a specific classpath resource. The classpath URL is extracted
+ * from loader.getResource() using the baseResource.
+ *
+ * @param baseResource
+ * @param loader
+ * @return
+ */
+ public static URL findResourceBase(String baseResource, ClassLoader loader)
+ {
+ URL url = loader.getResource(baseResource);
+ return findResourceBase(url, baseResource);
+ }
+
+ /**
+ * Find the classpath for the particular class
+ *
+ * @param clazz
+ * @return
+ */
+ public static URL findClassBase(Class clazz)
+ {
+ String resource = clazz.getName().replace('.', '/') + ".class";
+ return findResourceBase(resource, clazz.getClassLoader());
+ }
+
+ /**
+ * Uses the java.class.path system property to obtain a list of URLs that represent the CLASSPATH
+ *
+ * @return
+ */
+ public static URL[] findClassPaths()
+ {
+ List<URL> list = new ArrayList<URL>();
+ String classpath = System.getProperty("java.class.path");
+ StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
+
+ while (tokenizer.hasMoreTokens())
+ {
+ String path = tokenizer.nextToken();
+ File fp = new File(path);
+ if (!fp.exists()) throw new RuntimeException("File in java.class.path does not exist: " + fp);
+ try
+ {
+ list.add(fp.toURL());
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ return list.toArray(new URL[list.size()]);
+ }
+
+ /**
+ * Uses the java.class.path system property to obtain a list of URLs that represent the CLASSPATH
+ * <p/>
+ * paths is used as a filter to only include paths that have the specific relative file within it
+ *
+ * @param paths comma list of files that should exist in a particular path
+ * @return
+ */
+ public static URL[] findClassPaths(String... paths)
+ {
+ ArrayList<URL> list = new ArrayList<URL>();
+
+ String classpath = System.getProperty("java.class.path");
+ StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
+ for (int i = 0; i < paths.length; i++)
+ {
+ paths[i] = paths[i].trim();
+ }
+
+ while (tokenizer.hasMoreTokens())
+ {
+ String path = tokenizer.nextToken().trim();
+ boolean found = false;
+ for (String wantedPath : paths)
+ {
+ if (path.endsWith(File.separator + wantedPath))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found) continue;
+ File fp = new File(path);
+ if (!fp.exists()) throw new RuntimeException("File in java.class.path does not exists: " + fp);
+ try
+ {
+ list.add(fp.toURL());
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ return list.toArray(new URL[list.size()]);
+ }
+
+
+}
+
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface DirectoryIteratorFactory
+{
+ StreamIterator create(URL url, Filter filter) throws IOException;
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class FileIterator implements StreamIterator
+{
+ private ArrayList files;
+ private int index = 0;
+
+ public FileIterator(File file, Filter filter)
+ {
+ files = new ArrayList();
+ try
+ {
+ create(files, file, filter);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected static void create(List list, File dir, Filter filter) throws Exception
+ {
+ File[] files = dir.listFiles();
+ for (int i = 0; i < files.length; i++)
+ {
+ if (files[i].isDirectory())
+ {
+ create(list, files[i], filter);
+ }
+ else
+ {
+ if (filter == null || filter.accepts(files[i].getAbsolutePath()))
+ {
+ list.add(files[i]);
+ }
+ }
+ }
+ }
+
+ public InputStream next()
+ {
+ if (index >= files.size()) return null;
+ File fp = (File) files.get(index++);
+ try
+ {
+ return new FileInputStream(fp);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void close()
+ {
+ }
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class FileProtocolIteratorFactory implements DirectoryIteratorFactory
+{
+
+ public StreamIterator create(URL url, Filter filter) throws IOException
+ {
+ File f = new File(url.getPath());
+ if (f.isDirectory())
+ {
+ return new FileIterator(f, filter);
+ }
+ else
+ {
+ return new JarIterator(url.openStream(), filter);
+ }
+ }
+}
--- /dev/null
+package org.scannotation.classpath;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface Filter
+{
+ boolean accepts(String filename);
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Delegate to everything but close(). This object will not close the stream
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class InputStreamWrapper extends InputStream
+{
+ private InputStream delegate;
+
+ public InputStreamWrapper(InputStream delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ public int read()
+ throws IOException
+ {
+ return delegate.read();
+ }
+
+ public int read(byte[] bytes)
+ throws IOException
+ {
+ return delegate.read(bytes);
+ }
+
+ public int read(byte[] bytes, int i, int i1)
+ throws IOException
+ {
+ return delegate.read(bytes, i, i1);
+ }
+
+ public long skip(long l)
+ throws IOException
+ {
+ return delegate.skip(l);
+ }
+
+ public int available()
+ throws IOException
+ {
+ return delegate.available();
+ }
+
+ public void close()
+ throws IOException
+ {
+ // ignored
+ }
+
+ public void mark(int i)
+ {
+ delegate.mark(i);
+ }
+
+ public void reset()
+ throws IOException
+ {
+ delegate.reset();
+ }
+
+ public boolean markSupported()
+ {
+ return delegate.markSupported();
+ }
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class IteratorFactory
+{
+ private static final ConcurrentHashMap<String, DirectoryIteratorFactory> registry = new ConcurrentHashMap<String, DirectoryIteratorFactory>();
+
+ static
+ {
+ registry.put("file", new FileProtocolIteratorFactory());
+ }
+
+
+ public static StreamIterator create(URL url, Filter filter) throws IOException
+ {
+ String urlString = url.toString();
+ if (urlString.endsWith("!/"))
+ {
+ urlString = urlString.substring(4);
+ urlString = urlString.substring(0, urlString.length() - 2);
+ url = new URL(urlString);
+ }
+
+
+ if (!urlString.endsWith("/"))
+ {
+ return new JarIterator(url.openStream(), filter);
+ }
+ else
+ {
+ DirectoryIteratorFactory factory = registry.get(url.getProtocol());
+ if (factory == null) throw new IOException("Unable to scan directory of protocol: " + url.getProtocol());
+ return factory.create(url, filter);
+ }
+ }
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JarIterator implements StreamIterator
+{
+ JarInputStream jar;
+ JarEntry next;
+ Filter filter;
+ boolean initial = true;
+ boolean closed = false;
+
+ public JarIterator(File file, Filter filter) throws IOException
+ {
+ this(new FileInputStream(file), filter);
+ }
+
+
+ public JarIterator(InputStream is, Filter filter) throws IOException
+ {
+ this.filter = filter;
+ jar = new JarInputStream(is);
+ }
+
+ private void setNext()
+ {
+ initial = true;
+ try
+ {
+ if (next != null) jar.closeEntry();
+ next = null;
+ do
+ {
+ next = jar.getNextJarEntry();
+ } while (next != null && (next.isDirectory() || (filter == null || !filter.accepts(next.getName()))));
+ if (next == null)
+ {
+ close();
+ }
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("failed to browse jar", e);
+ }
+ }
+
+ public InputStream next()
+ {
+ if (closed || (next == null && !initial)) return null;
+ setNext();
+ if (next == null) return null;
+ return new InputStreamWrapper(jar);
+ }
+
+ public void close()
+ {
+ try
+ {
+ closed = true;
+ jar.close();
+ }
+ catch (IOException ignored)
+ {
+
+ }
+
+ }
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import java.io.InputStream;
+
+/**
+ * Simpler iterator than java.util.iterator. Things like JarInputStream does not allow you to implement hasNext()
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface StreamIterator
+{
+ /**
+ * User is resposible for closing the InputStream returned
+ *
+ * @return null if no more streams left to iterate on
+ */
+ InputStream next();
+
+ /**
+ * Cleanup any open resources of the iterator
+ *
+ */
+ void close();
+}
--- /dev/null
+package org.scannotation.classpath;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class WarUrlFinder
+{
+ public static URL[] findWebInfLibClasspaths(ServletContextEvent servletContextEvent)
+ {
+ ServletContext servletContext = servletContextEvent.getServletContext();
+ return findWebInfLibClasspaths(servletContext);
+ }
+
+ public static URL[] findWebInfLibClasspaths(ServletContext servletContext)
+ {
+ ArrayList<URL> list = new ArrayList<URL>();
+ Set libJars = servletContext.getResourcePaths("/WEB-INF/lib");
+ for (Object jar : libJars)
+ {
+ try
+ {
+ list.add(servletContext.getResource((String) jar));
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ return list.toArray(new URL[list.size()]);
+ }
+
+ public static URL findWebInfClassesPath(ServletContextEvent servletContextEvent)
+ {
+ ServletContext servletContext = servletContextEvent.getServletContext();
+ return findWebInfClassesPath(servletContext);
+ }
+
+ /**
+ * Find the URL pointing to "/WEB-INF/classes" This method may not work in conjunction with IteratorFactory
+ * if your servlet container does not extract the /WEB-INF/classes into a real file-based directory
+ *
+ * @param servletContext
+ * @return
+ */
+ public static URL findWebInfClassesPath(ServletContext servletContext)
+ {
+ Set libJars = servletContext.getResourcePaths("/WEB-INF/classes");
+ for (Object jar : libJars)
+ {
+ try
+ {
+ URL url = servletContext.getResource((String) jar);
+ String urlString = url.toString();
+ int index = urlString.lastIndexOf("/WEB-INF/classes/");
+ urlString = urlString.substring(0, index + "/WEB-INF/classes/".length());
+ return new URL(urlString);
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+
+ }
+}
--- /dev/null
+package org.scannotation.test;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClassWithFieldAnnotation
+{
+ private @SimpleAnnotation int field;
+}
--- /dev/null
+package org.scannotation.test;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CrossRef implements InterfaceWithParameterAnnotations
+{
+ public void junk(int param)
+ {
+ }
+}
--- /dev/null
+package org.scannotation.test;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface InterfaceWithParameterAnnotations
+{
+ public void junk(@SimpleAnnotation int param);
+}
--- /dev/null
+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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SimpleAnnotation
+{
+}
--- /dev/null
+package org.scannotation.test;
+
+import com.titan.domain.Address;
+import org.junit.Assert;
+import org.junit.Test;
+import org.scannotation.AnnotationDB;
+import org.scannotation.classpath.ClasspathUrlFinder;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class TestSmoke
+{
+
+ @Test
+ public void testFindResourceBase() throws Exception
+ {
+ URL url = ClasspathUrlFinder.findResourceBase("com/titan/domain/Address.class");
+ Assert.assertNotNull(url);
+ verify(url);
+ }
+
+ @Test
+ public void testFindResourceBases() throws Exception
+ {
+ URL[] urls = ClasspathUrlFinder.findResourceBases("com/titan/domain/Address.class");
+ Assert.assertNotNull(urls);
+ verify(urls);
+ }
+
+ @Test
+ public void testFindClasspaths() throws Exception
+ {
+ Assert.assertNotNull(System.getProperty("java.class.path"));
+ if (System.getProperty("java.class.path").indexOf("titan-cruise-1.0.jar") == -1)
+ {
+ System.err.println("WARNING!!!!!!!! CANNOT TEST testFindClasspaths(): This is a Maven2 and Surefire problem in that it doesn't set java.class.path correctly. I run this test within the IDE");
+ }
+
+ URL[] urls = ClasspathUrlFinder.findClassPaths("titan-cruise-1.0.jar");
+ Assert.assertNotNull(urls);
+ verify(urls);
+ }
+
+
+ @Test
+ public void testFindClasspaths2() throws Exception
+ {
+ Assert.assertNotNull(System.getProperty("java.class.path"));
+ if (System.getProperty("java.class.path").indexOf("titan-cruise-1.0.jar") == -1)
+ {
+ System.err.println("WARNING!!!!!!! CANNOT TEST testFindClasspaths2(): This is a Maven2 and Surefire problem in that it doesn't set java.class.path correctly. I run this test within the IDE");
+ }
+
+ URL[] urls = ClasspathUrlFinder.findClassPaths();
+ Assert.assertNotNull(urls);
+ AnnotationDB db = verify(urls);
+
+ Map<String, Set<String>> annotationIndex = db.getAnnotationIndex();
+ Set<String> tests = annotationIndex.get("org.junit.Test");
+ Assert.assertTrue(tests.contains(TestSmoke.class.getName()));
+
+ }
+
+ @Test
+ public void testFieldParameter() throws Exception
+ {
+ URL url = ClasspathUrlFinder.findClassBase(TestSmoke.class);
+ AnnotationDB db = new AnnotationDB();
+ db.scanArchives(url);
+
+ Map<String, Set<String>> annotationIndex = db.getAnnotationIndex();
+ Set<String> simpleClasses = annotationIndex.get(SimpleAnnotation.class.getName());
+ Assert.assertTrue(simpleClasses.contains(ClassWithFieldAnnotation.class.getName()));
+ Assert.assertTrue(simpleClasses.contains(InterfaceWithParameterAnnotations.class.getName()));
+
+ Set<String> simpleAnnotations = db.getClassIndex().get(ClassWithFieldAnnotation.class.getName());
+ Assert.assertTrue(simpleAnnotations.contains(SimpleAnnotation.class.getName()));
+ simpleAnnotations = db.getClassIndex().get(InterfaceWithParameterAnnotations.class.getName());
+ Assert.assertTrue(simpleAnnotations.contains(SimpleAnnotation.class.getName()));
+
+
+
+ }
+
+ @Test
+ public void testCrossRef() throws Exception
+ {
+ URL url = ClasspathUrlFinder.findClassBase(TestSmoke.class);
+ AnnotationDB db = new AnnotationDB();
+ db.scanArchives(url);
+ db.crossReferenceImplementedInterfaces();
+
+ Map<String, Set<String>> annotationIndex = db.getAnnotationIndex();
+ Set<String> simpleClasses = annotationIndex.get(SimpleAnnotation.class.getName());
+ Assert.assertTrue(simpleClasses.contains(CrossRef.class.getName()));
+
+ Set<String> simpleAnnotations = db.getClassIndex().get(CrossRef.class.getName());
+ Assert.assertTrue(simpleAnnotations.contains(SimpleAnnotation.class.getName()));
+ }
+
+
+ @Test
+ public void testByClass() throws Exception
+ {
+ URL url = ClasspathUrlFinder.findClassBase(Address.class);
+ Assert.assertNotNull(url);
+ verify(url);
+ }
+
+
+ private AnnotationDB verify(URL... urls)
+ throws IOException
+ {
+ AnnotationDB db = new AnnotationDB();
+ db.scanArchives(urls);
+
+ Map<String, Set<String>> annotationIndex = db.getAnnotationIndex();
+ {
+ Set<String> entities = annotationIndex.get("javax.persistence.Entity");
+ Assert.assertNotNull(entities);
+
+ Assert.assertTrue(entities.contains("com.titan.domain.Address"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Cabin"));
+ Assert.assertTrue(entities.contains("com.titan.domain.CreditCard"));
+ Assert.assertTrue(entities.contains("com.titan.domain.CreditCompany"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Cruise"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Customer"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Phone"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Reservation"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Ship"));
+ }
+
+ {
+ Set<String> entities = annotationIndex.get("javax.persistence.GeneratedValue");
+ Assert.assertNotNull(entities);
+
+ Assert.assertTrue(entities.contains("com.titan.domain.Address"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Cabin"));
+ Assert.assertTrue(entities.contains("com.titan.domain.CreditCard"));
+ Assert.assertTrue(entities.contains("com.titan.domain.CreditCompany"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Cruise"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Customer"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Phone"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Reservation"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Ship"));
+ }
+
+ {
+ Set<String> entities = annotationIndex.get("javax.persistence.Id");
+ Assert.assertNotNull(entities);
+
+ Assert.assertTrue(entities.contains("com.titan.domain.Address"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Cabin"));
+ Assert.assertTrue(entities.contains("com.titan.domain.CreditCard"));
+ Assert.assertTrue(entities.contains("com.titan.domain.CreditCompany"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Cruise"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Customer"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Phone"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Reservation"));
+ Assert.assertTrue(entities.contains("com.titan.domain.Ship"));
+ }
+
+ Map<String, Set<String>> classIndex = db.getClassIndex();
+ Set<String> annotations = classIndex.get("com.titan.domain.Address");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.Cabin");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.CreditCard");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.CreditCompany");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.Cruise");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.Customer");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.Phone");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.Reservation");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ annotations = classIndex.get("com.titan.domain.Ship");
+ Assert.assertNotNull(annotations);
+ Assert.assertTrue(annotations.contains("javax.persistence.Entity"));
+ Assert.assertTrue(annotations.contains("javax.persistence.Id"));
+ Assert.assertTrue(annotations.contains("javax.persistence.GeneratedValue"));
+
+ return db;
+ }
+}