How do you get java method annotations to work in scala - java

I've got two projects, a scala project and a java project. My scala project references the java project in the build path. In my java project, i'm declaring the following annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
public String Name();
}
In my scala project, I'm annotating some methods. I.e.
class MyClass {
...
#MyAnnotation(Name="Blah")
def myMethod() {
...
}
}
In another file somewhere, i'm trying to pull out the annotations.
var methods = myClassInstance.getClass().getDeclaredMethods()
var myMethod : Method = null
for (method <- methods) {
if (method.getName().equals("myMethod")) {
myMethod = method
}
}
var annotations = myMethod.getDeclaredAnnotations()
Unfortunately, annotations is always an empty array. Am I doing something fundamentally wrong or am I just missing something minor? Thanks!
EDIT
Originally, I was annotating myMethod with myAnnotation twice, which is incorrect as someone pointed out. It turns out this wasn't the problem. I'm still getting an empty array for annotations. No exception is being thrown.

I tried your code, the problem is that your use #MyAnnotation twice for myMethod, which should raise AnnotationFormatError: Duplicate annotation for class
When i change to use it once, the reflection just retrieves the annotions.

Related

Kotlin - Instance cannot retrieve it's class annotations via myInstance::class.annotations but can with javaClass.annotations

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.

Implement (/inherit/~extend) annotation in Kotlin

In Java I have the possibility to "implement" annotations.
Sample Java annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface JavaClassAnno {
String[] value();
}
Sample Java "implementation":
class MyAnnotationLiteral
extends AnnotationLiteral<JavaClassAnno>
implements JavaClassAnno { // <--- works in Java
private String value;
public MyAnnotationLiteral(String value) {
this.value = value;
}
#Override
public String[] value() {
return new String[] { value };
}
}
Trying to port that to Kotlin doesn't work as it says that the annotation is final and therefore can not be inherited, i.e. the following will not work:
class MyAnnotationLiteral(private val internalValue: String)
: AnnotationLiteral<JavaClassAnno>(),
JavaClassAnno { // <--- doesn't work in Kotlin (annotation can not be inherited)
override fun value(): Array<String> {
return arrayOf(internalValue)
}
}
How do you "implement/extend" annotations the Kotlin way? Could not find any reason why Kotlin differs in that regard to Java. Any hint how to solve that problem or any sources that tell why it is that way are welcome.
The following question contains a use case for this constellation: Dynamically fire CDI event with qualifier with members.
Basically you require something like this to narrow down which qualifier should trigger based on its members.
Note that this would also apply to a Kotlin annotation as well as it seems that a Kotlin annotation can not be open and therefore not be implemented/extended too.
What I found so far is rather mentioning #Inherited as a problem:
https://discuss.kotlinlang.org/t/inherited-annotations-and-other-reflections-enchancements/6209
https://youtrack.jetbrains.com/issue/KT-22265
But I did not find any reason why the annotation is not implementable/inheritable as it is in Java.
I also asked this question now here: https://discuss.kotlinlang.org/t/implement-inherit-extend-annotation-in-kotlin/8916
Update: Finally I found something regarding this design decision, namely the following issue (while I was opening my own issue for it): Annotations inheritance. Either prohibit or implement correctly. As it seems the decision was to "prohibit" it, even though there are no (visible?) comments, discussions or other sources about that decision.
Added the following issue: https://youtrack.jetbrains.com/issue/KT-25947
As of Kotlin 1.3, this case is not supported. To create custom instances of annotations one has to resort to Java for now. One of the reasons for this design decision is that making annotations interfaces is too JVM-specific and wouldn't map well to other platforms.

Custom Annotation not found while unit testing

say i've an Annotation like that:
#Retention(RetentionPolicy.RUNTIME)
public #interface AutoConvert {
boolean enabled() default true;
}
and class annotated with it:
#AutoConvert
public class ExampleCommandToExample extends BaseConverter{}
On the superclass i'am doing the following:
public void convert(){
Annotation annotation = (AutoConvert) this.getClass().getAnnotation(AutoConvert.class);
}
Everything works fine on runtime! Annotation is getting found and properly set!
But! While unit testing the convert method with JUnit:
this.getClass().getAnnotation(AutoConvert.class)
always returns null.
The test looks like this:
#Test
public void convertTest(){
//when
exampleCommandToExample.convert();
}
Are custom annotations not being found by reflection while running unit tests?
Does anyone has an answer for me?
I would really really appreciate it.
Thank you in advance.
EDIT:
Alright it seems to be grounded in the kind of intatiation...
I do the following:
exampleCommandToExample = new ExampleCommandToExample() {
#Override
public Type overideSomeMethod() {
return type;
}
};
May it be possible that an instance looses all it's annotations
if I override some methods on instantiation?
Since exampleCommandToExample ref represents an instance of an anonymous class, the call this.getClass().getAnnotation(AutoConvert.class) collects the annotations at its level and all inherited ones.
However, #AutoConvert in this example of anonymous implementation is not inherited, that is why getAnnotation returns null, which corresponds exactly to the behavior declared in Java API:
Returns this element's annotation for the specified type if such an annotation is present, else null.
To solve the issue, simply add
import java.lang.annotation.Inherited;
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface AutoConvert { /* no changes */ }
#Inherited will make the annotation visible for the anonymous implementation.

execute some code before and after of any method execution only by giving my custom annotation in java

I am trying to write a code for custom annotation. when I use this annotation on any method, then before execution and after execution of method some simple print msg should execute. I tried like this :
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#interface DemoAnnotation {
String value();
String value1();
}
// Applying annotation
class CustomAnnotationExample {
#DemoAnnotation(value = "code is started!!!", value1= "code is completed!!!")
public void sayHello() {
System.out.println("hello Annotation Example");
}
}
and in another main method I called it like :
CustomAnnotationExample h=new CustomAnnotationExample();
Method m=h.getClass().getMethod("sayHello");
DemoAnnotation anno=m.getAnnotation(DemoAnnotation.class);
System.out.println(anno.value());
h.sayHello();
System.out.println(anno.value1());
I want to print values from annotation without using System.out.println() in main method . when I just call sayHello() method . annotation values should get printed before and after execution of sayHello() method.
Please help me on this.
There are two ways, both of them very complex, runtime and compile time solution:
The runtime solution relies on specific framework which is used to instantiate the application. The common way is to create wrapping proxies for the final object and do the stuff from the proxy before (or after) calling the original object method.
For spring for example the solution is to register BeanPostProcessor object which would intercept the instantiation of the bean and check whether some of the method contains the DemoAnnotation annotation. In case it does, it would create a proxy to that object and return the proxy as the real bean.
Second solution is compile time solution and is based on annotation processors which can modify the java compiler behavior. You need to create and register annotation processor and after parsing the source file checking the annotations on the method and add the relevant code during the compilation time. There are many helpers, you can for example register on TreeScanner.visitMethod() method and invoke the TreeScanner from your annotation processor.
Generally the good example can be found in lombok which does similar things in terms of modifying the code during the compile time.

Java annotation returns cryptic class names

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.

Categories

Resources