I am trying to intercept spring's class using my implemented aspect.
My aspect looks like below:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class BatchExceptionInterceptor {
#Around("execution(* org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(..))")
public Object serviceMethodIntercept(ProceedingJoinPoint pjp)
throws Throwable {
System.out.println("I am here..");
return pjp.proceed();
}
}
Also, I have used below tag in my Springs context file:
<tx:annotation-driven proxy-target-class="true"/>
I am able to intercept my own classes this way. But not sure why SQLErrorCodeSQLExceptionTranslator.doTranslate() is not being intercepted even program controller goes through this method. My aspect is being initialized properly. Any idea?
Related
I followed the rest client guide in Quarkus web site. It works fine. But when registering a global provider using the ServiceLoader pattern, as described in the specification, the CDI beans injection did not work, they are all null. I downloaded the example and simply added the following classes:
package org.acme.rest.client;
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.core.Response;
#ApplicationScoped
public class MyExceptionMapper implements ResponseExceptionMapper<Exception> {
#Override
public Exception toThrowable (Response response) {
return new Exception();
}
}
package org.acme.rest.client;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.eclipse.microprofile.rest.client.spi.RestClientBuilderListener;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
#ApplicationScoped
public class MyListener implements RestClientBuilderListener {
#Inject MyExceptionMapper myExceptionMapper;
#Override
public void onNewBuilder (RestClientBuilder builder) {
builder.register(myExceptionMapper);
}
}
I also added the file META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientBuilderListener with the content org.acme.rest.client.MyListener. The MyListener onNewBuilder method is invoked, but the injected provider MyExceptionMapper is null. How to register a global provider in Quarkus client?
Implementation of RestClientBuilderListener are not CDI beans - they are just objects that are created via the normal Java ServiceLoader mechanism when RestClientBuilder is being used.
So if you want to obtain CDI beans when onNewBuilder is called, you can do something like:
CDI.current().select(MyExceptionMapper.class).get()
Furthermore, you need to annotate MyExceptionMapper with #Provider, not #ApplicationScoped.
I am writing an aspect which will send email on save/update/delete operations with old and updated data as the email information. I am using JpaRepository provided by the spring-boot-starter-data-jpa dependency.
I am using #Transactional on these operations! I want that the aspect i have written for email should be called after the transaction is committed. But its not working that way. Aspect is also executed within the transaction boundary.
Below is the aspect.
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class EmailAspect {
private EmailSender emailSender;
public EmailAspect( EmailSender emailSender) {
this.emailSender = emailSender;
}
#Around("execution(* com.company.app.service.*Repository.save*(..))")
public void sendEmail(ProceedingJoinPoint joinPoint) throws Throwable {
Object myCustomObject= joinPoint.proceed();
emailSender.send("Testing from app - Subject","Testing from app - Body", "test#test.com");
}
}
I'm using AspectJ and AOP in a Spring-boot project in order create an external library to log some activities.
Although I have configured this pointcut:
#Pointcut("call(void org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(Message,Channel))")
private void getEventOnMessage(){}
the aspect
#Before(value="getEventOnMessage()")
public void getEventOnMessage(JoinPoint joinPoint){
System.out.println("VOILA'");
}
is not triggered.
Details:
package com.tim.sdp.timLogging.Aspects.handler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages="org.springframework.amqp.rabbit.listener.adapter")
public class AppConfig {
#Bean()
public AspectForOnMessage myAspect() {
return new AspectForOnMessage();
}
}
Aspect class implementation:
package com.tim.sdp.timLogging.Aspects.handler;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class AspectForOnMessage {
#Pointcut("call(void org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(Message,Channel))")
private void getEventOnMessage(){}
#Before(value="getEventOnMessage()")
public void getEventOnMessage(JoinPoint joinPoint){
System.out.println("VOILA'");
}
}
Might you help me, please? It's the only event I can not capture.
In this forum you can find another person with the same problem:
Spring forum link
Thank you in advance.
Oh, a classical one!
As documented here, call() is not supported in proxy-based Spring AOP which you have configured in your application via #EnableAspectJAutoProxy. You need to switch from "AOP lite" to the full power of AspectJ as described there or stick with pointcuts really supported in Spring AOP.
I am getting following error in my weblogic console when i am starting my server.
SEVERE: Missing dependency for constructor
public com.test.mine.exception.JsonExceptionMapper(java.lang.String,com.fasterxml.jackson.core.JsonLocation) at parameter index 0
SEVERE: Missing dependency for constructor public com.test.mine.exception.JsonExceptionMapper(java.lang.String,com.fasterxml.jackson.core.JsonLocation) at parameter index 1
Below is my java code.
package com.test.mine.exception;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;
#Provider
#Service
public class JsonExceptionMapper extends JsonParseException implements ExceptionMapper {
public JsonExceptionMapper(String msg, JsonLocation loc) {
super(msg, loc);
// TODO Auto-generated constructor stub
}
private static final Logger LOGGER = LoggerFactory.getLogger(JsonExceptionMapper.class);
protected Logger getLogger() {
return LOGGER;
}
public Status getStatus(JsonParseException thr) {
return Status.BAD_REQUEST;
}
#Override
public Response toResponse(Throwable arg0) {
// TODO Auto-generated method stub
return Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).build();
}
}
The annotation #Service tells spring to create a singleton of the annotated class. At startup spring tries to create that instance and to provide the required constructor args String msg, JsonLocation loc which it does not find, so the exception.
JsonExceptionMapper does not look like a service, and it should not be a singleton. Instead it must be created whenever an exception is created.
I have never worked with that class, so sorry, cannot give you any advice on how to do that.
I bumped into a similar problem while configuring swagger to work with Jersey. After searching various forums found that Jersey scanning require a constructor without parameters. I added a a constructor and it worked for me.
I have a service implementation carrying a class-wide #Transactional annotation. I also have an aspect that uses the #Around advice to retry failed transactions. I'm now trying (for type-safety reasons) to make the pointcut definition annotation based:
#Around("#annotation(TransactionRetryable)")
TransactionRetryable.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface TransactionRetryable {
}
Service layer:
#Transactional
public class ... {
#Override
#TransactionRetryable
public String forceError() {
throw new RuntimeException(someNastyMessage);
}
In that form, it only applies to method, not whole classes. However, the #Transactional annotation propagates from class level to each method. Is there a way to avoid putting the #TransactionRetryable annotation above each method and simply once above the class like the #Transactional annotation? Desired form:
#Transactional
#TransactionRetryable
public class ... {
#Override
public String forceError() {
throw new RuntimeException(someNastyMessage);
}
This pointcut would advise all public methods of a class annotated with #TransactionRetryable:
#Around("execution(public * *(..)) && within(#your.package.TransactionRetryable *)")