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();
}
}
}
Related
I have an interface with a naive implementation, say
interface MyService {
void doIt();
}
class MyServicePlain implements MyService{
#Inject
SomeOtherInterface
public void doIt () {
}
}
I want to make a cache that caches the doIt, so I wrote a wrapper :
class CachingMyService implements MyService {
#Inject
MyService inner;
int cacheThingie;
public int doIt() {
if (cached) ... {
return cacheThingie;
}
else {
result = inner.doIt();
addToCache(result);
return result;
}
}
}
Then, I add both implementations to my Binder:
public class ApplicationBinder extends AbstractBinder {
protected void configure() {
this.bind(MyServicePlain.class).to(MyService.class).in(Singleton.class).ranked(2);
this.bind(CachingMyService.class).to(MyService.class).in(Singleton.class).ranked(2);
}
}
I get errors complaining about:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no
object available for injection at
SystemInjecteeImpl(requiredType=MyService,parent=CachingMyService},position=-1,optional=false,self=false,unqualified=null,1102650897)
I trief using Qualitifaction like this:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface NonCached {
}
#NonCached
class MyServicePlain implements MyService{
}
And using that:
class CachingMyService implements MyService {
#Inject #NonCached
MyService inner;
But that does not work either.
What is the proper way to wrap a caching service like this? And how can I make hk2 choose the proper implementations?
You need to use the qualifiedBy(Annotation) method when you want to qualify different types. You also need to annotate each injection point with a different qualifier annotation.
First you need the annotations and have a way to get an instance of them (the qualifiedBy method requires an annotation instance)
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface NonCached {
class Literal extends AnnotationLiteral<NonCached> implements NonCached {
public static final NonCached INSTANCE = new Literal();
private Literal() {
}
}
}
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface Cached {
class Literal extends AnnotationLiteral<Cached> implements Cached {
public static final Cached INSTANCE = new Literal();
private Literal() {
}
}
}
Then when you bind them used qualifiedBy
this.bind(MyServicePlain.class).to(MyService.class)
.in(Singleton.class).qualifiedBy(NonCached.Literal.INSTANCE);
this.bind(CachingMyService.class).to(MyService.class)
.in(Singleton.class).qualifiedBy(Cached.Literal.INSTANCE);
Then when you inject them, add the applicable qualifier
#Inject
#NonCached
MyService service;
#Inject
#Cached
MyService service;
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);
}
In an aspect, i'd like stop at a specified method. This method has one parameter which is annotated with a class level annotation:
The annotation is:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Auditable {}
The parameter is an object of a class annotated like:
#Auditable
public class User {}
The method I like to inspect:
public Object findSingleResultByExample(final Object entity) {}
This aspect is not working:
#AfterReturning(value="execution(* org.wtp.repository.GenericDao.find*(#org.wtp.aspects.Auditable (*)))",
argNames = "joinPoint, result",
returning = "result")
private void auditFindAnnotation(final JoinPoint joinPoint, final Object result) {}
First of all, your advice method must be public, not private. Please change that into
public void auditFindAnnotation(...)
It is not working because your pointcut intercepts methods with an #Auditable parameter annotation. Your sample method does not have such an annotation, though. It would work if the method signature was like this:
public Object findSingleResultByExample(final #Auditable Object entity) {}
BTW, then the #Target(ElementType.TYPE) restriction must be removed or extended in order for the code to still compile.
But I guess what you want is not to match on parameter annotations, but on type annotations. Then your pointcut would look like this (no parentheses around * this time):
execution(* org.wtp.repository.GenericDao.find*(#org.wtp.aspects.Auditable *))
But again, this does not match your sample method because its parameter type is not User or Auditable but just Object and the latter does not carry the annotation. You can see the difference if you overload your find* method and do something like this:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Auditable {}
package de.scrum_master.app;
#Auditable
public class User {}
package de.scrum_master.app;
import java.util.ArrayList;
public class Application {
public Object findSingleResultByExample(final Object entity) {
return entity;
}
public Object findSingleResultByExample(final User entity) {
return entity;
}
public static void main(String[] args) {
Application application = new Application();
application.findSingleResultByExample("foo");
application.findSingleResultByExample(new User());
application.findSingleResultByExample(new ArrayList<String>());
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AuditAspect {
#AfterReturning(
value = "execution(* de.scrum_master.app..find*(#de.scrum_master.app.Auditable *))",
argNames = "thisJoinPoint, result",
returning = "result"
)
public void auditFindAnnotation(final JoinPoint thisJoinPoint, final Object result) {
System.out.println(thisJoinPoint + " -> " + result);
}
}
The console log then looks like this:
execution(Object de.scrum_master.app.Application.findSingleResultByExample(User)) -> de.scrum_master.app.User#4a574795
Update: In order to get the whole thing working without changing or overloading any method signatures, you would have to make your pointcut match all calls and dynamically determine the type and its annotations from withing the aspect via reflection (not so nice, but possible). Feel free to ask questions if you do not understand this idea.
Good morning,
I have defined a custom annotation that I want to use to mark some classes as Auditable
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Auditable {
}
And have declared an aspect to handle all classes marked with this annotation. I am using AspectJ with Eclipse
#Aspect
public class AuditableClassAspect extends AbstractAuditableAspect {
#Autowired
private ApplicationContext applicationContext;
// Makes the bean auditable
#DeclareMixin(value="#Auditable *")
public Auditable auditableBeanFactory(Object instance) {
// Use a bean delegator as a mixin object
Auditable mixin = applicationContext.getBean(PersistentDelegate.class);
mixin.setObject(instance);
return mixin;
}
#Pointcut("get(* (#Auditable *).*) && this(object)")
public void executionGet(Object object) {}
#Pointcut("set(* (#Auditable *).*) && this(object)")
public void executionSet(Object object) {}
}
Then I have marked a class:
#Auditable
public class Report implements Serializable {
private static final long serialVersionUID = 4746372287860486647L;
private String companyName;
private Date reportingDate;
I am using AspectJ with Spring, and have defined the Aspect in applicationContext.xml
<bean class="com.xxx.aop.AuditableClassAspect" factory-method="aspectOf" />
My issue is that there is no matching happening. The Aspect doesn't "detect" the Report class as an Auditable class.
In eclipse it doesn't show any matching. At run time I have an exception when I am casting my report in an Auditable interface.
Do you have any idea what there is no match?
For information, if in my code I write
#DeclareMixin(value="com.xxx.Report")
Then I have a matching and the Aspect works.
Is there something missing with the annotation?
Thanks
Gilles
Searchable.java
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Searchable { }
Obj.java
public class Obj {
#Searchable
String myField;
}
void main(String[] args)
Annotation[] annotations = Obj.class.getDeclaredField("myField").getAnnotations();
I would expect annotations to be containing my #Searchable. Though it is null. According to documentation, this method:
Returns all annotations present on this element. (Returns an array of length zero if this element has no annotations.) The caller of this method is free to modify the returned array; it will have no effect on the arrays returned to other callers.
Which is even more weird (to me), since it returns null instead of Annotation[0].
What am I doing wrong here and more important, how will I be able to get my Annotation?
I just tested this for you, and it just works:
public class StackOverflowTest {
#Test
public void testName() throws Exception {
Annotation[] annotations = Obj.class.getDeclaredField("myField").getAnnotations();
System.out.println(annotations[0]);
}
}
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#interface Searchable {
}
class Obj {
#Searchable
String myField;
}
I ran it, and it produces the following output:
#nl.jworks.stackoverflow.Searchable()
Can you try running the above class in your IDE? I tried it with IntelliJ, openjdk-6.
Your code is correct. The problem is somewhere else. I just copied and run your code and it works.
It is possible that you are importing the wrong Obj class in your code you may want to check that first.
In my case, i had forgotten to add
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
to the method, so in the end it should look like:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}
In my case, the error was in my own annotation.
I fixed a couple of things, and it finally ended up like this:
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Target( { METHOD, FIELD, ANNOTATION_TYPE })
#Retention(RUNTIME)
public #interface MyAnnotation{
}
It works now