I would like to use initialization with aspectj.
#Aspect
public class TotoAspect
{
#Before("initialization( *.new(..))")
public void test(JoinPoint thisJoinPoint) throws AuditReactiveException
{
System.err.println("I AM HERE");
}
}
But, the message was not print with
new ABC();
I use the java agent for aspectj.
Where is the mistake ?
Well, actually on your console you should see something like this:
Exception in thread "main" org.aspectj.lang.NoAspectBoundException: Exception while initializing de.scrum_master.aspect.TotoAspect: org.aspectj.lang.NoAspectBoundException: de.scrum_master.aspect.TotoAspect
at de.scrum_master.aspect.TotoAspect.aspectOf(TotoAspect.java:1)
at de.scrum_master.app.ABC.<init>(ABC.java:4)
at de.scrum_master.app.ABC.main(ABC.java:10)
Caused by: org.aspectj.lang.NoAspectBoundException: de.scrum_master.aspect.TotoAspect
at de.scrum_master.aspect.TotoAspect.aspectOf(TotoAspect.java:1)
at de.scrum_master.aspect.TotoAspect.<init>(TotoAspect.java:10)
at de.scrum_master.aspect.TotoAspect.ajc$postClinit(TotoAspect.java:1)
at de.scrum_master.aspect.TotoAspect.<clinit>(TotoAspect.java:1)
... 2 more
This is because your advice is targetting all constructors, even its own aspect's one. You need to exclude it. Here is a compileable code sample:
Exception class:
This is to demonstrate that your pointcut also matches the exception's constructor.
package de.scrum_master.app;
public class AuditReactiveException extends Exception {
public AuditReactiveException(String message) {
super(message);
}
}
Sample driver class with main method:
package de.scrum_master.app;
public class ABC {
public ABC() throws AuditReactiveException {
System.err.println("Creating ABC object");
throw new AuditReactiveException("Something went wrong");
}
public static void main(String[] args) throws AuditReactiveException {
new ABC();
}
}
Aspect with modified pointcut:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import de.scrum_master.app.AuditReactiveException;
#Aspect
public class TotoAspect {
#Before("initialization(*.new(..)) && !within(TotoAspect)")
public void test(JoinPoint thisJoinPoint) throws AuditReactiveException {
System.err.println(thisJoinPoint);
}
}
Sample output:
initialization(de.scrum_master.app.ABC())
Creating ABC object
initialization(de.scrum_master.app.AuditReactiveException(String))
Exception in thread "main" de.scrum_master.app.AuditReactiveException: Something went wrong
at de.scrum_master.app.ABC.<init>(ABC.java:6)
at de.scrum_master.app.ABC.main(ABC.java:10)
You might also want to exclude the exception constructor, i.e. you should narrow down the pointcut's scope with package and/or class names. Check out the AspectJ documentation for pointcut syntax description, e.g. how to use jokers like * or ...
Related
Is there a way to set a ExceptionHandler for a Class and Exceptionclass?
I have a class like this:
public class MyServiceClass {
public void foo() {
//some Code...
throw new MyCustomRuntimeException();
//some more Code...
}
public void foo2() {
//some other Code...
throw new MyCustomRuntimeException();
//more other Code...
}
}
Now I would like to define a MyCustomRuntimeException - Handler something like this:
private void exceptionHandler(MyCustomRuntimeException ex) {
//some Magic
}
Which should be used everytime a MyCustomRuntimeException is thrown in this class. I know I could use try, catch, finally in each method, but is there a Class wide solution? Would like to skip the boilerplate
try {
...
} catch (MyCustomRuntimeException ex) {
exceptionHandler(ex);
}
Iam using Spring in this application (no Spring Boot), but I found nothing how to use #ExceptionHandler for plain Spring. I tried the following (doesn`t work):
EasyApplication
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class EasyApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
FooBar foo = context.getBean(FooBar.class);
foo.doException();
}
}
FooBar
import org.springframework.web.bind.annotation.ExceptionHandler;
public class FooBar {
public void doException() {
throw new RuntimeException();
}
#ExceptionHandler(value = RuntimeException.class)
public void conflict() {
System.out.println("Exception handled!");
}
}
MyConfiguration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyConfiguration {
#Bean(name = "FooBar")
public FooBar fooBar() {
return new FooBar();
}
}
If you are not using spring-mvc and not in a multi-threaded environment, you would be able to do well with the following.
public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("This is from the uncaught");
}
}
And then add this line in your main method. This works for small applications, and spring has minimal role here.
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
If you have a bigger application and needs a more elegant solution - look to introduce aspects (AOP) in to your app.
Edited June 2nd 2020
This is when spring-mvc is used
You can use #ExceptionHandler for this. Spring Tutorial
#ExceptionHandler can handle both class specific and global handlers (via #ControllerAdvice)
The class specific handlers is triggered before global handlers. So best practice is to use RuntimeException and Exception in global handlers, instead of using them in individual classes. Reduces boilerplate further.
I am working on a project that is basically a lot of processes that run periodically. Each process is a different class that extends an abstract class RunnableProcess we created, which contains a private attribute Map<String, String> result and the abstract method run with the signature below:
public abstract void run(Map processContext) throws IOException;
To improve modularization on the project, I'm starting to use Aspect Oriented Programming (AOP) to intercept the run calls from every RunnableProcess. I am still learning AOP, and I have the following code until now:
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
import process.RunnableProcess;
import java.util.Map;
public aspect ProcessRunInterceptor {
private Logger logger;
pointcut runProcess() : call(void RunnableProcess.run(Map));
after(): runProcess() {
logger = getLogger(thisJoinPoint.getClass());
logger.info("process run successfully");
}
}
It is working, but I want to log more information than just "process run successfully". I have this information inside the intercepted class, in the result attribute mentioned above. Is it possible to access it in the advice without changing the implementation of RunnableProcess?
I can (prefer not to, but if it would be the only choice...) change the attribute from private to protected, but I wouldn't change it to public. I also would not like to create a get method for it.
Building upon my answer to your other question, I will explain to you what you can do. A few hints:
Instead of before() and after() you could just use around().
You should not use a private member for the process instance in a singleton aspect because if you have asynchronous processes in multiple threads, the member could be overwritten. Thus, your approach is not thread-safe and you should use a local variable instead.
You should not print "process run successfully" in an after() advice because after() also runs after an exception. So you cannot safely assume that the process ran successfully, only that it ran at all. You should rather write "finished process" or similar. BTW, if you want to differentiate between successful processes and such ending with an exception, you might want to look into pointcut types after() returning and after() throwing().
It does not make sense to use an abstract base class and not define the member result there directly. Why add it as a private member in each subclass if you can have it as a protected member in the parent? We are still doing OOP here (beside AOP, of course), right? The advantage is that you can access the member directly from the aspect using the base class like you already do in your pointcut.
Here is an MCVE for you:
Process classes:
package de.scrum_master.app;
import java.io.IOException;
import java.util.Map;
public abstract class RunnableProcess {
protected String result = "foo";
public abstract void run(Map processContext) throws IOException;
}
package de.scrum_master.app;
import java.io.IOException;
import java.util.Map;
public class FirstRunnableProcess extends RunnableProcess {
#Override
public void run(Map processContext) throws IOException {
System.out.println("I am #1");
result = "first";
}
}
package de.scrum_master.app;
import java.io.IOException;
import java.util.Map;
public class SecondRunnableProcess extends RunnableProcess {
#Override
public void run(Map processContext) throws IOException {
System.out.println("I am #2");
result = "second";
}
}
Driver application:
package de.scrum_master.app;
import java.io.IOException;
public class Application {
public static void main(String[] args) throws IOException {
new FirstRunnableProcess().run(null);
new SecondRunnableProcess().run(null);
}
}
Aspect:
Here you just bind the target() object to a parameter in the pointcut and use it in both advices.
package de.scrum_master.aspect;
import static org.slf4j.LoggerFactory.getLogger;
import org.slf4j.Logger;
import de.scrum_master.app.RunnableProcess;
import java.util.Map;
public privileged aspect ProcessRunInterceptorProtocol {
pointcut runProcess(RunnableProcess process) :
call(void RunnableProcess.run(Map)) && target(process);
before(RunnableProcess process): runProcess(process) {
Logger logger = getLogger(process.getClass());
logger.info("logger = " + logger);
logger.info("running process = " + thisJoinPoint);
}
after(RunnableProcess process): runProcess(process) {
Logger logger = getLogger(process.getClass());
logger.info("finished process = " + thisJoinPoint);
logger.info("result = " + process.result);
}
}
Console log with JDK logging (some noise removed):
INFORMATION: logger = org.slf4j.impl.JDK14LoggerAdapter(de.scrum_master.app.FirstRunnableProcess)
INFORMATION: running process = call(void de.scrum_master.app.FirstRunnableProcess.run(Map))
I am #1
INFORMATION: finished process = call(void de.scrum_master.app.FirstRunnableProcess.run(Map))
INFORMATION: result = first
INFORMATION: logger = org.slf4j.impl.JDK14LoggerAdapter(de.scrum_master.app.SecondRunnableProcess)
INFORMATION: running process = call(void de.scrum_master.app.SecondRunnableProcess.run(Map))
I am #2
INFORMATION: finished process = call(void de.scrum_master.app.SecondRunnableProcess.run(Map))
INFORMATION: result = second
All the classes in project are in com.aspect package.
The main Aspect :
#Aspect
public class MainAspect {
#Pointcut("within(com.aspect..*)")
public void standaloneLayer(){}
}
Another aspect for joinpoints having account object as argument:
#Aspect
public class AccountAspect {
#After("com.aspect.MainAspect.standaloneLayer() && args(account)")
public void pointCutForAccount(JoinPoint joinPoint, Account account){
}
}
Service layer class:
#Service
public class Customer {
public void setAccountBalance(Account account) {}
}
While running application I am getting below exception:
Caused by:
java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:317)
Crosscheck your code once more whether you have imported org.aopalliance.intercept.Joinpoint instead of org.aspectj.lang.JoinPoint
Note for AspectJ AOP you need to import org.aspectj.lang.JoinPoint.
In my case the reason was that I imported the wrong class. Make sure that the class you import is org.aspectj.lang.JoinPoint and not any thing else.
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class LoggingAspect {
#Before("allCircleMethods()")
public void LogginAdvice(JoinPoint joinpoint)
{
System.out.println("advice is run");
System.out.println(joinpoint.toString());
}
#Before("args(String)")
public void StringArguementMethods()
{
System.out.println("A method that takes String arguement has been called");
}
#Pointcut("execution(* get*())")
public void allgetters()
{}
#Pointcut("within(as.model.Circle)")
public void allCircleMethods()
{}
}
when i imported import org.aopalliance.intercept.Joinpoint; i got 0 ubound in poincut error , so i changed the import to org.aspect.lang.JoinPoint and my program ran successfully
I have tried many combinations but I am unable to invoke callback before execution of following method
#SomeAnnotation(...)
#Override
public void someMethod(Serializable id) {
}
I have tried many combinations similar to
#Before("execution(#com.full.name.of.SomeAnnotation * com.full.name.of.Class.someMethod(java.io.Serializable))")
public void beforeMethod() {
System.out.println("I am here.");
}
If I write a more generic expession, it hits the beforeMethod but I am unable to target a single specific method. What am I missing here?
Okay guys, let me prove that the pointcut actually works as written by the original poster Haris Hasan.
Sample annotation:
package com.full.name.of;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface SomeAnnotation {
int id();
String name();
}
Sample class using the annotation:
package com.full.name.of;
import java.io.Serializable;
public class Class {
#SomeAnnotation(id = 1, name = "John Doe")
public void someMethod(Serializable s) {}
public static void main(String[] args) {
new Class().someMethod("x");
}
}
Sample aspect with Haris Hasan's exact pointcut:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class SampleAspect {
#Before("execution(#com.full.name.of.SomeAnnotation * com.full.name.of.Class.someMethod(java.io.Serializable))")
public void yetAnotherPointcut(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Console output:
execution(void com.full.name.of.Class.someMethod(Serializable))
Copy and paste everything exactly as is, then run it. Quod erat demonstrandum.
The expression below should work:
#Before("com.full.name.of.Class.someMethod(..) && args(java.io.Serializable)")
Correction by kriegaex:
#Before("execution(* com.full.name.of.Class.someMethod(*)) && args(java.io.Serializable)")
A few points worth considering: Is the method being advised public? Are you using cglib proxies or jdk proxies? Does your class implement any interface and is the method being advised declared in the interface contract?
Also do take a look at what spring doc has to say about writing good pointcuts
Hope this helps.
Why do you not just use
#Before("execution(* com.full.name.of.Class.someMethod(java.io.Serializable))")
That specifically targets the method you want, you do not need to put the annotation to specify the target
First of all, please know that I've searched SO before asking this question, but I was unable to find a satisfying answer.
I'm using JUnit4 and Powermock 1.5.5 (with mockito 1.9.5)
My problem is the following : in my unit tests, I need to mock a static method in a class I can't modify. I only want to mock one method, and not the whole class, so I went for a spy.
Here's what I have so far :
[...]
import static org.mockito.Matchers.*;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(JUnitParamsRunner.class)
#ContextConfiguration(locations={"classpath:applicationContext-test.xml"},
loader=MockWebApplicationContextLoader.class)
#MockWebApplication(name="my-app")
#PrepareForTest(value = {
Role.class
})
public class MyTest {
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#Before
public void setUp() throws Exception {
initSpring();
mockRoleServices();
}
private void mockRoleServices() throws Exception {
spy(Role.class);
RoleAnswer roleAnswer = new RoleAnswer(RoleEnum.ADMIN);
when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
.then(roleAnswer);
}
private class RoleAnswer implements Answer<Boolean> {
private RoleEnum roleEnum;
private RoleAnswer(RoleEnum roleEnum) {
this.roleEnum = roleEnum;
}
#Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return getRenderRequest().getUserRole() != null &&
getRenderRequest().getUserRole().equals(roleEnum);
}
}
}
Here's the problem : the method Role.hasAdministratorRole() is called instead of being mocked
Here's what I tried so far :
Using mockStatic(Role.class) instead of the spy() method. As expected, all methods are mocked, so I end up getting an NPE before Role.hasAdministratorRole() is called
Doing something like doAnswer(...).when(...). I get a runtime error with powermock telling me my mock is not complete (which actually confirms that something's wrong either with my code or with the lib itself)
Trying to declare the method by its name rather than calling it directly : when(Role.class, "hasAdministratorRole", long.class, long.class, long.class). Same behavior
A bunch of other things I don't recall anymore.
Your help will be greatly appreciated.
Thanks !
EDIT : Thanks to SrikanthLingala's answer, I was able to pinpoint the problem.
This didn't work :
when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
.thenAnswer(roleAnswer);
but this did :
doAnswer(roleAnswer).when(Role.class, "hasSiteAdministratorRole",
anyLong(), anyLong(), anyLong());
So switching then when() and the answer() worked
As I do not have all of your implementations, I setup some dummy implementations and made a similar setup like yours. The below code works fine for me.
import static junit.framework.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = {
Role.class
})
public class RoleTest {
#Test
public void mockRoleServices() throws Exception {
PowerMockito.spy(Role.class);
PowerMockito.doAnswer(new RoleAnswer(RoleEnum.ADMIN)).when(Role.class, "hasAdministratorRole", Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());
Role.printOut();
assertTrue(Role.hasAdministratorRole(1, 1, 1));
}
private class RoleAnswer implements Answer<Boolean> {
private RoleEnum roleEnum;
private RoleAnswer(RoleEnum roleEnum) {
this.roleEnum = roleEnum;
}
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return true;
}
}
}
Dummy Role class:
public class Role {
public static Boolean hasAdministratorRole(long a, long b, long c) {
System.out.println("Inside hasAdministratorRole");
return a + b + c < 0;
}
public static void printOut() {
System.out.println("Inside Printout");
}
}
My test case does not printout Inside hasAdministratorRole, but prints out Inside Printout
Hope this helps
Glad you have solved your issue, this just a warning for everyone else having a similar issue.
Project setup:
Powermock 1.5.5
Mockito 1.9.5
TestNG 6.8.8
Powermock is not taking into account mocks/spies created in a method annotated with #BeforeTest
E.g.:
#BeforeTest
public void setup(){
testee = mock(AClass.class);
}
It gets discarded and then it is entering the mocked method instead of returning the expected result OR throwing all kinds of strange exceptions. When moved to a common test method, it suddenly starts working:
#Test
public void test(){
AClass testee = mock(AClass.class);
....
}
Possibly it is a bug.