Aspects not Working within #SpringBoot class - java

I am trying to integrate AspectJ and SpringBoot. It was running fine until I tried experimenting a bit and used:
#SpringBootApplication
public class TestClassRunner {
#MyAnnotation
public void someDisplay(){
System.out.println("My Display");
}
#Bean(name="dummyString")
public String getString(){
someDisplay();
return "SUCCESS";
}
}
The Aspect class is defined as:
#Aspect
#Component
public class MyAnnotationProcessor{
#Before("#annotation(myTest.MyAnnotation)")
public void aroundSampleCreation(JoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint.getSignature());
System.out.println("Executing the Before call");
}
}
Now this Advice is not getting executed. Is it because of some special character of the #Configuration class (I know #SpringBoot uses that internally)?
I have included all the dependencies and that should not be the cause of this not working.
Any help is highly appreciated.

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.

Spring Cache not working as a compute property

I want to use a mechanism for create a one time compute function. I try to use Spring Caching. But it does not working. Please help me to solve this problem. My code like as below,
Gradle Dependency
compile 'org.springframework.boot:spring-boot-starter-cache'
Main Class of Spring Boot Application
#SpringBootApplication
#EnableCaching
public class Application {
public static ApplicationContext applicationContext;
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// todo: Try to save response text and request body
applicationContext = SpringApplication.run(Application.class, args);
}
#Bean
WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("classpath:/")
.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS).noTransform().mustRevalidate());
}
};
}
}
My Coputational property and Test method
public String test(){
return hello();
}
#Cacheable("hello")
public String hello(){
System.out.println("hello");
return "Hello";
}
The #Cacheable annotation caches the values when it is called from outside your #Bean so calling it from another method inside your bean will not work.
try something like
#Bean
public class CachingBean {
#Cacheable("hello")
public String hello(){
System.out.println("hello");
return "Hello";
}
}
#Service
public class CallerService {
#Autowired
private CachingBean cachingBean;
// Setters, constructors...
public String test(){
return cachingBean.hello();
}
}
And then it should work.
That's because the #Cacheable annotation creates a proxy around the method call when it is injected as a Bean, so a direct call (to an instance created directly) or an internal call are not intercepted and the caching mechanism does not even see those calls.
I still sometimes forget about it and get biten by it at the beginning :).
Cheers!

How to avoid spring AOP aspect being called during test

I need to avoid an aspect being called when unit testing a class.
I'm working with Java 8, spring 4.3.22.RELEASE and mockito. I have a #Service and a unit test for it. I also have an #Aspect that defines a pointcut on a method in the service and it is working fine when I run my application. The problem is when I run my unit test, the aspect is called and a NullPointerException is raised because of a missing dependency in the aspect.
Service class:
#Service
public class ContactService {
#Autowired
public InContactService(ContactDao contactDao) {
this.contactDao = contactDao;
}
public boolean muteCall(Long contactId) {
return contactDao.muteCall(contactId);
}
}
Service test:
public class ContactServiceTest {
#Mock
private ContactDao contactDao;
private ContactService contactService;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
contactService = new ContactService(contactDao);
}
#Test
public void testMuteCall(){
contactService.muteCall(1L);
}
}
Aspect:
#Aspect
public class ContactAspect {
private MeterRegistry registry;
public void setRegistry(MeterRegistry registry) {
this.registry = registry;
}
#AfterReturning(pointcut = "execution(* com.company.ContactService.muteCall(..))", returning = "retVal")
public void checkReturnContactServiceMuteCall(JoinPoint joinPoint, boolean retVal) {
Object[] args = joinPoint.getArgs();
registry.counter("my.metric.mute_call").increment();
}
}
Application context:
#Configuration
public class ApplicationContext {
#Bean
public MeterRegistry meterRegistry() {
return new SimpleMeterRegistry();
}
#Bean
public ContactAspect contactAspect() {
ContactAspect aspect = Aspects.aspectOf(ContactAspect.class);
aspect.setRegistry(meterRegistry());
return aspect;
}
}
I expected that when the test is ran the aspect is not called. Currently I get a NullPointerException when I run the test because registry is not defined in the aspect.
The best approach is using Spring profiles, which allows you to have different running schemes.
check this:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
I ran into this issue with legacy code to which I wanted to add integration tests but didn't need or want the aspects to be invoked.
There most likely is somewhere in your context configuration telling the application to enable aspects. Wherever that is, find it, and disable it.
In my case, the configs were XML based so in my applicationContext-services-integration-test.xml file being loaded for my integration tests, I commented out
<aop:aspectj-autoproxy /> and it bypassed all the aspects for my tests.
Cheers!
We've run into the same problem and fixed it by disabling property when running tests.
import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
#Aspect
#ConditionalOnExpression("${aspect.property.enabled:true}")
public class AspectClass {
test/resources/application.properties
aspect.property.enabled=false

Aspect Before annotation not working

Testing out Aspect #Before annotation in a Spring Boot application and it is not working. No Errors thrown. Just simply not working. It is a very simple rest service as below. Been at it for some time now and any tutorials and answers here seems to point that this is correct. My rest service returns correctly. Just that the message from Aspect doesn't print. I am very confident my package structure is correct. Please advice.
#SpringBootApplication
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class StuffApplication {
public static void main(String[] args) {
SpringApplication.run(StuffApplication.class, args);
}
}
#RestController
#RequestMapping("/information")
public class ContentController {
#GetMapping("/person")
public People getPerson(Model model){
log(); // expecting the aspect print to occur when I call this.
// some logic to get personList which works fine
return new People(personList);
}
public void log(){
System.out.println("This is a logger");
}
}
#Aspect
#Component
public class JsonAspect {
#Before(value = "execution(* com.example.stuff.controller.ContentController.log())")
public void printBefore(){
System.out.println("I was called before the logger"); // never prints when I call log method
}
}

#DeclareParents fail to introduce new method

everybody, I am a beginner in Spring and I am encountering some problems with #DeclareParents. I follow the instructions in Spring In Action but I fail to realize the introduction.
Here are my codes.
I first define Interface performance
public interface Performance {
void perform();
}
and then implement the interface.
#Component
public class OnePerformance implements Performance {
#Autowired
public OnePerformance(){
}
public void perform() {
System.out.println("The Band is performing....");
}
}
I want to introduce method void performEncore() into Performance.
So I define the Interface,
public interface Encoreable {
void performEncore();
}
implement it,
#Aspect
public class DefaultEncoreable implements Encoreable{
public void performEncore() {
System.out.println("performEncore");
}
}
and introduce it,
#Aspect
#Component
public class EncoreableIntroduction {
#DeclareParents(value="Performance+",
, defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}
I use autoconfiguration,
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class ConcertConfig {
}
However, when testing, I fail to introduce method void performEncore().
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
performance.perform();
}}
And I also enabled AspectJ Support Plugins.
I have read the book and several blogs carefully but I still can not find the cause. So what may be the cause of this problem? Thanks in advance.
Thanks for M. Deinum, NewUser and Wim Deblauwe. With their help, I finally figured out the problem. The previous JUnit4 class is not correct.
The proper solution to solve this problem is to cast Performance into Encoreable, and then call the performEncore() method.
The code is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= ConcertConfig.class)
public class OnePerformanceTest {
#Autowired
private Performance performance;
#Test
public void perform() throws Exception {
Encoreable encoreable = (Encoreable)(performance);
encoreable.performEncore();
}
}

Categories