URLClassLoader loads the Annotation as com.sun. $ Proxy $ 27

I am trying to dynamically load a java class. The main idea is that the bank contains modules that are dynamically loaded at run time. Here's how I do it (I know this is hacked, but there is no other way to dynamically add a jar of an existing classloader afaik):

Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class }); method.setAccessible(true); method.invoke(moduleLoader, new Object[] { file.toURI().toURL() }); Class fooClass = moduleLoader.loadClass("com.coderunner.Foo"); Object foo = fooClass.newInstance(); 

Each module is annotated with @Module annotation. Therefore, in order to get additional information about the module, I am trying to get annotation. The problem is that the annotation on foo is of type com.sun. $ Proxy $ 27 instead of com.coderunner.Module and so I get

 ClassCastException: Cannot cast com.sun.proxy.$Proxy42 (id=64) to com.coderunner.Module 

I have to say that I'm a little confused about what is going on here. Is this what I want to make possible? How?

Edit: Perhaps I should also mention that I'm trying to do this in spring / spring-mvc and tomcat environments.

+4
source share
3 answers

The fact that reflection returns a proxy object does not prevent you from collecting information about the annotation and its values.

The getclass method returns a proxy object:

  log.info("annotation class:" + annotation.getClass()); 

Exit:

  [INFO] annotation class:class com.sun.proxy.$Proxy16class 

The conclusion is the same as in your example, but this is not a problem. The presence of a method (or field) is sufficient. The extra part is simply calling the annotation method .

 public void analyseClass(Class myClass) { for (Method method: myClass.getMethods()) { System.out.println("aanotations :" + Arrays.toString(field.getAnnotations())); for (Annotation annotation : method.getAnnotations()) { log.info("annotation class:" + annotation.getClass()); log.info("annotation class type:" + annotation.annotationType()); Class<Annotation> type = (Class<Annotation>) annotation.annotationType(); /* extract info only for a certain annotation */ if(type.getName().equals(MyAnnotation.class.getName())) { String annotationValue = (String) type.getMethod("MY_ANNOTATION_CERTAIN_METHOD_NAME").invoke(annotation); log.info("annotationValue :" + annotationValue); break; } } } //do the same for the fields of the class for (Field field : myClass.getFields()) { //... } } 

To come to this solution, I used the following entry: How to get the annotation class name, attribute values ​​using reflection

+1
source

The fact that you get a proxy before the annotation type does not matter. This can lead you astray into believing that this is causing the problems you are experiencing. If things like "isAnnotationPresent (..)" fail, this is not due to this proxy because you loaded the annotation class several times using multiple class loaders. For example, Jetty gives priority to the default WebApp class loader. Therefore, if your Jetty server instance (or Tomcat or something else) has already loaded the annotation class, and the annotation in your path to the WebApp class may also occur, for example, "getAnnotation ()" does not return anything. Just make sure the library containing your annotation is not loading twice.

The solution provided by Andreas is a very dirty solution and just hides the fact that you probably do not have recharges under control / properly organized.

+1
source

I had the same problem when trying to create an ant task to generate code based on a declarative approach using annotations. I found that the Proxy-Object documentation states that instanceof should allow it, but that didn't work. I finally talked to

Annotation[] annotations = classObj.getAnnotations();

  for(int i = 0;i < annotations.length;i++) { Class<?>[] interfaces = annotations[i].getClass().getInterfaces(); for(int i2 = 0; i2 < interfaces.length;i2++) { System.out.println("interface:" + interfaces[i2].getName()); } 

code> giving me the name of the original annotation, so comparing this name with the classname annotation will give you the desired result.

0
source

Source: https://habr.com/ru/post/1497505/


All Articles