Generics with annotation annotated by annotation - java

I am trying to do this, I have some "base" annotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.ANNOTATION_TYPE})
public #interface A
{
}
and I have annotaion B which is annotated by A
#A
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD })
public #interface B {
String value();
}
I want to have interface which behaves something like this, being sure that T is annotation which is annotated by A.
interface SomeInterface<T extends A>
{
void method(T argument);
}
So that I implement that something like this
public class Implementation implements SomeInterface<B>
{
public void method(B argument);
}
How to do that? When I use "T extends A" in SomeInterface, when I implement that, it says that B is not a valid substitue.
Thanks!

B is not a valid substitution for <T extends A> because B does not extend A.
Java does not include a way to require that a generic type parameter has a particular annotation.
If you can refactor SomeInterface to be a class instead of an interface, you could put a runtime check in the constructor:
protected SomeInterface(Class<T> classOfT) {
if(classOfT.getAnnotation(A.class) == null)
throw new RuntimeException("T must be annotated with #A");
}

Annotation inheritance is not possible in Java.
What you have written is simply an annotation annotated by another annotation, not an annotation extending another one.
If annotation inheritance would have been possible, I guess it would have been something like this:
public #interface B extends A {
String value();
}
But it just does not exist.
Check also this link and this link

Related

How to force annotations to have an "id" field?

I have the following annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface IdentifiableMethod {
String id() default "";
}
I will have to loop through a list of annotations and for each of them, perform a annotation.id().
Hence, I would have liked to use this "base" annotation to make it extended by other annotations:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface SpecificMethod extends IdentifiableMethod{
//invalid: annotation cannot have extends list
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface OtherSpecificMethod extends IdentifiableMethod{
//invalid: annotation cannot have extends list
}
... and then generically access the .id() method in a loop by getting in parameter a List<A extends IdentifiableMethod>, so that the compiler always makes me access that method.
However, I've just found out that in the Java specification, all Java annotations extend natively the interface Annotation and they cannot have an extends list [Source: this Stack Overflow question and its answers].
Is there any way to reach something similar?
Just to clarify the need, I need to get all the methods of all the classes within my package by reflection and scan for these annotations. They may be different (they may have more or less properties, different usages etc.), but they all need to have a String id field:
List<Class<?>> classes = getClasses(packageName);
for (Class<?> clazz : classes) {
for (Method method : clazz.getMethods()) {
for (Class<A> annotation : annotations) { //<-- annotations is a Collection<Class<A extends Annotation>>
if (method.isAnnotationPresent(annotation)) {
A targetAnnotation = method.getAnnotation(annotation);
String id = targetAnnotation.id(); //<-- this is not valid because A extends Annotation, not IdentifiableMethod
//rest of code (not relevant)
}
}
}
}
P.s. I already did this but I was looking for something cleaner:
String id = targetAnnotation.getClass().getMethod("id").invoke(targetAnnotation).toString();

Have a common base type for all my custom annotations

So, I have created several custom annotations:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Foo {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Bar {
}
Those annotations are used in my functions:
public class Worker {
#Foo
public void doTaskOne() {...}
#Bar
public void doTaskX() {...}
...
}
I want to use java reflection to check if certain annotation is declared in one method.
for (Method m : methods) {
if (m.isAnnotationPresent(Foo.class)) {
...
} else if (m.isAnnotationPresent(Bar.class)) {
...
}
}
The problem is that since in Java, custom annotation #interface is not able to be extended. I mean this is illegal:
public #interface Bar extends MyBaseAnnotation{
}
That's I am not able to have a base #interface for all my custom annotation class Foo and Bar. So, if I have a new custom annotation created, I need to add more else if condition in above method checking code, which sucks! Is there anyway to get rid of this problem? What I want to achieve is to generalize my method checking code to :
for (Method m : methods) {
if (m.isAnnotationPresent(MyBaseAnnotation.class)) {
...
}
}
How to achieve it?
You can annotate your custom annotations with a base custom annotation, like composed annotations do.
Instead of:
public #interface Bar extends MyBaseAnnotation{
}
use:
#MyBaseAnnotation
public #interface Bar {
}
Assuming that
#Parent
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface Foo {}
#Parent
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface Bar {}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
#interface Parent {}
and there is a method
public static boolean isAnnotationPresent(Method method, Class<? extends Annotation> parentAnnotation) throws NoSuchMethodException {
for (Annotation methodAnnotation : method.getDeclaredAnnotations()) {
if (methodAnnotation.annotationType().isAnnotationPresent(parentAnnotation)) {
return true;
}
}
return false;
}
you can do
isAnnotationPresent(m, Parent.class)
You got it right: there is no inheritance between annotation types in Java. You could make your own rules, though. By saying "if annotation B has annotation A over it, then B extends A", you define the rule that you will follow while using reflection.

How to call method from a reference send to annotation in java

I have a Interface I and a Abstract Class A , I have My custom annotation MyAnnotation which should take parameter as subclass S of A, now while processing annotation I want to call method of concrete class S
public interface I{
void m1();
}
public abstract class A implements I {
public abstract void m1();
}
public #interface MyAnnotation {
public Class< ? extends A> ref();
public Class< ? super A> ref2();
}
public S extends A{
public void m1() {}
}
I am annotating method like
#MyAnnotation(ref= new XX() ) or #MyAnnotation(ref= XX.class )
#MyAnnotation(ref= new yy() ) or #MyAnnotation(ref= yy.class )
whichever works
//In spring aspect before processing I am getting method annotation and trying to call m1()
annotation.ref().m1() //Error
annotation.ref2().m1() //Error
You can't use new XX() in an annotation. Annotations parameters can use a very specific set of types:
primitive
String
Class
an Enum
another Annotation
an array of any of the above
See this answer.
So to accomplish what you're trying to accomplish, you'd have to use a class.
You would then have to use reflection to create an instance and invoke the method.
Class<?> clazz = annotation.ref();
I instance = (I) cls.getConstructor().newInstance();
instance.m1();
See this answer.
Your classes must all have no-argument constructors, else you'll only be able to instantiate some this way but not others (leading you to have to conditionally branch based on the class).
You can't do that simply like that. You need an instance of the class first.
If your A class is a Spring's bean, you can inject ApplicationContext and get the bean from there. Then you can call a method.
#Autowired
private ApplicationContext context;
void test(MyAnnotation annotation) {
A bean = context.getBean(annotation.ref());
bean.m1();
}

How to create an annotation with an interface that has a generic?

I am trying to create an annotation that will allow me to wrap a (spring) bean with an instance of the supplied class. The interface has a type parameter which is (should not, if possible) not specified by the wrapping class. See the code below for an example of what I mean.
I managed to get a (compilation, haven't tried runtime yet) fix by making MyWrapperImpl implement the type parameter with super class of the class used by MyWrappedClass, however I would rather not specify it.
How can I keep the type parameter? In other words how can I keep MyWrapperImpl as generic as possible?
Annotation:
#Documented
#Target(ElementType.TYPE)
#Inherited
#Retention(RetentionPolicy.Runtime)
public #interface Wrap {
Class<? extends MyInterface<?>> classToWrapWith();
}
Interface:
public interface MyInterface<T> {
T getSomething();
}
A wrapper class:
public class MyWrapperImpl<T> implements MyInterface<T> {
private MyInterface<T> wrapped;
public T getSometing() {
// Do something special, such as:
System.out.println("Calling get something from wrapped object");
return wrapped.getSomething(); // MyWrapperImpl should "use" the type from the wrapped instance.
}
}
Annotated class:
// Attempt 1
#Wrap(classToWrapWith = MyWrapperImpl.class) // <-- Compile error "found class<MyWrapperImpl>, required class<? extends MyInterface<?>>"
// Attempt 2
#Wrap(classToWrapWith = MyWrapperImpl<T>.class) // <-- Compile error, cannot select from parameterized type.
public class MyWrappedClass implements MyInterface<SubObject> {
public SubObject getSomething() {
return new SubObject();
}
}
Wrapper class with a working fix (Where SuperObject is a parent class of SubObject, which is used in MyWrappedClass (see above)):
public class MyWrapperImpl<SuperObject> implements MyInterface<T> {
private MyInterface<SuperObject> wrapped;
public SuperObject getSometing() {
return wrapped.getSomething();
}
}

Class.getAnnotations() / getDeclaredAnnotations() returns empty array for subclass

I have an annotation defined like:
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#interface Retriable {
}
And I'm using it like this:
#Retriable
interface MyInterface {
public void myMethod();
}
Now, I have a second interface, which extends the first:
interface MySecondInterface extends MyInterface {
}
I want to get all annotations for MySecondInterface, it means that I would like to also get the annotation(s) defined on super interfaces.
What I tried:
Class clazz = MySecondInterface.class;
Retriable annotation = clazz.getAnnotation(Retriable.class);
System.out.println("Retriable annotation: " + annotation);
Annotation[] annotations = clazz.getAnnotations();
System.out.println("Annotations: " + Arrays.toString(annotations));
annotations = clazz.getDeclaredAnnotations();
System.out.println("Declared Annotations: " + Arrays.toString(annotations));
The result is:
Retriable annotation: null
Annotations: []
Declared Annotations: []
In all cases it can't find the Retriable annotation inherited from MyInterface. (DEMO)
Is there a way to make it recognize annotations of super-interface?
From the javadocs of java.lang.annotation.Inherited:
Note that this meta-annotation type has no effect if the annotated type is used to annotate
anything other than a class. Note also that this meta-annotation only causes annotations to be
inherited from superclasses; annotations on implemented interfaces have no effect.
so change interface to class. it will affect
#Retriable
class MyClass {
public void myMethod(){
}
}
class MySecondClass extends MyClass {
}

Categories

Resources