#Around Aspect is Executing before #transaction Annotation Spring - java

I have one class with transaction Annotation:
#Service
#EnableTransactionManagement(order=2000)
public class UserManagementServiceImpl implements UserManagementService {
#Transactional
public User addUser(User user) throws AlreadyExistException {
// ...
}
}
I have one Aspect class:
#Component
#Aspect
public class PublisherAspect {
#Around("execution(* com.toi.expresso.service.UserManagementService.addUser(..))")
public User publishAddUserEvent(ProceedingJoinPoint jp) {
// ...
}
}
my #Around Annotation is getting executed before addUser save the data in Database. Please suggest me how #Around will execute after data save in database.

The interesting part of your aspect is the ..., i.e. the advice body. Assuming that your addUser method really returns a User and not void (which I would expect) or anything else, you can narrow down the pointcut to methods actually having a User return type so as to avoid problems with methods returning other types.
#Component
#Aspect
public class PublisherAspect {
#Around("execution(User com.toi.expresso.service.UserManagementService.addUser(..))")
public User publishAddUserEvent(ProceedingJoinPoint jp) {
// Do something before method execution
User user = jp.proceed();
// Do something after method execution
return user;
}
}
The more generic solution if you want to match all return types:
#Component
#Aspect
public class PublisherAspect {
#Around("execution(* com.toi.expresso.service.UserManagementService.addUser(..))")
public Object publishAddUserEvent(ProceedingJoinPoint jp) {
// Do something before method execution
Object result = jp.proceed();
// Do something after method execution
return result;
}
}

yes 'adduser' is returning User object. but just after holding user object if I am checking database for the same user its returning empty set.
#Component
#Aspect
public class PublisherAspect {
#Around("execution(User com.toi.expresso.service.UserManagementService.addUser(..))")
public User publishAddUserEvent(ProceedingJoinPoint jp)
{
// Do something before method execution
User user = jp.proceed();
//checking in database(Sending message to other application but that application didn't find user in same db)
return user;
}
}
}

Related

How to audit methods in Java Spring Boot

I am writing a Spring Boot Application. I want to audit methods with my annotation #AuditMetod: For example I have method foo() with the annotation:
#AuditMetod(name = "SomeValue")
foo() {...}
I want to handle and audit such methods like this (the simplest example):
auditMethod(Method method) {
if (method.hasAnnotation(AuditMethod.class)) {
System.out.println (method.getName() + " was called at " + new Date())
}
}
upd
Thanks to #Karthikeyan #Swapnil Khante and #misha2048 I understood, that I need to use AOP. But I have 2 problems:
The only method in Aspect class in not being called and I don't see the inscription "----------ASPECT METHOD IS CALLED-----------" in log
How can I check in aspect method what method it is intercepting. To get an instance of Method class.
Now I have the following code:
Controller:
#PostMapping
#LoggingRest(executor = "USER", method = "CREATE", model = "SUBSCRIPTION")
public ResponseEntity<?> create(#Valid #RequestBody SubscriptionRequestDto dto) {
...
}
Aspect:
`#Aspect
#Slf4j
#Component
public class AuditAspect {
#Pointcut(value = "#annotation(com.aspect.annotations.LoggingRest)")
public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) {
log.info("----------ASPECT METHOD IS CALLED------------");
}`
And annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface LoggingRest {
String executor() default "SYSTEM";
String method() default "";
String model() default "";
}
Auditing is a cross-cutting concern and can be handled using AOP.
Another solution would be to use a low-level solution by writing a custom annotation and using a Spring interceptorto write your business logic.
To use the Spring interceptor you will need to implement the HandlerInterceptor interface
Example of the annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Audit {
boolean active() default true;
}
Interceptor example
#Component
public class AuditInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Audit annotation = handlerMethod.getMethodAnnotation(Audit.class);
if (annotation != null && annotation.active()) {
// your business logic
}
}
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
check this interceptor example
I think one of the solutions here, as #Karthikeyan mentioned, is to use Spring AOP.
If you are not aware a brief introduction - spring-aop module implements the aspect oriented programming paradigm. We extract some common functionality, that we generally want to apply to some subset of functions/methods, to an entity called Aspect (see class annotated with #Aspect). This class will contain out cross-cutting functionality - such as auditing, for instance we want to audit the methods execution time, lets say. We just put the code to be executed, the condition, which tell the spring what exact beans methods should be affect by this aspect, see below.
For example, if I can audit the method execution duration with the following very simple example (in my case I said that any public method, returning void inside the Class com.example.stackoverflow.BusinessLogicClass must be inspected by this Aspect):
#SpringBootApplication
#EnableAspectJAutoProxy
public class StackoverflowApplication implements ApplicationRunner {
#Autowired
private BusinessLogicClass businessLogicClass;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
businessLogicClass.test();
}
}
#Aspect
#Component
class MyAspectLogicClass {
#Around("execution(public void com.example.stackoverflow.BusinessLogicClass.*(..))")
public Object hangAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long before = System.currentTimeMillis();
Object returnedValue = proceedingJoinPoint.proceed();
long after = System.currentTimeMillis();
System.out.printf("Retruned in '%s' ms %n", (after - before));
return returnedValue;
}
}
#Component
class BusinessLogicClass {
public void test() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
In my case, I will get the time before method execution, then by the means of
proceedingJoinPoint.proceed() call I delegate the execution to the real method, and then, once I get the response back, I will get the current system time and calculate the execution time, fairly simple.
I hope I have at least directed you somewhere, if you are looking for documentation, this are the resources I suggest you should look for:
https://docs.spring.io/spring-framework/docs/2.5.x/reference/aop.html offical spring doc (stale a bit, but there are some valuable things to learn)
https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html is more fresh doc
Hope it helped :)
The problem was in right annotation. In Aspect class I tried #Around and everything works as I need.
#Aspect
#Slf4j
#Component
public class AuditAspect {
#Around(value = "#annotation(com.aspect.annotations.LoggingRest)")
public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) {
var method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
log.info("----------ASPECT METHOD IS CALLED------------");
}
}
For getting a Method instance I use fallowing code
Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();

AOP and annotation 'inheritance'

let's consider the following situation.
#interface LoggedMethodInvocation{}
#LoggedMethodInvocation
#interface MonitoredMethodInvocation{}
I would like the #MonitoredMethodInvocation annotation implying the #LoggedMethodInvocation annotation.
class LoggingAOPConfig {
#Pointcut("#annotation(LoggedMethodInvocation)")
public void servicePointcut() {
}
#Around("servicePointcut()")
public Object logMethodInvocation(ProceedingJoinPoint pjp) throws Throwable {
// log the method invocation...
}
}
class MonitoringAOPConfig {
#Pointcut("#annotation(MonitoredMethodInvocation)")
public void servicePointcut() {
}
#Around("servicePointcut()")
public Object monitorResponseTime(ProceedingJoinPoint pjp) throws Throwable {
// add some meters to the method invocation
}
}
Now I would like to introduce some method, which shall be both monitored and logged. And I would like to annotate the method only with one annotation, namely #MonitoredMethodInvocation.
class SomeService {
#MonitoredMethodInvocation
Object someMethod(Object requestPayload) {
// ...
return responsePayload;
}
}
However it doesn't play, the logging aspect is not taken into the account.
There is spring's AnnotationUtils.findAnnotation which offers the needed functionality (of recognizing, whether the #LoggedMethodInvocation shall be considered). However, I don't know how to put this into the pointcut configuration.
How shall I modify the logging AOP config so it will recognize the logging annotation even if it is hidden behind the #MonitoredMethodInvocation?

Spring Boot. #Transactional method calling a #Transactional(readonly=true) method

I have the next problem. When a controller invokes a service method with #Transactional annotation and this method invokes a #Transactional(readonly=true) method, the changes in the object doesn't get saved in the database. I don't know why. I thought that the first method begins a 'read and write' transaction and the second method uses the same transaction.
Example :
/** Controller class **/
#RestController
#RequestMapping("/path1")
public class MyObjectRestController {
...
#Autowired
MyObjectService myObjectService;
#PostMapping(value = "/path2")
#ResponseStatus(HttpStatus.CREATED)
public void save(#RequestBody MyObject myObject) {
myObjectService.save(myObject);
}
...
}
/** Service class **/
public interface MyObjectService {
public MyObject save(MyObject myObject);
public MyObject findOne(long id);
}
/** Service implementation class **/
#Service
public class MyObjectServiceImpl implements MyObjectService {
/**
* Save Object
*/
#Override
#Transactional
public Object save(Object newObject) {
Object myObject = this.findOne(newObject.getId());
// Modify Object
myObject.setAttribute1(...)
myObject.setAttribute2(...)
// Save Object (using Repository)
return MyObjectDao.save(myObject);
}
/**
* Get Object by Id
*/
#Override
#Transactional(readOnly = true)
public MyObject findOne(long id) {
Optional<MyObject> myObject = MyObjectDao.findById(id);
return myObject.isPresent() ? myObject.get() : null;
}
}
This example doesn't update the object attributes. But if I remove the #Transactional annotation in save(..) method ... this example works successfully! (the object is modified).
Why is this happening?
I see save method is annotated with #Transactional and calls findOne method which is also #Transactional. So in this case the same transaction is getting propagated to findOne method and it applies readonly behaviour to the current transaction. And thus it does not perform Flush and you see entity is not modified.
So in this case, you should use a separate transaction for read and writes.
findOne method can be annotated with below -
#Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)

Intercept the instance of an object from RestController or Hibernate in Spring before it's returned to the client

I'm developing a translation service that currently works inside another Service. For example:
public Profile getById(int chainId, int profileId, Integer languageId) {
Profile profile = profileRepository.getById(chainId, profileId);
translationService.translate(profile, languageId); // Here
return profile;
}
Now, to avoid to use a translate method on every service method of all the application, and as I only have the language of a user from the controller, I would like to execute the translate method before every Profile (and any other object) is returned to the client.
I tried to implement HandlerInterceptor in a custom interceptor, but it seems it doesn't returns the instance of the object that I'm returning. Anyone could help?
Another way to do it could be to translate every object that came from a select in Hibernate, but I also don't find any good solution to it this way...
The solution was to use Spring AOP. Probably the question wasn't very well explained, but what we needed was a way to intercept the object a user was asking to the backend, because they are able to create their own translations and we save them in the database. We had to return the model with the correct translation for each user, who has their localization in their profile. Here's the way we intercept it:
#Component
#Aspect
public class TranslatorInterceptor extends AccessApiController {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
public TranslationService translationService;
#Pointcut("execution(* com.company.project.api.controller.*.get*(..))")
public void petitionsStartWithGet() { }
#Pointcut("execution(* com.company.project.api.controller.*.list*(..))")
public void petitionsStartWithList() { }
#Pointcut("execution(* com.company.project.api.controller.*.find*(..))")
public void petitionsStartWithFind() { }
#AfterReturning(pointcut = "petitionsStartWithGet() || petitionsStartWithList() || petitionsStartWithFind()", returning = "result")
public void getNameAdvice(JoinPoint joinPoint, Object result){
translationService.translate(result, getCustomUserDetails().getLanguageId());
logger.debug("Translating " + result.getClass().toString());
}
}
What we do here is to "watch" all the methods in the package "controller" that start by 'get', 'list' or 'find' (getById(), for example) and through this advice, we intercept the object before is sent to Jackson. The method getCustomUserDetails comes from AccessApiController, which is a class we did to provide our Controllers with some information we need.

Using generic types as return type for a pointcut

I'm using Spring Boot to set up a REST API. I'll be making a bunch of #RestControllers and want to set a pointcut on those methods that return a subtype of a specific abstract class I call Model. These controllers look something like this:
#RestController
public class UserController {
#RequestMapping(...)
public Person getAllPeople() {
...
}
}
Where my Person class would look something like this:
public class Person extends Model {
...
}
So would it be possible to write advice that looks something like this:
#Aspect
#Component
public class ModelAspect {
#AfterReturning(
value = "execution(<T extends mypackages.Model> T mypackages.api.*.*(..))",
returning = "model")
public void doSomethingWithModel(Model model) {
...
}
}
Of course that won't work because the advice is not valid syntactically. In the reference documentation, I have only found information about generic parameters, not return types (Spring AOP reference). What I have now is this, but I think something like the example above would be a lot more efficient:
#Aspect
#Component
public class ModelAspect {
#AfterReturning(
value = "execution(* mypackages.api.*.*(..))",
returning = "model")
public void doSomething(Object model) {
if (model instanceof Model)
doSomethingWithModel((Model) model);
}
}
My next question would be, is the same possible for those methods that return a Collection of suptypes of Model? Because the reference states that parameter types cannot be generic Collections.
Have you tried using + after your interface?
#Aspect
#Component
public class ModelAspect {
#AfterReturning(
value = "execution(mypackages.Model+ mypackages.api.*.*(..))",
returning = "model")
public void doSomethingWithModel(Model model) {
...
}
}
You could try do not specify the return type. Based on the documentation it will be resolved by the type of the parameter used at the returning clause:
A returning clause also restricts matching to only those method
executions that return a value of the specified type ( Object in this
case, which will match any return value).
#Aspect
#Component
public class ModelAspect {
#AfterReturning(
value = "execution(* mypackages.api.*.*(..))",
returning = "model")
public void doSomethingWithModel(Model model) {
...
}
}
Have a look to the below link. It answers also your second question, about generic collections.
Aspectj Matching Return Type
Just for curiosity I have created a project for testing this and it started working for me straight forward. I can only think the path your pointcut is pointing to is wrong. Try with:
#Aspect
#Component
public class ModelAspect {
#AfterReturning(
value = "execution(* mypackages.api..*(..))",
returning = "model")
public void doSomethingWithModel(Model model) {
...
}
}
You can have a look to my project at: spring-aspectj-interfaces
There you will see different values for the pointcut (only one not commented, of course), all of them valid.

Categories