I'm creating some annotations, and one of them I trying to enable to annotate twice. I use #Repeatable and created the conteiner. But when I use the annotation twice it appears that it needs to use #Repeatable.
As shown in the image below:
Message error: Duplicate annotation of non-repeatable type #TX2Value. Only annotation types marked #Repeatable can be used multiple times at one target.
#Repeatable(TX2ValueContainer.class)
#Retention(RUNTIME)
#Target({ FIELD, METHOD, ANNOTATION_TYPE, TYPE_USE })
public #interface TX2Value {
String name();
...
}
#Retention(RUNTIME)
#Target({ FIELD, METHOD, ANNOTATION_TYPE, TYPE_USE })
#interface TX2ValueContainer {
TX2Value[] value();
}
public void TestA() {
#TX2Value(name="test01")
#TX2Value(name="test02")
private String value;
}
Related
I am trying to create an annotation by combining annother's functionality. Let's say as below:
#Documented
#Retention(RUNTIME)
#Target({TYPE, METHOD})
#Around
#io.micronaut.tracing.annotation.NewSpan
public #interface NewSpan {
String value() default "";
}
Now it's seems impossible to pass the value to io.micronaut.tracing.annotation.NewSpan, after searching many other answers and java docs, it seems impossible to me, any help.
So when I use my #NewSpan("val"), it should be passed down to io.micronaut.tracing.annotation.NewSpan's value.
Thanks!
I believe that should be the same as in spring
#Documented
#Retention(RUNTIME)
#Target({TYPE, METHOD})
#Around
#io.micronaut.tracing.annotation.NewSpan
public #interface NewSpan {
#AliasFor(annotation = io.micronaut.tracing.annotation.NewSpan.class, member="value")
String value() default "";
}
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();
The #Parameters annotation implementation from org.testng.annotations looks like this:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE})
public #interface Parameters {
String[] value() default {};
}
So, it should allow me to use it on a ElementType.TYPE => it could also be used on a class.
When I use it on a method, I simply take the value using:
#Parameters("value")
public void m(String value) {
...
}
But if I use
#Parameters("value")
public class A {
...
}
how can I get the value inside the class?
If you want to use it for initialising class variables you can put in on constructor of class and use it.
ElementType.TYPE also means applicable to interfaces and enums - may be that one is specified if you want to extend the annotation.
Given this annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
public #interface Interceptor {
Class<? extends Behaviour> value();
}
The users of my library can extend its API creating custom annotations annotated with #Interceptor, as follows:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Interceptor(BypassInterceptor.class)
public #interface Bypass {
}
AbstractProcessor provides a method called getSupportedAnnotationTypes which returns the names of the annotation types supported by the processor. But if I specify the name of #Interceptor, as follows:
#Override public Set<String> getSupportedAnnotationTypes() {
Set<String> annotations = new LinkedHashSet();
annotations.add(Interceptor.class.getCanonicalName());
return annotations;
}
The processor#process method will not be notified when a class is annotated with #Bypass annotation.
So, when using an AbstractProcessor, how to claim for annotations which target is another annotation?
If your annotation processor is scanning for all annotations that are meta-annotated with your annotation, you'll need to specify "*" for your supported annotation types, and then inspect each annotation's declaration (using ProcessingEnvironment.getElements() to determine whether it has the meta-annotation of interest.
You should use the #SupportedAnnotationTypes annotation on your processor, and not override the getSupportedAnnotationTypes() method, for example:
#SupportedAnnotationTypes({"com.test.Interceptor"})
public class AnnotationProcessor extends AbstractProcessor {
...
The Processor.getSupportedAnnotationTypes() method can construct its
result from the value of this annotation, as done by
AbstractProcessor.getSupportedAnnotationTypes().
Javadoc:
https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/SupportedAnnotationTypes.html
I have written below the Custom Annotation.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
String value();
}
and am using the annotation as below.
#MyAnnotation("someValue")
public void someMethod(){
}
above code is working fine without any issues.
But in the annotation class, value() method name i have to reanme. Can i do as below?
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
String name();
}
I tried doing but eclipse is giving the compilation error.
- The attribute value is undefined for the annotation type
MyAnnotation
- The annotation #MyAnnotation must define the attribute
name
Any reason?
Use it like this :
#MyAnnotation(name="someValue")
public void someMethod(){
}
because by default annotation has value method so if you specify like this
#MyAnnotation("someValue")
public void someMethod(){
}
it will by default take it as value="someValue"