Herbert Schildt mentions in his book on Java,
#Inherited is a marker annotation that can be used only on another annotation declaration. Furthermore, it affects only annotations that will be used on class declarations. #Inherited causes the annotation for a superclass to be inherited by a subclass.
Therefore, when a request for a specific annotation is made to the subclass, if that annotation is not present in the subclass, then its superclass is checked. If that annotation is present in the superclass, and if it is annotated with #Inherited, then that annotation will be returned.
I know pretty well that annotations are not inherited. Exceptions are annotations, which its declaration is annotated with #Inherited.
I have understood the rest of the annotations which includes java.lang.annotation: #Retention, #Documented, and #Target. and other three—#Override, #Deprecated, and #SuppressWarnings.
I am a bit confused when it comes to the #Inherited annotation. Could someone demonstrate it with a simple foobar example?
Secondly, going through one of the questions regarding this on StackOverflow, I came across this,
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD) #Inherited
public #interface Baz {
String value(); }
public interface Foo{
#Baz("baz") void doStuff();
}
public interface Bar{
#Baz("phleem") void doStuff();
}
public class Flipp{
#Baz("flopp") public void doStuff(){}
}
What use does the #Inherited annotation have when put on the annotation #interface Baz?
Please don't explain me in context with annotations used Spring Framework, I am no in way familiar with it.
First, as the quote you posted states,
it affects only annotations that will be used on class declarations
So your example doesn't apply since you're annotating methods.
Here's one that does.
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Bar.class.isAnnotationPresent(InheritedAnnotation.class));
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
//#Inherited
#interface InheritedAnnotation {
}
#InheritedAnnotation
class Foo {
}
class Bar extends Foo {
}
This will print false since the CustomAnnotation is not annotated with #Inherited. If you uncomment the use of #Inherited, it will print true.
Related
Is it always the case that the following
public interface Foo {
#MyCustomAnnotation
void bar();
#MyCustomAnnotation
void bar2();
}
Is equivalent to
#MyCustomAnnotation
public interface Foo {
void bar();
void bar2();
}
Or does it depend on how the annotation is defined? In other words, are class/interface-level annotations always inherited by methods of that type (as long as the method isn't also marked with this annotation)?
Specifically, if I define the annotation above as
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnnotation {
}
Will methods inherit this annotation from the surrounding class/interface?
It is never the case that they are equivalent unless the library interpreting the annotation specifically decides to treat the type-level annotation as a default (e.g., Spring's #Transactional). Even then, it is entirely up to the code written in the library whether a combination of class-level and method-level annotations result in combination (#RequestMapping) or replacement (#Transactional) of definitions.
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.
I have a Weld qualifier annotation declared like this:
#Qualifier
#Retention(RUNTIME)
#Target({Field, Method, Constructor})
public #interface AccountResponse {
}
My bean interface is this:
#Stateless
public interface Responder {
/* Declares stuff */
}
The qualified implementation is this:
#AccountResponse
public class AccountResponseResponder implements Responder {
/* Does stuff */
}
The Maven compiler says (on AccountResponseResponder.java):
annotation type not applicable to this type of declaration
I'm sure I'm missing something obvious, but what it is escapes me. Any help would be appreciated.
#Target({Field, Method, Constructor})
Means you can only apply this annotation to given parts of your code. In order to enable class annotation you would have to add Type to the #Target
I have defined an annotation for validation like this:
#Documented
#Constraint(validatedBy = MyValidator.class)
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomValid {
//required methods
}
Now, I want to decide the "validatedBy" class at runtime. Like I have a field in my class:
public class MyClass {
#MyCustomValid
MyObject myObject;
}
How do I pass the ConstraintValidator class at runtime. I have different implementations for different cases.
Annotations are compiled into the code at compile time and they can't change, so you need a hack.
Create a validation class which delegates to another validator. The delegate needs to be created at runtime, using whatever algorithm you design. Note that the code might be used concurrently, so you need a thread-safe initialization.
I am working on a logging aspect which need to intercept all the classes and methods annotated with a custom annotation.
Below is custom annotation class which can be annotated on class and methods:
#Documented
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface Loggable {
LogLevel value();
}
I am using these pointcut expressions to intercept methods and classes with annotation #Loggable, which is working for all the simple classes but does not work for classses which extend or implement.
//Works for annotation #Loggable on class level
#Pointcut("execution(* *(..)) && within(#com.logger.Loggable *)")
public void classAnnotationLogger() {
}
//Working for methods annotated with #Loggable
#Before(value = "#annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {
..
..
}
Below is code for super class
#Component
#Loggable(LogLevel.INFO)
public abstract class Processor{
public void process(){
readProcess();
}
public abstract void readProcess();
}
Below is code for subclass
#Service
#Loggable(LogLevel.INFO)
public class MyServiceProcessor extends Processor {
#Override
public void readProcess(){
...
...
}
}
In the application readProcess() is called by doing
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
Even though I have #Loggable on Processor and MyServiceProcessor, when readProcess is called the advice is not being invoked.
But advice is invoked for process() and not readProcess.
How do I write the pointcut expression which also intercepts the call to any subclass methods, when annotation #Logabble is applied on any class or method?
Well, first of all this
#Pointcut("execution(* *(..)) && within(#com.logger.Loggable *)")
public void classAnnotationLogger() {}
is just a pointcut and not an advice, so it does not do anything unless you also have an advice actually using this pointcut. You have not posted such an advice, so I can only speculate.
Secondly, you have not provided any sample code which would be triggered by
#Before(value = "#annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {}
at all, i.e. no annotated method. Your sample code only shows annotated classes.
As for the #Loggable annotation on the subclass, it should not be necessary because its base class already carries the same annotation and the annotation is #Inherited. This works for annotations on classes, but not for annotations on methods or interfaces, see my other answer for an explanation and a possible workaround.
This example of yours should actually work, I cannot see a reason why it would not:
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
But this internal call to readProcess() (equivalent to this.readProcess()) will not work:
public void process() {
readProcess();
}
This is because Spring AOP is a proxy-based "AOP lite" framework relying on JDK dynamic proxies (for interfaces) or CGLIB proxies (for classes). But calls to this.someMethod() are not routed through proxies of any type so they cannot be intercepted by Spring aspects. This is documented behaviour. If you want to overcome this limitation and apply aspects to internal method calls as well, please use full-blown AspectJ as documented here.