Spring aop by annotation on controller method does not work - java

Annotation
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
String value();
}
AOP
#Aspect
#Component
public class MyAspect {
#Around("#annotation(MyAnnotation)")
public Object aroundHandler(ProceedingJoinPoint joinPoint) throws Throwable {
...
}
Controller
#Controller
public class MyController {
#RequestMapping(value="/hello", method=RequestMethod.GET)
#ResponseBody
#MyAnnotation(value="hello")
public String hello() {
return "hello";
}
}
in above condition, my aop does not work...
It works fine with other methods, which is not annotated by #Controller.
And it works fine with aop expression and controller method.
Is it possible to use aop by annotation with controller method?

Try this:
#Around("#annotation(myAnnotation)")
public Object aroundHandler(ProceedingJoinPoint joinPoint,MyAnnotation myAnnotation) throws Throwable {
// Do Something
}

I think you need to use #within...this blog post may help https://www.productiveprogrammer.net/?p=49

Related

how to unit test Aspect annotation

I have defined an Aspect and it will be used when the method is annotated. Please see the sample code below
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface PredefinedCheck {
}
#Aspect
#Component
public class PredefinedAspect {
#Before("#annotation(PredefinedCheck)")
#SneakyThrows
public void check(JoinPoint joinPoint) {
......
log.debug("hello!!");
}
}
#Service
public class ActionService {
#PredefinedCheck
public MyEntity updateMyEntity(AuthenticationJwtToken authToken, EntityUpdateRequest request) {
......
}
}
Now, the question is how can I unit test my PredefinedAspect code? I thought unit testing the updateMyEntity method will trigger it, but it didn't (I debugged and it not hit the break point. Also, the sonarqube doesn't shows the code being covered). Please advise.

Custom Spring annotation not working

I'm trying out a simple custom Spring annotation, but it seems like Spring isn't executing anything when i slap the annotation on a method...anyone have any ideas? I see no logging at all. Maybe i need some aop dependency?
#Aspect
#Component
public class LethargicLoggerAspect {
private final Logger log = LoggerFactory.getLogger(getClass());
#Around("#annotation(LethargicLogger)")
public Object logSlowExecutionTime(ProceedingJoinPoint
proceedingJoinPoint) throws
Throwable {
log.error("HIIIIIIIIII david");
Object proceed = proceedingJoinPoint.proceed();
return proceed;
}
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface LethargicLogger {
}
It looks good, you need to add package to the #Around annotation.
#Around("#annotation(com.example.package.LethargicLogger)")
public Object logSlowExecutionTime(ProceedingJoinPoint
proceedingJoinPoint) throws
Throwable {
}

Exclude a specific method to be invoked by CDI Interceptor

I have an interceptor binding annotation :
#InterceptorBinding
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyBinding {
}
To this CDI interceptor :
#Interceptor
#MyBinding
public class MyInterceptor {
#AroundInvoke
public Object applyPolicy(InvocationContext ctx) throws Exception {
return blablabla;
}
}
And a class annotated, that mean every methods of this class will invoke MyInterceptor
#MyBinding
public class GlobalController {
public void methodA() {...}
public void methodB() {...}
}
All works fine, but I wish methodB not invoking my interceptor.
I tried both annotations #ExcludeClassInterceptors and #ExcludeDefaultInterceptors on my method but it doesn't works for me. I think these annotations are especially for exclude a method for EJB Interceptor, and not CDI Interceptor with Interceptor binding.
Not sure about these annotations but as a workaround you can add an annotation to the method you want to exclude. Get Method from InvocationContext in the interceptor and check whether the method has the annotation. In this case just delegate to the original method.
Try #MyBinding at method level:
public class GlobalController {
#MyBinding
public void methodA() {...}
public void methodB() {...}
}

How to test if #Valid annotation is working?

I have the following unit test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {EqualblogApplication.class})
#WebAppConfiguration
#TestPropertySource("classpath:application-test.properties")
public class PostServiceTest {
// ...
#Test(expected = ConstraintViolationException.class)
public void testInvalidTitle() {
postService.save(new Post()); // no title
}
}
The code for save in PostService is:
public Post save(#Valid Post post) {
return postRepository.save(post);
}
The Post class is marked with #NotNull in most fields.
The problem is: no validation exception is thrown.
However, this happens only in testing. Using the application normally runs the validation and throws the exception.
Note: I would like to do it automatically (on save) and not by manually validating and then saving (since it's more realistic).
This solution works with Spring 5. It should work with Spring 4 as well. (I've tested it on Spring 5 and SpringBoot 2.0.0).
There are three things that have to be there:
in the test class, provide a bean for method validation (PostServiceTest in your example)
Like this:
#TestConfiguration
static class TestContextConfiguration {
#Bean
public MethodValidationPostProcessor bean() {
return new MethodValidationPostProcessor();
}
}
in the class that has #Valid annotations on method, you also need to annotate it with #Validated (org.springframework.validation.annotation.Validated) on the class level!
Like this:
#Validated
class PostService {
public Post save(#Valid Post post) {
return postRepository.save(post);
}
}
You have to have a Bean Validation 1.1 provider (such as Hibernate Validator 5.x) in the classpath. The actual provider will be autodetected by Spring and automatically adapted.
More details in MethodValidationPostProcessor documentation
Hope that helps
This is how I did it by loading ValidationAutoConfiguration.class into context:
#SpringBootTest
#ContextConfiguration(classes = { MyComponent.class, ValidationAutoConfiguration.class
public class MyComponentValidationTest {
#Autowired
private MyComponent myComponent;
#Test
void myValidationTest() {
String input = ...;
// static import from org.assertj.core.api.Assertions
assertThatThrownBy(() -> myComponent.myValidatedMethod(input))
.isInstanceOf(ConstraintViolationException.class)
.hasMessageContaining("my error message");
}
}
And MyComponent class:
#Component
#Validated
public class MyComponent {
public void myValidatedMethod(#Size(min = 1, max = 30) String input) {
// method body
}
)

Spring aop (custom param in ControllerAdvice & ModelAttribute)

I want to add custom param to ControllerAdvice and ModelAttribute method. Please see code below.
#Target( { ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyPage {
String param();
}
#Controller
public class MyController {
#RequestMapping...
#MyPage(param = "a")
public void myPage() {
....
}
}
#ControllerAdvice
public class MyAdviceController {
#ModelAttribute
public void addAttributes(Model model, MyPage myPage){
System.out.println(myPage.param());
}
}
How can I get myPage param work.
I am getting
class org.springframework.beans.BeanInstantiationException
Exception: Could not instantiate bean class [MyPage]: Specified class is an interface
I want to get myPage object with param() value "a"

Categories