I have an interceptor binding annotation :
#InterceptorBinding
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyBinding {
}
To this CDI interceptor :
#Interceptor
#MyBinding
public class MyInterceptor {
#AroundInvoke
public Object applyPolicy(InvocationContext ctx) throws Exception {
return blablabla;
}
}
And a class annotated, that mean every methods of this class will invoke MyInterceptor
#MyBinding
public class GlobalController {
public void methodA() {...}
public void methodB() {...}
}
All works fine, but I wish methodB not invoking my interceptor.
I tried both annotations #ExcludeClassInterceptors and #ExcludeDefaultInterceptors on my method but it doesn't works for me. I think these annotations are especially for exclude a method for EJB Interceptor, and not CDI Interceptor with Interceptor binding.
Not sure about these annotations but as a workaround you can add an annotation to the method you want to exclude. Get Method from InvocationContext in the interceptor and check whether the method has the annotation. In this case just delegate to the original method.
Try #MyBinding at method level:
public class GlobalController {
#MyBinding
public void methodA() {...}
public void methodB() {...}
}
Related
I have #Tenantable annotation to decide for pointCut :
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Tenantable {
}
this my aspect :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Around("publicMethod() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
This is working without any problem for this service class :
#Tenantable
#Service
public class MyService(){
public void doSomething(){
...
}
}
my aspect is running when I call doSomething() method, It is ok but I want to implement aspect for CrudRepository interface that belongs spring data.
I have changed my Aspect to achieve this like below :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Pointcut("this(org.springframework.data.repository.Repository)")
public void repositoryExec(){}
#Around("publicMethod() && repositoryExec() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
this is repository :
#Tenantable
#Repository
public interface MyRepository extends CrudRepository{
}
But it doesn't work when I call any method inside of MyRepository.
Is there anyway to do this?
Edit :
It works for all repositories when I apply these :
#Pointcut("execution(public * org.springframework.data.repository.Repository+.*(..))")
and exclude this :
#within(com.sam.example.aspect.aspectexample.model.Tenantable)
But I need this anotation to apply it for specific repositories.
Having taken another look, I think I know what is going on here: You are assuming that just because you made your annotation #Inherited, it will be inherited by implementing classes if you annotate an interface. But this assumption is wrong. #Inherited only works in exactly one case: when extending an annotated base class. It does not work for annotated interfaces, methods etc. This is also documented here:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
As soon as you annotate your implementing class, it works.
Your repositoryExec pointcut should end with + to advice all subclass of Repository
#Pointcut("this(org.springframework.data.repository.Repository+)")
I have CDI interceptor class annotated with javax.interceptor.InterceptorBinding #LogBinding, defined as follows:
#InterceptorBinding
#Retention(RUNTIME)
#Target({METHOD, TYPE})
public #interface LogBinding {}
Then I use annotation on EJB bean:
#Alternative
#Stateless
#LogBinding
public class FooService {
#Asynchronous
public fooMethod() {
}
}
I invoke fooMethod from another bean. The problem is that interceptor isn't called. Everything works when I change #LogBinding annotation to #Interceptors({LogInterceptor.class}) on the FooService.
I don't know if it may have impact but FooService is market as #Alternative, because it's injected in other places as EJB bean, below is the producer field:
#Default
#Produces
#EJB
private FooService fooService;
#Interceptor
#LogBinding
#Priority(Interceptor.Priority.APPLICATION)
public class LogInterceptor {
#AroundInvoke
public Object invoke(final InvocationContext invocationContext) throws Exception {
System.out.println("it works");
}
}
Why it doesn't work?
You also have to annotate your interceptor class with that binding in order for it to know which class to use as the interceptor
#LogBinding
#Interceptor
public class LogInterceptor {...}
I am learning Java EE CDI, dependency injection, and #Produces in particular. I am wondering why in getGreedingCard() method, it needs a #Produces annotation at all, since the two classes GreetingCardImpl and AnotherGreetingCardImpl are already imported into the space. This is just like the regular package/class dependency and a simple import solves the problem. Why does it need a dependency injection through a #producer annotation?
Thanks for explanation in advance.
public interface GreetingCard {
void sayHello();
}
public class GreetingCardImpl implements GreetingCard {
public void sayHello() {
System.out.println("Hello!!!");
}
}
public class AnotherGreetingCardImpl implements GreetingCard {
public void sayHello() {
System.out.println("Have a nice day!!!");
}
}
import com.javacodegeeks.snippets.enterprise.cdibeans.impl.AnotherGreetingCardImpl;
import com.javacodegeeks.snippets.enterprise.cdibeans.impl.GreetingCardImpl;
#SessionScoped
public class GreetingCardFactory implements Serializable {
private GreetingType greetingType;
#Produces
public GreetingCard getGreetingCard() {
switch (greetingType) {
case HELLO:
return new GreetingCardImpl();
case ANOTHER_HI:
return new AnotherGreetingCardImpl();
default:
return new GreetingCardImpl();
}
}
}
I am wondering why in getGreedingCard() method, it needs a #Produces
annotation at all, since the two classes GreetingCardImpl and
AnotherGreetingCardImpl are already imported into the space.
Well, it's not that getGreetingCard needs the #Produces annotation. The point is to enable other classes to recieve GreetingCards via Dependency Injection.
public class Foo {
#Inject // <--- will invoke #Producer method
GreetingCard foosGreetingCard
...
}
See here for more details:
A producer method is a method that acts as a source of bean instances.
The method declaration itself describes the bean and the container
invokes the method to obtain an instance of the bean when no instance
exists in the specified context.
In your case it doesn't need #Produces as you will be injecting factory bean and using its method directly to create instances, and not injecting the greetingCard beans themseleves.
#Inject
GreetingCardFactory factory;
...
GreetingCard card = factory.getGreetingCard();
If you would define it as #Produces method, and the try to inject GreetingCard, then you would get exception that I've described in the comment.
However, if you would additionally create qualifier, like this:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public #interface ProducedCard {}
and add it to the producer method:
#Produces #ProducedCard
public GreetingCard getGreetingCard() {
...
then you would be able to inject just GreetingCard beans using your producer method like this:
#Inject #ProducedCard
GreetingCard card;
since now there is no ambiguity, as there is only one place to create greeting cards marked with #ProducedCard :-)
I was trying to create an Aspectj pointcut on method annotation but I failed all the time with different approaches. I'm using aspectj autoproxy (I have no other weaving configured in my spring context). My classes look like this:
public interface Intf
{
#SomeAnnotation
void method1() throws SomeExc;
}
public class Impl implements Intf
{
#Override
public void method1() throws SomeExc
{
//...
}
}
#Aspect
public class MyAspect
{
#AfterThrowing(
pointcut = "execution(* *(..)) && #annotation(SomeAnnotation)",
throwing = "error")
public void afterThrowing(JoinPoint jp, Throwable error)
{
System.err.println(error.getMessage());
}
}
#Component
public class Usage
{
#Autowired
Intf intf;
public void doStuff()
{
intf.method1();
}
}
So I'm wondering why the aspectj won't create the pointcut. I managed to make it work using execution(* *(..) throws SomeExc) which does the job for me but I still want to know what I did wrong.
Also since method1 is defined in an interface and I specify the annotation on implementing class, is there a way to make it work this way? Other proxying mechanisms like transaction management/security works this way in other parts of spring right? And if I'm using interface proxying would specifying the pointcut on implementing class create the pointcut? (I guess not since I'm not using cglib)
try to add #Component to MyAspect class
#Component
#Aspect
public class MyAspect {
...
simply mark your aspect method with
#After("#annotation(package.SomeAnnotation)")
Have a look at this for a step by step guide
I have read carefully the article about Interceptors in the Seam/Weld documentation and implemented a InterceptorBinding:
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface MyLog {}
and a Interceptor class:
#MyLog #Interceptor
public class ErpLogInterceptor implements Serializable
{
#AroundInvoke
public Object logMethodEntry(InvocationContext invocationContext) throws Exception
{..}
#PostConstruct
public Object logPostConstruct(InvocationContext invocationContext) throws Exception
{...}
}
No I tried to activated the interceptor in the #Named #ViewScoped bean:
#javax.inject.Named;
#javax.faces.bean.ViewScoped
public class MyBean implements Serializable
{
#PostConstruct #MyLog
public void init()
{...}
#MyLog public void toggleButton()
{..}
}
If I push a button on my JSF page the method toggleButton is invoked correctly and the Interceptor method logMethodEntry is called. But it seems the method #PostConstruct (I am interested in) is never intercepted by my class.
The question seems to be related to Java EE Interceptors and #ViewScoped bean but actually my interceptor is working in normal methods.
You should set return type of #PostConstruct interceptor to void not Object.
Change:
#PostConstruct
public Object logPostConstruct(InvocationContext invocationContext) throws Exception
{...}
to:
#PostConstruct
public void logPostConstruct(InvocationContext invocationContext) throws Exception
{...}