-1

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
Michael
  • 41,989
  • 11
  • 82
  • 128
Arvind
  • 1,207
  • 6
  • 27
  • 55

2 Answers2

3

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).

Michael
  • 41,989
  • 11
  • 82
  • 128
  • I think `((I) cls.newInstance()).m1()` is a better option than `...getMethod(...).invoke(...)` – ernest_k Oct 07 '18 at 18:06
  • 1
    @ernest_k `newInstance` is deprecated since 9; it's better to call `Constructor::newInstance` – Eugene Oct 07 '18 at 18:09
  • @Eugene That's right. My comment is just about avoiding the `getMethod(...).invoke(...)` part, if you notice... – ernest_k Oct 07 '18 at 18:11
  • @ernest_k + Eugene, You're both right. It was a bit of a lazy answer, mostly just copied and pasted from the sources I listed. I've improved it now – Michael Oct 07 '18 at 18:24
0

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();
}
Mariusz.v7
  • 2,322
  • 2
  • 16
  • 24