Trigger a second advised method from a method already being advised in Spring - spring

I have a Class, call it X, in this class I have successfully advised a method call it method(){} from an Annotated Spring.
So, here it is:
public class X {
public void method(){...}
public void method2(){...}
}
Here is my aspect, shortened of course:
#Aspect
public class MyAspect{
#Pointcut("execution(* X.method(..))")
public void methodJP(){}
#Pointcut("execution(* X.method2(..))")
public void method2JP(){}
#Around("methodJP()")
public void doMethodJP(ProceedingJoinPoint pjp) throws Exception {
pjp.proceed(); //Amongst other things!!!
}
#After("method2JP()")
public void doMethod2JP(JoinPoint jp) throws Exception {
//Do some stuff here
}
}
Now... both join points work well, however, I within my X.method, I also call the method that is advised by method2JP()... and of course, my method2JP does not get triggered.
Is there any way I can get this to work?
Thanks.

Since Spring AOP works by proxying classes, for the advice to be invoked, you must call the method through the proxy or wrapper supplied by the bean factory.
If you don't want to break out into multiple classes, you can have the method retrieve a the proxied version of "itself" from the beanfactory. Something like this
#Service
public class MyService {
#Autowired
ApplicationContext context;
public void method1() {
context.getBean(MyService.class).method2();
}
public void method2() {
}
}
This will guarantee that the invocation of method2 from method1 will apply any aspects on the method2 pointcut.

methodJP() should be declared in another class. In the regular scenario the aspects are not triggered when you invoke a method from within the same object.

Related

Quarkus encapsulation behavior

I have this class:
#ApplicationScoped
public class BookService {
public boolean doorClosed;
public boolean isDoorClosed() {
return doorClosed;
}
}
And I have this test class:
#QuarkusTest
public class BookServiceTest {
#Inject BookService bookService;
#Test
public void testBookServiceDoor() throws InterruptedException {
bookService.doorClosed=true;
assertTrue(bookService.doorClosed);
assertTrue(bookService.isDoorClosed());
}
}
I am surprised that the last test assertion fails. The first passes but the last fails. It almost seems like that the getter/setters are using different variables than the one I am accessing directly.
I did the same test with Spring Boot and got the two assertions passing:
#Service
public class BookService {
public boolean doorClosed;
public boolean isDoorClosed() {
return doorClosed;
}
}
And the test:
#SpringBootTest
public class BookServiceTest {
#Autowired BookService bookService;
#Test
public void testBookServiceDoor() throws InterruptedException {
bookService.doorClosed=true;
assertTrue(bookService.doorClosed);
assertTrue(bookService.isDoorClosed());
}
}
Using the #ApplicationScoped annotation makes the class a normal scoped bean. This means that the container never injects an actual instance of the class; instead, you get a proxy that will lookup the correct instance on each method invocation.
This is most commonly useful for example with #RequestScoped beans, where you get a single proxy, which will dispatch method invocations to instances that belong to the "current request" (typically an HTTP request). However, there are good reasons why you might want this for application scoped beans as well (e.g. when you want lazy initialization).
The rule is: never access fields directly on normal scoped beans, only call methods.
If you want, you can make the class #Singleton. That is a pseudo scope, and you get no proxy, you get the actual instance that you can work with directly.

Spring rabbit: Intercept method calls annotated with #RabbitListener without AspectJ usage

Is there a way to intercept calls of bean methods annotated with #RabbitListener without using AspectJ.
The code is something like this
#OtherAnnotation
#RabbitListener
public void do(Message message)
I need to intercept all calls to #RabbitListener method, if the method has #OtherAnnotation annotation.
UPDATE:
I managed to make it work using Gary Russell solution.
public class CustomRabbitListenerAnnotationBeanPostProcessor extends RabbitListenerAnnotationBeanPostProcessor {
#Override
protected void processAmqpListener(RabbitListener rabbitListener, final Method method, Object bean, String beanName) {
if (method.isAnnotationPresent(OtherAnnotation.class)) {
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.addAdvisor(new StaticMethodMatcherPointcutAdvisor(new OtherAnnotationInterceptor()) {
#Override
public boolean matches(Method advisorMethod, Class<?> targetClass) {
return advisorMethod.equals(method);
}
});
Object proxiedBean = proxyFactory.getProxy();
super.processAmqpListener(rabbitListener, method, proxiedBean, beanName);
} else {
super.processAmqpListener(rabbitListener, method, bean, beanName);
}
}
}
The bean definition is like:
#Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
public CustomRabbitListenerAnnotationBeanPostProcessor customRabbitListenerAnnotationBeanPostProcessor() {
return new CustomRabbitListenerAnnotationBeanPostProcessor();
}
It's a bit ugly, but it works. If anyone has better solution, please share it.
You can subclass RabbitListenerAnnotationBeanPostProcessor and override the processListener method and modify the bean before invoking the super version.
Then, replace the RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME bean registered by the #EnableRabbit with your subclass.
Or, simply add your advice to the container factory's advice chain and all listeners will be advised. You can then do a runtime check to see if the other annotation is present.
i think what you are looking for is a bean-post-processor
heres a simple example:
https://www.tutorialspoint.com/spring/spring_bean_post_processors.htm
if you need to intercept calls you can wrap a proxy over the returned instance. a good example is the org.springframework.validation.beanvalidation.MethodValidationPostProcessor. you can probably extend org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor as well.
EDIT i am just learning this myself so i hope that is the right way to do this but this worked for me when experimenting with it
#Component
public class MyInterceptAnnotationBeanPostProcessor
extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
public void afterPropertiesSet() {
AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(
null,
MyIntercept.class);
this.advisor = new DefaultPointcutAdvisor(pointcut, this.createAdvice());
}
protected Advice createAdvice() {
return new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("advice");
return arg0.proceed();
}
};
}
}

register multiple resource instances of same type

I have a resource endpoint that injects a #PathParam into constructor, i.e., different instance per #PathParam value. It all works fine in Jetty. But now I'm trying to write unit tests using Jersey Test Framework, and it seems that the test framework only supports one registered endpoint per type.
So if I do something like this:
#Path("/users")
public class MyResource {
public MyResource(#PathParam("userId") int userId) {
}
#Path("{userId}")
public String get() {
}
}
public class MyTest extends JerseyTestNg.ContainerPerClassTest {
#Override
protected Application configure() {
return new ResourceConfig()
.register(new MyResource(1))
.register(new MyResource(2));
}
#Test
public void test2() {
target("/users/1").request().get();
}
#Test
public void test2() {
target("/users/2").request().get();
}
}
I see that both test1 and test2 are invoking the instance of MyResource(1). Is this expected? Is there a solution to invoke the correct instance?
You should register the resource as a class. Jersey will create it for you. And handle all the injections.
"The example I posted is dumbed down. In reality, my resource constructor has another injected object that I need to mock. So how would I specify a mocked object parameter for the constructor?"
You can do something like
#Mock
private Service service;
#Override
public ResourceConfig configure() {
MockitoAnnotations.initMocks(this);
return new ResourceConfig()
.register(MyResource.class)
.register(new AbstractBinder() {
#Override
protected configure() {
bind(service).to(Service.class);
}
});
}
#Test
public void test() {
when(service.getSomething()).thenReturn("Something");
// test
}
Assuming you are already using the built in HK2 DI, and have an #Inject annotation on the constructor of your resource class, this should work. In the AbstractBinder we are making the mock object injectable. So now Jersey can inject it into your resource.
See Also:
Jersey - How to mock service

Will invoking two methods on #Stateless use the same instance?

If I have something like this-
#Stateless
public class EJBServcie{
public void method1(){
// some code goes here
}
public void method2(){
// some code goes here
}
}
with the bean using it as-
public class Bean{
#EJB
EJBService ejbService;
punlic void action(){
ejbService.method1();
ejbService.method2();
}
}
In this example, method1 is invoked on an instance of EJBService. Will method2 be invoked on the same instance?
The EJB container might choose to use the same instance depending on pooling configuration or concurrent calls, but there is no guarantee: it could choose to use a different instance for each call.

Get AOP proxy from the object itself

Is possible to get the proxy of a given object in Spring? I need to call a function of a subclass. But, obviously, when I do a direct call, the aspects aren't applied. Here's an example:
public class Parent {
public doSomething() {
Parent proxyOfMe = Spring.getProxyOfMe(this); // (please)
Method method = this.class.getMethod("sayHello");
method.invoke(proxyOfMe);
}
}
public class Child extends Parent {
#Secured("president")
public void sayHello() {
System.out.println("Hello Mr. President");
}
}
I've found a way of achieving this. It works, but I think is not very elegant:
public class Parent implements BeanNameAware {
#Autowired private ApplicationContext applicationContext;
private String beanName; // Getter
public doSomething() {
Parent proxyOfMe = applicationContext.getBean(beanName, Parent.class);
Method method = this.class.getMethod("sayHello");
method.invoke(proxyOfMe);
}
}
This hack is extremely awkward, please consider refactoring your code or using AspectJ weaving. You may feel warned, here is the solution
AopContext.currentProxy()
JavaDoc. I blogged about it here and here.
AopContext.currentProxy() as suggested by Tomasz will work. A more generic solution, that will work outside of the proxied class is to cast the object to org.springframework.aop.framework.Advised and get .getTargetSource().getTarget()
The former (getting the real object from the proxied object) is something that you should not really need. On the other hand getting the target proxy might be useful in some utility class that inspects existing beans in order to add some feature.
You can use a bean post-processor to set a reference to the proxy on the target bean. It moves the Spring-specifics from your beans to a single class.
Post-Processor
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class SelfReferencingBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof SelfReferencingBean) {
((SelfReferencingBean) bean).setProxy(bean);
}
return bean;
}
}
Context
Register the post-processor in applicationContext.xml.
<bean id="srbpp" class="SelfReferencingBeanPostProcessor"/>
Beans
Each bean must implement SelfReferencingBean to tell the post-processor that it needs a reference to the proxy.
public interface SelfReferencingBean {
void setProxy(Object proxy) ;
}
Now implement setProxy in each bean that needs to call itself through its proxy.
public class MyBean implements SelfReferencingBean {
MyBean proxy;
#Override
public void setProxy(Object proxy) {
this.proxy = (MyBean) proxy;
}
}
You could put this last bit of code into a bean base class if you don't mind casting proxy to bean's type when calling methods directly on it. Since you're going through Method.invoke you wouldn't even need the cast.
With a little work I bet this could be converted to an annotation processor a la #Autowired. Come to think of it, I don't recall if I even tried adding a self-reference using #Autowired itself.
public class MyBean implements SelfReferencingBean {
#Autowired MyBean proxy;
}

Resources