Reflection getAnnotations() returns null - java

Searchable.java
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Searchable { }
Obj.java
public class Obj {
#Searchable
String myField;
}
void main(String[] args)
Annotation[] annotations = Obj.class.getDeclaredField("myField").getAnnotations();
I would expect annotations to be containing my #Searchable. Though it is null. According to documentation, this method:
Returns all annotations present on this element. (Returns an array of length zero if this element has no annotations.) The caller of this method is free to modify the returned array; it will have no effect on the arrays returned to other callers.
Which is even more weird (to me), since it returns null instead of Annotation[0].
What am I doing wrong here and more important, how will I be able to get my Annotation?

I just tested this for you, and it just works:
public class StackOverflowTest {
#Test
public void testName() throws Exception {
Annotation[] annotations = Obj.class.getDeclaredField("myField").getAnnotations();
System.out.println(annotations[0]);
}
}
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#interface Searchable {
}
class Obj {
#Searchable
String myField;
}
I ran it, and it produces the following output:
#nl.jworks.stackoverflow.Searchable()
Can you try running the above class in your IDE? I tried it with IntelliJ, openjdk-6.

Your code is correct. The problem is somewhere else. I just copied and run your code and it works.
It is possible that you are importing the wrong Obj class in your code you may want to check that first.

In my case, i had forgotten to add
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
to the method, so in the end it should look like:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}

In my case, the error was in my own annotation.
I fixed a couple of things, and it finally ended up like this:
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Target( { METHOD, FIELD, ANNOTATION_TYPE })
#Retention(RUNTIME)
public #interface MyAnnotation{
}
It works now

Related

How to create my own annotation, nothing works

I'm trying to make my own getter annotation, as it is done in lombok:
package testAnns.anns;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target({ElementType.FIELD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Get {
Access value() default Access.PUBLIC;
Value[] method() default {};
#Retention(RetentionPolicy.RUNTIME)
#Target({})
#interface Value {}
}
Tried to specify:
package testAnns;
import testAnns.anns.Get;
public class TestAnns {
#Get public int l = 10;
}
I try to call:
public static void main(String[] args) {
TestAnns ann = new TestAnns();
System.out.println(ann.getL()); // error
}
Nothing works.
What to do, how to be, why does not work?
Connoisseurs, please help me figure it out, I don’t understand why it doesn’t work ...

Number of annotations at JUnit test incorrect

I have created some custom annotations to use for system tests which are run via JUnit.
A test e.g. looks like this:
#TestCaseName("Change History")
public class ChangeHistory extends SystemTestBase
{
#Test
#Risk(1)
public void test()
{
...
I am now implementing a Test Runner which shall report the test name, the risk and the somewhere for documentation purposes.
public class MyRunner extends BlockJUnit4ClassRunner
{
...
#Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier)
{
...
System.out.println("Class annotations:");
Annotation[] classanno = klass.getAnnotations();
for (Annotation annotation : classanno) {
System.out.println(annotation.annotationType());
}
System.out.println("Method annotations:");
Annotation[] methanno = method.getAnnotations();
for (Annotation annotation : methanno) {
System.out.println(annotation.annotationType());
}
The output is
Class annotations:
Method annotations:
interface org.junit.Test
So getAnnotations() seems to return annotations of JUnit only and not all annotations. This is not mentioned in the documentation of JUnit:
Returns the annotations on this method
The return type is java.lang.Annotation which made me believe that I can use any annotation. I defined the annotation like follows - I just used it and when there was an error I let Eclipse generate the annotation:
public #interface Risk {
int value();
}
How do I get all annotations of the test class and test method?
You need to set the retention policy of the Risk annotation to RUNTIME. Otherwise, the annotation will be discarded after the compilation and won't be available during the execution of the code.
This should be working:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Risk {
int value();
}

AspectJ - Pointcut at specified method with a param annotated with class level annotation

In an aspect, i'd like stop at a specified method. This method has one parameter which is annotated with a class level annotation:
The annotation is:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Auditable {}
The parameter is an object of a class annotated like:
#Auditable
public class User {}
The method I like to inspect:
public Object findSingleResultByExample(final Object entity) {}
This aspect is not working:
#AfterReturning(value="execution(* org.wtp.repository.GenericDao.find*(#org.wtp.aspects.Auditable (*)))",
argNames = "joinPoint, result",
returning = "result")
private void auditFindAnnotation(final JoinPoint joinPoint, final Object result) {}
First of all, your advice method must be public, not private. Please change that into
public void auditFindAnnotation(...)
It is not working because your pointcut intercepts methods with an #Auditable parameter annotation. Your sample method does not have such an annotation, though. It would work if the method signature was like this:
public Object findSingleResultByExample(final #Auditable Object entity) {}
BTW, then the #Target(ElementType.TYPE) restriction must be removed or extended in order for the code to still compile.
But I guess what you want is not to match on parameter annotations, but on type annotations. Then your pointcut would look like this (no parentheses around * this time):
execution(* org.wtp.repository.GenericDao.find*(#org.wtp.aspects.Auditable *))
But again, this does not match your sample method because its parameter type is not User or Auditable but just Object and the latter does not carry the annotation. You can see the difference if you overload your find* method and do something like this:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Auditable {}
package de.scrum_master.app;
#Auditable
public class User {}
package de.scrum_master.app;
import java.util.ArrayList;
public class Application {
public Object findSingleResultByExample(final Object entity) {
return entity;
}
public Object findSingleResultByExample(final User entity) {
return entity;
}
public static void main(String[] args) {
Application application = new Application();
application.findSingleResultByExample("foo");
application.findSingleResultByExample(new User());
application.findSingleResultByExample(new ArrayList<String>());
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AuditAspect {
#AfterReturning(
value = "execution(* de.scrum_master.app..find*(#de.scrum_master.app.Auditable *))",
argNames = "thisJoinPoint, result",
returning = "result"
)
public void auditFindAnnotation(final JoinPoint thisJoinPoint, final Object result) {
System.out.println(thisJoinPoint + " -> " + result);
}
}
The console log then looks like this:
execution(Object de.scrum_master.app.Application.findSingleResultByExample(User)) -> de.scrum_master.app.User#4a574795
Update: In order to get the whole thing working without changing or overloading any method signatures, you would have to make your pointcut match all calls and dynamically determine the type and its annotations from withing the aspect via reflection (not so nice, but possible). Feel free to ask questions if you do not understand this idea.

what is the values() that I have seen in various CDI qualifiers in java?

I have seen various references to values() inside #Qualifier definitions.
I understand #Qualifier to be a tagging system, yet you define them as an interface.
An interface can allow enums, but I don't understand the word values() that I've seen in the two unrelated examples I've listed below.
Could you please explain to me the word values() means?
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, TYPE, METHOD})
public #interface NumberOfDigits {
Digits value();
}
public enum Digits {
TWO,
EIGHT,
TEN,
THIRTEEN
}
package com.byteslounge.bean;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, TYPE, METHOD})
public #interface MessageTransport {
MessageTransportType value();
}
These are not interfaces. These are annotations. It is possible to declare static information on annotations and annotate them. Code that inspects annotations can then utilize this information.
Annotations declared as Qualifiers let CDI disambiguate between implementations of the same type.
Consider the qualifier Foo:
#Qualifier #Retention(RUNTIME) #Target({FIELD, TYPE, METHOD})
public #interface Foo { int value(); }
Types annotated with Foo:
#Foo(1) public class Bar implements Runnable {
//...impl
#Foo(2) public class Baz implements Runnable {
//...impl
A CDI bean:
public class Bean {
#Inject #Foo(1) Runnable a;
#Inject #Foo(2) Runnable b;
//...impl
Here, a will be resolved to an instance of Bar while b will be resolved to an instance of Baz.
Without the qualifier annotation, the CDI API wouldn't be able to tell which instance of Runnable to inject. All the values must be an exact match.

getAnnotations() is empty

I would like to use annotations in my application. For this reason I create "hello world" for annotations:
follows example:
public class HelloAnnotation
{
#Foo(bar = "Hello World !")
public String str;
public static void main(final String[] args) throws Exception
{
System.out.println(HelloAnnotation.class.getField("str").getAnnotations().length);
}
}
And this is the Annotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Target(ElementType.FIELD)
public #interface Foo
{
public String doTestTarget();
}
My problem is now that getAnnotations() in main is empty. What is wrong with my code?
Add the following to your annotation:
#Retention(RetentionPolicy.RUNTIME)
From the javadoc for #Retention:
the retention policy defaults to RetentionPolicy.CLASS
From the javadoc for RetentionPolicy:
CLASS
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.
RUNTIME
Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
SOURCE
Annotations are to be discarded by the compiler.

Categories