I am somewhat new to Java so perhaps I misunderstand the use cases for annotations in java. My issue is the following:
After annotating a method I receive class names such as $Proxy31 when inspecting the annotations on the method. I am curious why I am receiving class names for my annotations that are similar to this, and what I can do to fix this problem.
Method m = this.remoteServiceClass.getMethod(rpcRequest.getMethod().getName());
RequiredPermission a = m.getAnnotation(RequiredPermission.class);
This returns a null annotation even though I know that the method it is looking up has the RequiredPermission annotation implemented.
for(Annotation a : m.getAnnotations())
{
System.out.println(a.getClass().getName());
}
This prints out the $Proxy31 class names.
Given Annotation a, you need to call annotationType(), not getClass() to determine the type of the annotation. An Annotation object is just a proxy that represents that instance of the annotation on that class.
Object o = ...;
Class c = o.getClass();
Annotation[] as = c.getAnnotations();
for (Annotation a : as) {
// prints out the proxy class name
System.out.println(a.getClass().getName());
// prints out the name of the actual annotation
System.out.println(a.annotationType().getName());
}
When you add annotations in the source code, Java actually creates a bunch of interfaces and classes "under the hood" to allow you (or your tools) to ask the program things about the annotations using restrictions. Method annotations create "dyanmic proxies", and accordingly Java creates classes for you, probably with the name Proxy.
If you are interested in this, read on java.lang.reflect.InvocationHandler and its subtype, AnnotationInvocationHandler
That being said, you should not have to worry about what Java actually generates. I suspect you are not using reflection correctly to inspect your annotations from within a Java program.
also.. remember to set this:
#Retention(RetentionPolicy.RUNTIME)
on your annotation so that it lives beyond the compile.
Related
I've encountered strange behaviour when trying to read Class's annotations from an object.
For example:
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.CLASS)
annotation class MyAnnotation(val value: String) {}
#MyAnnotation("HelloWorld")
class MyClass
// in test
val obj = MyClass()
println(obj::class.annotations) // DOESN'T finds annotation
println(obj::class.java.annotations) // finds annotation
println(obj.javaClass.annotations) // finds annotation
However, it does find it when I make direct reference to a class like so:
println(MyClass::class.annotations) // finds annotation
Anything I'm missing?
I will keep the question open for some more time, since after restarting android studio it started showing annotation in the list, w/o any code change.
can I use the reflection API to find a class according to an annotation?
I'm looking for a way to execute a class based on an annotation.
for example, I have a class credentials with an Verify annotation and the parameter "token" and "permissions" are actions to execute the responsable class
#Verify ("token")
#Verify ("permissions")
class Credentials {
....
}
The Verify("token") should call the execute method in the TokenVerifier class and the Verify("permissions") should call the execute method in the PermissionsVerifier class, for example.
I would put in my classes the annotation #verifier with the necessary parameters to be able to find it. Like this:
#verifier(path="classPath", action="token")
class TokenVerifier
{
…
}
#verifier(path="classPath", action="permissions")
class PermissionsVerifier
{
…
}
Can I get somehow those classes with these annotations? It is worth mentioning that I do not know which classes will have these annotations, the idea is that it is dynamic.
Standard Java does not allow you to find all classes with a given annotation, since annotations are evaluated after loading a class, not before.
However there are tools that scan the classpath for classes containing an annotation and loading the class if a match occurs, e.g. fast-classpath-scanner.
To get all Verifys:
new FastClasspathScanner("package.to.search.in")
.matchClassesWithAnnotation(Verify.class, c -> System.out.println(c.getName()))
.scan();
To get all verifiers:
new FastClasspathScanner("package.to.search.in")
.matchClassesWithAnnotation(verifier.class, c -> System.out.println(c.getName()))
.scan();
After loading the classes you can evaluate and match the classes as you like with standard reflection.
I have 2 java annotation types, let's say XA and YA. Both have some method(). I parse the source code and retrieve Annotation object. Now I'd like to dynamicaly cast the annotation to the real type of it to be able to call the method(). How can I do it without the instanceof statement? I really want to avoid switch-like source. I need something like this:
Annotation annotation = getAnnotation(); // I recieve the Annotation object here
String annotationType = annotation.annotationType().getName();
?_? myAnnotation = (Class.forName(annotationType)) annotation;
annotation.method(); // this is what I need, get the method() called
?_? means I have no idea what would be myAnnotation type. I cannot use the base class for my XA and YA annotations since the inheritance in annotations is not allowed. Or is it possible to do somehow?
Thanks for any suggestion or help.
Why don't you use the typesafe way to retrieve your annotation ?
final YourAnnotationType annotation = classType.getAnnotation(YourAnnotationType.class);
annotation.yourMethod();
If your annotation can't be found, null is returned.
Please note that this also works with fields and methods.
One way is to invoke the method dynamically using the name of it:
Annotation annotation = getAnnotation();
Class<? extends Annotation> annotationType = annotation.annotationType();
Object result = annotationType.getMethod("method").invoke(annotation);
This approach is quite risky and totally compromise the code refactoring if needed.
I have an annotation #MyAnnotation and I can annotate any type (class) with it. Then I have a class called AnnotatedClassRegister and I would like it to register all classes annotated with #MyAnnotation so I can access them later. And I'd like to register these classes automatically upon creation of the AnnotatedClassRegister if possible, and most importantly before the annotated classes are instantiated.
I have AspectJ and Guice at my disposal. The only solution I came up with so far is to use Guice to inject a singleton instance of the AnnotatedClassRegister to an aspect, which searches for all classes annotated with #MyAnnotation and it adds the code needed to register such class in its constructor. The downside of this solution is that I need to instantiate every annotated class in order for the code added by AOP to be actually run, therefore I cannot utilize lazy instantiation of these classes.
Simplified pseudo-code example of my solution:
// This is the class where annotated types are registered
public class AnnotatedClassRegister {
public void registerClass(Class<?> clz) {
...
}
}
// This is the aspect which adds registration code to constructors of annotated
// classes
public aspect AutomaticRegistrationAspect {
#Inject
AnnotatedClassRegister register;
pointcutWhichPicksConstructorsOfAnnotatedClasses(Object annotatedType) :
execution(/* Pointcut definition */) && args(this)
after(Object annotatedType) :
pointcutWhichPicksConstructorsOfAnnotatedClasses(annotatedType) {
// registering the class of object whose constructor was picked
// by the pointcut
register.registerClass(annotatedType.getClass())
}
}
What approach should I use to address this problem? Is there any simple way to get all such annotated classes in classpath via reflection so I wouldn't need to use AOP at all? Or any other solution?
Any ideas are much appreciated, thanks!
It's possible:
Get all paths in a classpath. Parse System.getProperties().getProperty("java.class.path", null) to get all paths.
Use ClassLoader.getResources(path) to get all resources and check for classes: http://snippets.dzone.com/posts/show/4831
It isn't simple that much is sure, but I'd do it in a Pure Java way:
Get your application's Jar location from the classpath
Create a JarFile object with this location, iterate over the entries
for every entry that ends with .class do a Class.forName() to get the Class object
read the annotation by reflection. If it's present, store the class in a List or Set
Aspects won't help you there, because aspects only work on code that's actually executed.
But annotation processing may be an Option, create a Processor that records all annotated classes and creates a class that provides a List of these classes
Well, if your AnnotatedClassRegister.registerClass() doesn't have to be called immediately at AnnotatedClassRegister creation time, but it could wait until a class is first instantiated, then I would consider using a Guice TypeListener, registered with a Matcher that checks if a class is annotated with #MyAnnotation.
That way, you don't need to search for all those classes, they will be registered just before being used. Note that this will work only for classes that get instantiated by Guice.
I would use the staticinitialization() pointcut in AspectJ and amend classes to your register as they are loaded, like so:
after() : staticinitialization(#MyAnnotation *) {
register.registerClass(thisJoinPointStaticPart.getSignature().getDeclaringType());
}
Piece of cake, very simple and elegant.
You can use the ClassGraph package like so:
Java:
try (ScanResult scanResult = new ClassGraph().enableAnnotationInfo().scan()) {
for (ClassInfo classInfo = scanResult.getClassesWithAnnotation(classOf[MyAnnotation].getName()) {
System.out.println(String.format("classInfo = %s", classInfo.getName()));
}
}
Scala:
Using(new ClassGraph().enableAnnotationInfo.scan) { scanResult =>
for (classInfo <- scanResult.getClassesWithAnnotation(classOf[MyAnnotation].getName).asScala) {
println(s"classInfo = ${classInfo.getName}")
}
}
I'm using Spring 3.x, Java 6.
I have an #Around aspect with the following joinpoint:
#Around("execution(public * my.service.*.*Connector.*(..))")
So, I'm basically interested in intercepting all calls to public methods of classes with the class name ending with "Connector". So far so good.
Now, in my aspect I would like to access the actual argument names of the methods:
public doStuff(String myarg, Long anotherArg)
myarg and anotherArg
I understand that using:
CodeSignature signature = (CodeSignature)jointPoint.getSignature();
return signature.getParameterNames();
will actually work but only if I compile the code with the "-g" flag (full debug) and I would rather not do it.
Is there any other way to get access to that kind of runtime information.
Thanks
L
Unfortunately you can't do this :-(. It is a well known limitation of JVM/bytecode - argument names can't be obtained using reflection, as they are not always stored in bytecode (in the contrary to method/class names).
As a workaround several frameworks/specification introduce custom annotations over arguments like WebParam (name property) or PathParam.
For the time being all you can get without annotations is an array of values.
Check the implementations of org.springframework.core.ParameterNameDiscoverer.
Annotations like #RequestParam used by spring inspect the parameter name if no value is set. So #RequestParam String foo will in fact fetch the request parameter named "foo". It uses the ParameterNameDiscoverer mechanism. I'm just not sure which of the implementations are used, by try each of them.
The LocalVariableTableParameterNameDiscoverer reads the .class and uses asm to inspect the names.
So, it is possible. But make sure to cache this information (for example - store a parameter name in a map, with key = class+method+parameter index).
But, as it is noted in the docs, you need the debug information. From the docs of #PathVariable:
The matching of method parameter names to URI Template variable names can only be done if your code is compiled with debugging enabled. If you do not have debugging enabled, you must specify the name of the URI Template variable name in the #PathVariable annotation in order to bind the resolved value of the variable name to a method parameter
So, if you really don't want to include that information, Tomasz Nurkiewicz's answer explains the workaround.
In Java 8 there is a new compiler flag that allows additional metadata to be stored with byte code and these parameter names can be extracted using the Parameter object in reflection. See JDK 8 spec. In newer versions of hibernate org.springframework.core.ParameterNameDiscoverer uses this feature. To use it compile using javac with this flag:
-parameters Generate metadata for reflection on method parameters
Access parameters using reflection's Parameter class.
I am not sure if its a best way, but I added a Annotation on my method:
My Annotation:
#Retention (RetentionPolicy.RUNTIME)
#Target (ElementType.METHOD)
public #interface ReadApi
{
String[] paramNames() default "";
}
#ReadApi (paramNames={"name","id","phone"})
public Address findCustomerInfo(String name, String id, String phone)
{ ..... }
And in the Aspect:
#Around("aspect param && #annotation(readApi)")
public Object logParams(ProceedingJoinPoint pjp,
ReadApi readApi)
{
//use pjp.getArgs() and readApi.paramNames();
}
This is probably a hack but i did not want to compile with more options to get information. Anyways, its working well for me. Only downside is that i need to keep the names in annotation and method in sync.