How to cast dynamically loaded annotation class to Annotation? - java

I want to achieve the following logic:
Load an annotation class with ClassLoader.loadClass( String )
Check if a given Class object has that annotation using Class.isAnnotationPresent(Class<? extends Annotation>)
However, the return type of loadClass() is Class<?>, which cannot be used in isAnnotationPresent() directly. So, what steps should I take to use the loaded annotation class in isAnnotationPresent()?
This seems a simple problem, but I just fail to find an answer from the mighty Google. :-(
In any case, thank you very much.

You can use Class.asSubclass():
Class<? extends Annotation> a = cl.loadClass(...).asSubclass(Annotation.class);

Related

How to configure jackson to use JaxbAnnotationIntrospector or JacksonAnnotationIntrospector depending on the field being serialized

I have a wrapper class WrapperClassthat encapsulates two objects: ObjectOne and ObjectTwo:
public class WrapperClass {
ObjectOne objectOne;
ObjectTwo objectTwo;
}
While serializing a WrapperClassinstance, I want to use the JaxbAnnotationIntrospector on objectTwo but not on objectOne. Is that possible?
I have looked into creating a custom annotation introspector that extends JacksonAnnotationIntrospector and overrides its findSerializer() method to pick JAXB's findSerializer() if the class type is ObjectTwo.class. Would that work?
Thank you.
As I mentioned in my other comment. What I am trying to achieve is not currently formally supported by the Jackson lib. A customized AnnotationIntrospectorPair that properly delegates the introspection is an idea to how to go about this. I will look into this more in the future.

java generic how to ensure type has specified annotation?

I'm trying to create a generic class in android using Java but I want to make sure that the type would take specific classes with specific annotations like this:
I have class Table with annotation #Entity
#Entity
public class Table{}
and the generic class should only accept objects that have the #Entity annotation
Simple answer: not possible.
Annotations represent meta information that isn't available when constructing classes using generic type parameters.
if you want to check class annotation you have to use Reflection
http://static.javadoc.io/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
getTypesAnnotatedWith is the function you need
final Reflections reflections = new Reflections(packagePrefix);
final Set<Class<?>> namedClasses = reflections.getTypesAnnotatedWith(Named.class);
for (final Class<?> namedClass : namedClasses) {
}

Cannot find field in mongo collection using morphia

I have an abstract Scala class as a Mongo collection.
#Entity("aclTemplate")
abstract class AclTemplate(#(Id#field) var id: String) extends Serializable
Another class extends the above
#Entity("aclTemplate")
class GroupACLTemplate(id: String, var groupRoleAccess: Set[GroupRoleAccess]) extends AclTemplate(id) with Serializable
There are some docs of GroupACLTemplate in the collection. I am trying a simple query
createQuery().disableValidation().field("groupRoleAccess.groupId").equal(groupId).asList();
This throws a ValidationException
org.mongodb.morphia.query.ValidationException: The field 'groupRoleAccess.groupId' could not be found in 'com.model.acl.AclTemplate'
I do not think it is because of the long standing polymorphism issue in morphia. Because when I try to access just groupRoleAccess, it is able to. However, it is not able to access inside that set. It is a normal Java set. This is the GroupRoleAccess class
class GroupRoleAccess(var groupId: String, var roleId: String) extends Serializable
Am I missing something here?
I managed to hack something up. Apparently, since the collection is an abstract class, Mongo/Morphia does not look for attributes that are present in its subclasses. So I used createQuery and passed the class of the subclass.
ds.createQuery(clazz).disableValidation().field("groupRoleAccess.groupId").equal(groupId).asList();
But I still wonder how it was able to extract groupRoleAccess before
You should try 1.3.0-SNAPSHOT. I just fixed a bug similar to this and it probably fixes your issue, too.

Binding a map of classes to instances inside guice module

I am currently trying to add the entries of a map consisting of Map<? extends CustomModule, CustomModule> (from an additional, custom module system) as bindings within a guice module.
My code so far looks like this:
manager.getRegistry().forEach(new BiConsumer<Class<? extends CustomModule>, ModuleRegistry.Entry>() {
#Override
public void accept(Class<? extends CustomModule> moduleClass, ModuleRegistry.Entry entry) {
bind(moduleClass).to(entry.getModule()); // getModule() returns the instance which implements moduleClass
}
});
Guice sadly needs the direct class instead of a wildcard ("? extends").
Since I already got the "bindings", is there another way to add them to the injector?
Thanks in advance!
So after trying various other possible ways, I finally found one that works.
Since the original problem was that Guice required a "capture" of something (in this case "capture of ? extends Module instance", basically means something that is an instance of something that is a module) and failed, I had to cast my already known module class to its raw type, like this:
final Class moduleClass = (Class) aClass;
final Binding binding = injector.getExistingBinding(Key.get(moduleClass));
if (binding == null) {
bind(moduleClass).toInstance(entry.getModule());
}
I also had to add a null check in my case, but it also includes the way how to cast your unknown class to guice's "Key" helper.

Javassist: Convert CtMethod to java.lang.reflect.Method

I currently need to change the annotation of a java.lang.reflect.Method Object, which should be a clone of the original method so the original one wont get modified. To do so I downloaded the Library Javassist. So, basically, the optimal code to do so would be:
java.lang.reflect.Method myMethod = /*obtain it*/;
java.lang.reflect.Method myMethodClone = myMethod.clone();
myMethodClone.removeAllAnnotations();
myMethodClone.addAnnotation("#MyAnnotation(something=\"something\", etc");
But a code similar to this pseudo-code unfortunately isn't possible. I tried to use javassist to solve my problem, but then I encountered another problem: I can't convert Javassists CtMethod Object into a Method Object, at least not without changing the class where the original method is.
Anyone has an idea how to solve this?
javassist uses his own class hierarchy,not the Java one. If you want to use javassist start reading official doc and how it works.
About your question: conversion Method <-> CtMethod is impossible. In addiction, what do you intend to do with cloned method? If you want to "duplicate" a method in which class will it live? In the same of the original method? Impossible, because you will receive a "method already present" (or similar).
javassist can solve your problem but a full answer if not possible because the question is pretty vague. My advice is to start from official doc or using this tutorial
I managed to get my code working by using the default java Annotation & Method class plus some reflection.
Here's how I did it (Probably won't help anyone, since my problem was really specific, but you never know...)(Pseudo-Code):
//Create Annotation
MyAnnotationOld oldAnnotation;
MyAnnotation modifiedAnnotation = new MyAnnotation{
public Class<? extends java.lang.annotation.Annotation> annotationType() {return oldAnnotation.annotationType();}
public String propertyWhichShallRemainTheSame() {return oldAnnotation.propertyWhichShallRemainTheSame();}
public String propertyWhichShallBeModified() {return "Modified Thingy";}
}
//Copy Method
Method toCopy;
Method copyMethod = Method.class.getDeclaredMethod("copy", (Class<?>[])null);
copyMethod.setAccessible(true);
Method copiedMethod = (Method) copyMethod.invoke(toCopy, (Object[]) null);
//Add annotation to copied method
Field field = Method.class.getDeclaredField("declaredAnnotations");
field.setAccessible(true);
//Intantiate field !!IMPORTANT!! If you don't do this, the field will be null and thus return an error.
copiedMethod.getAnnotations();
Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) field.get(copiedMethod);
annotations.put(MyAnnotation.class, modifiedAnnotation);

Categories