I have an annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface A {
Class<?> value();
}
and another annotation that uses #AliasFor
#A (Void.class)
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface B {
#AliasFor(annotation = A.class)
Class<?> value();
}
which is used on class
#B(D.class)
public class C implements D {
}
If I have an instance of C, how can I programatically resolve A.value() to Class<D>?
I'm trying to synthesise the annotation with AnnotationUtils but when I retrieve the value I'm constantly getting Class<Void>.
After some digging around, the answer is that I've used the wrong class. Instead of AnnotationUtils it can be done with AnnotatedElementUtils:
#Test
public void shouldFindAliasedValue() {
Class<?> actual = AnnotatedElementUtils.findMergedAnnotation(C.class, A.class).value();
then(actual).isEqualTo(D.class);
}
Related
We're using #JacksonAnnotationsInside and would like to inject a property from the classes using the meta annotation.
i.e. we have a meta annotation with #JsonTypeInfo() and would like to inject the defaultImpl via the aggregating annotation.
Here is the annotation I'm trying to use:
#Inherited
#JacksonAnnotationsInside
#Retention(RetentionPolicy.RUNTIME)
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class") //, defaultImpl=defaultType())
public #interface PolymorphismSupport {
//#AliasFor("defaultImpl") ...
Class<?> defaultType() default Object.class;
}
The AliasFor like support is not available in Jackson.But as an workaround we can modify the consumption of metadata supplied by annotation by extending JacksonAnnotationIntrospector.
What you are trying to achieve can be done by providing an custom JacksonAnnotationIntrospector which will supply the default implementation from the PolymorphismSupport annotation.
#Inherited
#JacksonAnnotationsInside
#Retention(RetentionPolicy.RUNTIME)
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
public #interface PolymorphismSupport {
Class<?> defaultType() default Object.class;
}
public class CustomAnnotationIntrospector extends JacksonAnnotationIntrospector {
#Override
protected TypeResolverBuilder<?> _findTypeResolver(MapperConfig<?> config, Annotated ann, JavaType baseType) {
TypeResolverBuilder<?> b = super._findTypeResolver(config, ann, baseType);
PolymorphismSupport support = _findAnnotation(ann, PolymorphismSupport.class);
if (null != b && null != support) {
b.defaultImpl(support.defaultType());
}
return b;
}
}
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
setAnnotationIntrospector(new CustomAnnotationIntrospector());
}
}
The only downside with this approach is that you have to register the introspector into the object mapper when initializing.
I have a weird problem trying to add a parameterized logging interceptor to my Java EE 7 application.
I went from a class interceptor using the #Interceptors annotation to writing a custom interceptor binding. What I have not looks like this...
The annotation
#Inherited
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({
ElementType.TYPE,
ElementType.METHOD
})
public #interface LogMethodCall {
MethodLogger logLevel() default MethodLogger.INFO;
}
The interceptor
#Slf4j
#LogMethodCall
#Interceptor
#Priority(Interceptor.Priority.APPLICATION)
public class ActionInterceptor {
#AroundInvoke
protected Object protocolInvocation(final InvocationContext ic) throws Exception {
log.info(
"{}: <{}> called. Parameters={}",
ic.getTarget().getClass().getName(),
ic.getMethod().getName(),
ic.getParameters());
return ic.proceed();
}
}
The usage
#GET
#Path("/{account}")
#LogMethodCall
public void inboxes(#Suspended AsyncResponse response, #PathParam("account") String account) {
...
}
When I use it like this everything works OK.
Buy when I try to use change the logLevel and use
#LogMethodCall(logLevel=MethodLogger.DEBUG)
then my interceptor never gets called.
What am I missing here? Why setting the annotation value breaks the code?
If you say that your interceptor is catching only when the value is INFO, you can consider to put your logLevel() attribute as #Nonbinding.
By default, qualifier arguments are considered for matching bean qualifiers to injection point qualifiers. A #Nonbinding argument is not considered for matching.
Try this:
#Inherited
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({
ElementType.TYPE,
ElementType.METHOD
})
public #interface LogMethodCall {
#Nonbinding MethodLogger logLevel() default MethodLogger.INFO;
}
I have created some custom annotations to use for system tests which are run via JUnit.
A test e.g. looks like this:
#TestCaseName("Change History")
public class ChangeHistory extends SystemTestBase
{
#Test
#Risk(1)
public void test()
{
...
I am now implementing a Test Runner which shall report the test name, the risk and the somewhere for documentation purposes.
public class MyRunner extends BlockJUnit4ClassRunner
{
...
#Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier)
{
...
System.out.println("Class annotations:");
Annotation[] classanno = klass.getAnnotations();
for (Annotation annotation : classanno) {
System.out.println(annotation.annotationType());
}
System.out.println("Method annotations:");
Annotation[] methanno = method.getAnnotations();
for (Annotation annotation : methanno) {
System.out.println(annotation.annotationType());
}
The output is
Class annotations:
Method annotations:
interface org.junit.Test
So getAnnotations() seems to return annotations of JUnit only and not all annotations. This is not mentioned in the documentation of JUnit:
Returns the annotations on this method
The return type is java.lang.Annotation which made me believe that I can use any annotation. I defined the annotation like follows - I just used it and when there was an error I let Eclipse generate the annotation:
public #interface Risk {
int value();
}
How do I get all annotations of the test class and test method?
You need to set the retention policy of the Risk annotation to RUNTIME. Otherwise, the annotation will be discarded after the compilation and won't be available during the execution of the code.
This should be working:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Risk {
int value();
}
In the example given in http://undancer.com/2013/10/30/Jersey-2.4-User-Guide/#ef.annotations (also code excerpt below) I dont quite understand the use case where this is needed. Could someone please explain the reason for using such custom annotiations ?
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#EntityFiltering
public #interface ProjectDetailedView {
/**
* Factory class for creating instances of {#code ProjectDetailedView} annotation.
*/
public static class Factory
extends AnnotationLiteral<ProjectDetailedView>
implements ProjectDetailedView {
private Factory() {
}
public static ProjectDetailedView get() {
return new Factory();
}
}
}
I recently found that ( http://www.javabeat.net/articles/30-annotations-in-java-50-2.htmlthe )syntax of the #Override annotation is
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.RUNTIME)
public #interface Override
{
}
But I think the following.Since it can be applied only to methods and since it inform this to compiler.
#Retention(RetentionPolicy.CLASS
#Target(ElementType.METHOD)
public #interface Override
{
}
Please tell me which one is correct. Please explain, if i am wrong.
Thanks.
Both are wrong; it is defined (according to javadoc) as
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface Override