I have plugin I am writing where I need to know the type of the List<Person>
where Person
is an object defined within a dependency.
The Person
class:
package com.dependency.models;
public class Person {
// Irrelevent
}
The use within the class I am performing the query on:
package com.project.wrappers;
import com.dependency.Person;
@MyAnnotation
public class Wrapper {
List<Person> people;
// Other irrelevant stuff
}
The annotation:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.TYPE})
public @interface MyAnnotation {}
From within a Maven plugin use context I load all the Wrapper
objects via annotation and then process. To do this I need to use a custom classloader via the Reflections library:
public static Set<Class<?>> findAnnotatedClasses(MavenProject mavenProject, Class<? extends Annotation> input) throws MojoExecutionException {
List<String> classpathElements = null;
try {
classpathElements = mavenProject.getCompileClasspathElements();
List<URL> projectClasspathList = new ArrayList<URL>();
for (String element : classpathElements) {
Application.getLogger().debug("Considering compile classpath element (via MavenProject): " + element);
try {
projectClasspathList.add(new File(element).toURI().toURL());
} catch (MalformedURLException e) {
throw new MojoExecutionException(element + " is an invalid classpath element", e);
}
}
// Retain annotations
JavassistAdapter javassistAdapter = new JavassistAdapter();
javassistAdapter.includeInvisibleTag = false;
URLClassLoader urlClassLoader = new URLClassLoader(projectClasspathList.toArray(new URL[]{}),
Thread.currentThread().getContextClassLoader());
Reflections reflections = new Reflections(
new ConfigurationBuilder().setUrls(
ClasspathHelper.forClassLoader(urlClassLoader)
).addClassLoader(urlClassLoader).setScanners(new TypeAnnotationsScanner(), new TypeElementsScanner(),
new FieldAnnotationsScanner(), new TypeAnnotationsScanner(), new SubTypesScanner(false)
).setMetadataAdapter(javassistAdapter)
);
return findAnnotatedClasses(reflections, input);
} catch (DependencyResolutionRequiredException e) {
throw new MojoExecutionException("Dependency resolution failed", e);
}
}
Everything up to here works great. But if I try the following, within my parser, it fails:
Field field = Wrapper.class.getDeclaredField("people");
ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class<?> listTypeClass = (Class<?>) listType.getActualTypeArguments()[0];
The following exception is thrown:
Caused by: java.lang.TypeNotPresentException: Type com.dependency.Person not present
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:117)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.visitor.Reifier.reifyTypeArguments(Reifier.java:68)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:138)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.repository.FieldRepository.getGenericType(FieldRepository.java:85)
at java.lang.reflect.Field.getGenericType(Field.java:247)
Which means that my classloading is working for everything prior to this last step. I think I need a way to override the classloader used within the sun.reflect
library but it may not be possible. Any recommendations on a better approach?
Aucun commentaire:
Enregistrer un commentaire