For the benefit of anyone searching this mailing list due to a similar
problem in future:

My problem was due to using the wrong (default) classloader:
ClassLoader loader = new URLClassLoader(urls);

The issue was resolved by switching to:
ClassLoader loader = new URLClassLoader(urls,
ParserApp.class.getClassLoader());



On Tue, Aug 28, 2012 at 5:23 PM, Thomas McDermott <tcmcderm...@gmail.com>wrote:

> Dear all,
>
> I have difficulty finding annotations on classes loaded from a Maven
> plugin (I am using JDK 1.7 and Maven 3.0.4).
>
> I have a Class ParserApp
> with a method processAllClassFiles(rootClassFolder)
> which processes all the ".class" files in the folder tree under
> rootClassFolder.
>
> In short, the method processAllClassFiles can load class files and find
> annotations when run from a unit test in eclipse
> or when called from the commandline; however when the method is wrapped in
> a MavenMojo plugin the class file is loaded
> but the annotations are not found.
>
> The following snippets from the ParserApp class provide some further
> details of the problem.
>
> Given a path to a .class file obtained from searching a rootFolder
> Files.walkFileTree(Paths.get(rootFolder), ...
>
>     Path file = "./target/test-classes/com/example/AnnotatedPojo.class";
>
>
> ----------------------------------------------------------------------------------------
> Content of AnnotatedPojo.java:
>
> package com.example.pojos;
> import com.example.annotation.*;
> @AnnotationDefinition(value = "ValueOfTheAnnotation")
> public class AnnotatedPojo {
> }
>
> ----------------------------------------------------------------------------------------
>
> I use the javassist library
> <dependency>
>     <groupId>javassist</groupId>
>     <artifactId>javassist</artifactId>
>     <version>3.12.1.GA</version>
> </dependency>
> to parse the .classfile and find and display the "AnnotationDefinition"
> annotation
>
>     DataInputStream dstream = new DataInputStream(new
> BufferedInputStream(new FileInputStream(file.toFile())));
>     ClassFile classFile =  new ClassFile(dstream);
>     String className = classFile.getName();
>     System.out.println("class name = "+className);
>     AnnotationsAttribute visible = (AnnotationsAttribute)
> classfile.getAttribute(AnnotationsAttribute.visibleTag);
>     if (visible != null) {
>         System.out.println("visible="+visible.getName());
>         System.out.println("num_annotations="+visible.numAnnotations());
>
> System.out.println("annotation[0]="+visible.getAnnotations()[0].toString());
>     }
>
> This gives the expected output:
>
> class name = com.example.pojos.AnnotatedPojo
> visible=RuntimeVisibleAnnotations
> num_annotations=1
>
> annotation[0]=@com.example.annotation.AnnotationDefinition(value="ValueOfTheAnnotation")
>
>
>
> ----------------------------------------------------------------------------------------
> Content of AnnotationDefinition.java:
>
> package com.example.annotation;
> import java.lang.annotation.*;
> @Target({ ElementType.TYPE })
> @Retention(RetentionPolicy.RUNTIME)
> @Documented
> public @interface AnnotationDefinition {
>     String value();
> }
>
> ----------------------------------------------------------------------------------------
>
>
> Now I attempt to load the class and find the annotation by reflection:
>
>
> URL[] urls = { (new File(rootFolder)).toURI().toURL() };
> ClassLoader loader = new URLClassLoader(urls);
> Class<?> cls = loader.loadClass(className);
>
> System.out.println("\nclass loaded in ParseApp.execute()= " +
> cls.getName());
> Annotation[] annotations = cls.getAnnotations();
> if (annotations.length > 0) {
>     for (Annotation annotation : annotations) {
>         System.out.println("\t" + annotation);
>     }
> } else {
>     System.out.println("\t" + "no annotations found");
> }
>
>
> This also gives the expected output:
>
> class loaded in ParseApp.execute()= com.example.pojos.AnnotatedPojo
> Annotations:
>
> @com.example.annotation.AnnotationDefinition(value=ValueOfTheAnnotation)
>
>
> The problem occurs when I call the above ParserApp.processAllClassFiles
> method from inside a maven plugin
>
>
> /**
>  * Parse .class files.
>  *
>  * @goal process-classes
>  *
>  * @phase process-classes
>  *
>  * @requiresDependencyResolution compile+runtime
>  * @requiresProject false
>  *
>  *
>  */
>
> public class ParserMojo extends AbstractMojo {
> ...
>    /**
>     *
>     * @parameter expression="${project.compileClasspathElements}"
>     * @required
>     * @readonly
>     */
>    private List<?> classpathElements;
>
>     @Override
>     public void execute() throws MojoExecutionException {
>
>         getLog().info("Processing class files in " + rootClassFolders[0]);
>         for (Object cpe:classpathElements) {
>             getLog().info((CharSequence) cpe.toString());
>         }
>
> getLog().info("---------------------------------------------------------");
>
>         try {
>             ParserApp.processAllClassFiles(rootClassFolder);
>         } catch (IOException e) {
>             e.printStackTrace();
>         }
>     }
> }
>
>
> The relevant part of the output is:
>
> [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @
> using-maven-plugin-test ---
> [INFO] Nothing to compile - all classes are up to date
> [INFO]
> [INFO] --- process-classes-maven-plugin:1.0.1-SNAPSHOT:process-classes (0)
> @ using-maven-plugin-test ---
> [INFO] Processing class files in
> C:\Users\tmcd\workspaces\minimal_plugin_classloader\using-the-maven-plugin\target\classes
> [INFO]
> C:\Users\tmcd\workspaces\minimal_plugin_classloader\using-the-maven-plugin\target\classes
> [INFO]
> C:\Users\tmcd\.m2\repository\com\example\process-classes-maven-plugin\1.0.1-SNAPSHOT\process-classes-maven-plugin-1.0.1-SNAPSHOT.jar
> [INFO]
> C:\Users\tmcd\.m2\repository\org\apache\maven\maven-plugin-api\2.0\maven-plugin-api-2.0.jar
> [INFO]
> C:\Users\tmcd\.m2\repository\com\example\annotation-processor\1.0.1-SNAPSHOT\annotation-processor-1.0.1-SNAPSHOT.jar
> [INFO] C:\Users\tmcd\.m2\repository\javassist\javassist\3.12.1.GA
> \javassist-3.12.1.GA.jar
> [INFO]
> C:\Users\tmcd\.m2\repository\com\example\required-annotations\1.0.1-SNAPSHOT\required-annotations-1.0.1-SNAPSHOT.jar
> [INFO] ---------------------------------------------------------
>
>
> processing com.example.pojos.AnnotatedPojo
> class name = com.example.pojos.AnnotatedPojo
> visible=RuntimeVisibleAnnotations
> num_annotations=1
>
> annotation[0]=@com.example.annotation.AnnotationDefinition(value="ValueOfTheAnnotation")
>
> class loaded in ParseApp.execute()= com.example.pojos.AnnotatedPojo
> Annotations:
>     no annotations found
>
>
> Note: the jar containing the annotation is
> "required-annotations-1.0.1-SNAPSHOT.jar" in in
> "${project.compileClasspathElements}"
>
> The annotation is found in the .class bytecode
> num_annotations=1
>
> annotation[0]=@com.example.annotation.AnnotationDefinition(value="ValueOfTheAnnotation"
>
> BUT the annotation is nolonger found in the loaded class:
>
> class loaded in ParseApp.execute()= com.example.pojos.AnnotatedPojo
> Annotations:
>     no annotations found
>
>
> The plugin jar
>     process-classes-maven-plugin-1.0.1-SNAPSHOT.jar
> has a dependency on
>     annotation-processor-1.0.1-SNAPSHOT.jar    (which contains the
> ParserApp class)
> which has a dependency on
>     required-annotations-1.0.1-SNAPSHOT.jar
>
> I have tried placing the dependency on the required annotation
>
>         <dependency>
>             <groupId>com.example</groupId>
>             <artifactId>required-annotations</artifactId>
>             <version>1.0.1-SNAPSHOT</version>
>         </dependency>
>
> directly into the plugin pom
> and also into the <build><plugins> section of the independent project
> which uses the plugin
>
>     <build>
>         <plugins>
>             <plugin>
>                 <groupId>com.example</groupId>
>                 <artifactId>process-classes-maven-plugin</artifactId>
>                 <version>${project.version}</version>
>                 <executions>
>                     <execution>
>                         <id>0</id>
>                         <phase>process-classes</phase>
>                         <goals>
>                             <goal>process-classes</goal>
>                         </goals>
>                     </execution>
>                 </executions>
>                 <dependencies>
>                     <dependency>
>                         <groupId>com.example</groupId>
>                         <artifactId>required-annotations</artifactId>
>                         <version>1.0.1-SNAPSHOT</version>
>                     </dependency>
>                 </dependencies>
>             </plugin>
>             <plugin>
>                 <groupId>org.apache.maven.plugins</groupId>
>                 <artifactId>maven-compiler-plugin</artifactId>
>                 <version>2.5.1</version>
>                 <configuration>
>                     <source>1.7</source>
>                     <target>1.7</target>
>                 </configuration>
>             </plugin>
>         </plugins>
>     </build>
>
> However I am still failing to find the annotation in the loaded class file.
> I assume the problem has something to do with loading the files inside the
> maven container?
>
> Any advice for solving this problem would be appreciated.
>
> Best regards,
>
> Tom McDermott
>
>
>
>
>

Reply via email to