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();
I write a class in Java and Spring Boot. It is a service, and in the service, it calls other libraries. The problem is when I call the libraries, it will log some errors, these erros actually didn't affect the execution of the service.
So I am wondering, can I suppress the errors in the class?
The service class looks like below.
#Service
public class serviceImpl implements service {
#Override
public String executeComputation(String rawData, String computationName)
throws BrokerException, IOException {
//call some libs
}
}
The error looks like this:
Unexpected exception during (something) evaluation. Details: Cannot invoke method collectEntries() on null object. Source Code: import java.text.DateFormat;
Write an aspect for it. An example of aspect:
#Aspect
public class MyAspect {
#Around("thePointcutExpression")
public Object executeComputationAspect(ProceedingJoinPoint pjp) throws Throwable {
Object ob;
try {
ob = pjp.proceed();
} catch(Exception e) {} // swallow the exception
return ob;
}
}
How catch NoEndpointFoundException in Spring WS?
By default MessageDispatcher.dispath() throws NoEndpointFoundException in case of absence appropriate Endpoint but then WebServiceMessageReceiverObjectSupport.handleConnection() just hides the exception. In my point I should catch it by myself.
Is it good idea to add custom EndpointMapping via MessageDispatcher.getEndpointMappings().add() and throws exception in that?
I find out following solution:
#Component
#Order(Ordered.LOWEST_PRECEDENCE)
public class NoEndpointFoundEndpointMapping implements EndpointMapping {
#Override
public EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception {
throw new MyCustomException(...);
}
}
I want my ExceptionMapper to catch all exceptions and log them... I'm using Jersey 2.0 right now.
I have an exception mapper like so:
#Provider
public class RestExceptionMapper implements ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
log(e);
if (e instanceof WebApplicationException) {
return ((WebApplicationException) e).getResponse();
} else {
return buildResponse(e);
}
This exception mapper only gets called for non-WebApplication application exceptions.
How do I make one global exception mapper catch all the exceptions so I can log them. Is there another way I should approach this?
Thanks
Judging from the source code of Jersey where this is handled there is no way to do this with an ExceptionMapper. WebApplicationExceptions get a special treatment are never mapped.
A way to log all exceptions is to set the logger org.glassfish.jersey.server.ServerRuntime to FINER.
Description
I have a unit test for which I do not want the AOP to be loaded. I don't load the AOP in any of the unit test code. The classes which are not mocked do not have any AOP/beans/components autowired and or used.
On running the unit test the code is suppose to throw a custom exception called FrameworkException.
However the AOP catches the exception and runs the AfterThrowing Advice. I don't want this in the unit test.
Can anyone help?
The Problem
Why is the ExceptionAspect afterThrowing() advice still being called? It was not called previously.
Suspicions
Does mock code still instantiate with any existing functionality?
Attempted resolutions
- I have tried loading an AnnotationConfigApplicationContext which loads an empty configuration class. This did not seem to work.
Code Example - Unit Test
#Test
public void processRequest_WithRequestParameterNull_ExceptionExpected()
{
try
{
RequestWrapper requestMock = Mockito.mock(RequestWrapper.class);
Auditor auditorMock = Mockito.mock(Auditor.class);
CoreWrapper coreMock = Mockito.mock(CoreWrapper.class);
RequestAssessmentStatusHandler handler = new RequestAssessmentStatusHandler(requestMock, auditorMock,
coreMock);
handler.processRequest(null);
fail("processRequest_WithRequestParameterNull_ExceptionExpected failed.");
}
catch (FrameworkException e)
{
assertEquals(EventIds.INVALID_FRAMEWORK_PARAMETER, e.getEventId());
}
catch (Exception e)
{
fail("processRequest_WithRequestParameterNull_ExceptionExpected unhandled exception: "
+ e.getStackTrace().toString());
}
}
Code Example - AfterThrowing Advice
#Component
#Aspect
public class ExceptionAspect
{
#AfterThrowing(pointcut = "execution(* *(..))", throwing = "exception")
public void afterThrowing(JoinPoint joinPoint, Exception exception) throws Exception
{
// Do things here.
}
}
You could add #Profile("!test") to your aspect component and then add #ActiveProfiles("test") annotation to your test.