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.
Related
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.
I don't know if you managed to figure out what i am trying to do just from the title so I'll try to explain with example
Lets suppose I have created my own annotation #VerifySomething
And I have created test class for that annotation to make sure it works.
Now lets suppose that I have class SomeClass with field something anoted with annotation #VerifySomething
class SomeClass {
#VerifySomething
String something;
}
So far so good, but now I want to create test class for my SomeClass however I don't see any point in verifying all the test cases of something as I have already checked that #VerifySomething works as it should in class which tests that annotation, however I need to make sure that field something actually has #VerifySomething annotation without copy pasting all these test cases.
So my question is, is there a way to check if some field has one or more required annotation without writing test cases I have already written in annotation test class to make sure it works as it should.
You can use getAnnotation to determine if there is a specific Annotation on the field, which takes the annotation class as a parameter:
field.getAnnotation( SomeAnnotation.class );
Here is a method you can use to verify that a class has a field annotated by given annotation:
import java.lang.reflect.Field;
import javax.validation.constraints.NotNull;
import org.junit.Test;
import org.springframework.util.Assert;
public class TestHasAnnotatedField {
#Test
public void testHasFieldsWithAnnotation() throws SecurityException, NoSuchFieldException {
Class<?>[] classesToVerify = new Class[] {MyClass1.class, MyClass2.class};
for (Class<?> clazz : classesToVerify) {
Field field = clazz.getDeclaredField("something");
Assert.notNull(field.getAnnotation(NotNull.class));
}
}
static class MyClass1 { #NotNull String something; }
static class MyClass2 { #NotNull String something; }
}
I am not sure I am following, but in case you want to verify whether a class and or its properties have a given Bean Validation constraint, you can use the meta data api. The entry point is Validator#getConstraintsForClass(SomeClass.class). You get a BeanDescriptor. From there you can do _beanDescriptor#getConstraintsForProperty("something") which gives you a PropertyDescriptor. Via propertyDescriptor#getConstraintDescriptors() you get then a set of ConstraintDescriptors which you can iterate to verify that a given constraint annotation was used.
Note, this is a Bean Validation specific solution compared to generic reflection as in the answer above, but it depends what you are really after. To be honest I don't quite understand your use case yet.
I've got two projects, a scala project and a java project. My scala project references the java project in the build path. In my java project, i'm declaring the following annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
public String Name();
}
In my scala project, I'm annotating some methods. I.e.
class MyClass {
...
#MyAnnotation(Name="Blah")
def myMethod() {
...
}
}
In another file somewhere, i'm trying to pull out the annotations.
var methods = myClassInstance.getClass().getDeclaredMethods()
var myMethod : Method = null
for (method <- methods) {
if (method.getName().equals("myMethod")) {
myMethod = method
}
}
var annotations = myMethod.getDeclaredAnnotations()
Unfortunately, annotations is always an empty array. Am I doing something fundamentally wrong or am I just missing something minor? Thanks!
EDIT
Originally, I was annotating myMethod with myAnnotation twice, which is incorrect as someone pointed out. It turns out this wasn't the problem. I'm still getting an empty array for annotations. No exception is being thrown.
I tried your code, the problem is that your use #MyAnnotation twice for myMethod, which should raise AnnotationFormatError: Duplicate annotation for class
When i change to use it once, the reflection just retrieves the annotions.
I'm writing an swing app and i'd like to have 'wait' cursor when some methods are executed. We can do it this way:
public void someMethod() {
MainUI.getInstance().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//method code
MainUI.getInstance().setCursor(Cursor.getDefaultCursor());
}
What I'd like to achieve is a java annotation, that would set wait cursor before method execution and set it back to normal after execution. So previous example would look something like this
#WaitCursor
public void someMethod() {
//method code
}
How can i achieve this? Suggestions about other variants of solving this problem are also welcome.
Thanks!
P.S. - We use Google Guice in our project, but i don't get how to solve the problem using it. If someone would provide me with simple example of similar problem, that would be very helpful
You may use AspectJ, or use Google Guice which bring its own AOP.
The object having the method annotated with your WaitCursor annotation must be injected with Guice.
You define your annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface WaitCursor {}
You add a MethodInterceptor :
public class WaitCursorInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// show the cursor
MainUI.getInstance().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// execute the method annotated with `#WaitCursor`
Object result = invocation.proceed();
// hide the waiting cursor
MainUI.getInstance().setCursor(Cursor.getDefaultCursor());
return result;
}
}
And define a module where you bind the interceptor on any method having your annotation.
public class WaitCursorModule extends AbstractModule {
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(WaitCursor.class), new WaitCursorInterceptor());
}
}
You can see more advanced uses on this page
You might want to look at using around() advice in AspectJ in conjunction with your annotation to associate the around() advice with all methods that are qualified with your annotation.
Say I have an annotation with a property:
#Named(name = "Steve")
private Person person
and I want to create a compound annotation with several meta-annotations, including the one that takes a property
#Named
#AnotherAnnotation
#YetAnotherAnnotation
public #interface CompoundAnnotation {
...
}
Is there a way that I can pass properties to the compound annotation to one of the meta annotations?
Eg, something like this:
#CompoundAnnotation(name = "Bob")
private Person person;
that is equivalent to, but much more convenient than
#Named(name = "Bob")
#AnotherAnnotation
#YetAnotherAnnotation
private Person person;
Thanks!
PS apologies for my poor choice of an example annotation - I didn't have the javax.inject.#Named annotation in mind, just some arbitrary annotation that has properties.
Thank you everyone for your answers/comments.
It definitely seems to be the case that this is not possible. However, it just happens that there is a simple work-around for my case-in-point, which I will share in case it helps anyone:
I am working with Spring and want to create my own Annotations that have #Component as a meta-annotation, thus being autodetected by component scanning. However, I also wanted to be able to set the BeanName property (corresponding to the value property in #Component) so I could have custom bean names.
Well it turns out that the thoughtful guys at Spring made it possible to do just that - the AnnotationBeanNameGenerator will take the 'value' property of whatever annotation it is passed and use that as the bean name (and of course, by default, it will only get passed annotations that are #Component or have #Component as a meta-annotation). In retrospect this should have been obvious to me from the start - this is how existing annotations with #Component as a meta-annotation, such as #Service and #Registry, can provide bean names.
Hope that is useful to someone. I still think it's a shame that this is not possible more generally though!
It is a few years later now, and since you are using Spring, what you are asking for is sort of possible now using the #AliasFor annotation.
For example:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#SpringApplicationConfiguration
#ActiveProfiles("test")
public #interface SpringContextTest {
#AliasFor(annotation = SpringApplicationConfiguration.class, attribute = "classes")
Class<?>[] value() default {};
#AliasFor("value")
Class<?>[] classes() default {};
}
Now you can annotate your test with #SpringContextTest(MyConfig.class), and the amazing thing is that it actually works the way you would expect.
N.B. When you need to programmatically get the attribute values, the Spring automagical aliasing works only when you use AnnotatedElementUtils instead of AnnotationUtils, as the documentation says:
AnnotatedElementUtils defines the public API for Spring's meta-annotation programming model with support for annotation attribute overrides. If you do not need support for annotation attribute overrides, consider using AnnotationUtils instead.
Example:
final Named namedAnnotation = AnnotatedElementUtils.findMergedAnnotation(Person.class, Named.class);
final String name = namedAnnotation.name();
assertEquals("Steve", name);
Is there a way that I can pass properties to the compound annotation to one of the meta annotations?
I think the simple answer is "no". There is no way to ask Person what annotations it has on it and get #Named for example.
The more complex answer is that you can chain annotations but you would have to investigate these annotations via reflection. For example, the following works:
#Bar
public class Foo {
public static void main(String[] args) {
Annotation[] fooAnnotations = Foo.class.getAnnotations();
assertEquals(1, fooAnnotations.length);
for (Annotation annotation : fooAnnotations) {
Annotation[] annotations =
annotation.annotationType().getAnnotations();
assertEquals(2, annotations.length);
assertEquals(Baz.class, annotations[0].annotationType());
}
}
#Baz
#Retention(RetentionPolicy.RUNTIME)
public #interface Bar {
}
#Retention(RetentionPolicy.RUNTIME)
public #interface Baz {
}
}
However the following statement will return null:
// this always returns null
Baz baz = Foo.class.getAnnotation(Baz.class)
This means that any 3rd party class that is looking for the #Baz annotation won't see it.