JAVA-8280: Split or move spring-aop module

This commit is contained in:
sampadawagde
2021-12-30 20:39:11 +05:30
parent 77dcb8853f
commit 9eaa8f4dff
26 changed files with 123 additions and 7 deletions
@@ -0,0 +1,12 @@
package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@@ -0,0 +1,28 @@
package com.baeldung.method.info;
public class Account {
private String accountNumber;
private double balance;
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" + "accountNumber='" + accountNumber + '\'' + ", balance=" + balance + '}';
}
}
@@ -0,0 +1,12 @@
package com.baeldung.method.info;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccountOperation {
String operation();
}
@@ -0,0 +1,55 @@
package com.baeldung.method.info;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
@Aspect
@Component
public class BankAccountAspect {
@Before(value = "@annotation(com.baeldung.method.info.AccountOperation)")
public void getAccountOperationInfo(JoinPoint joinPoint) {
// Method Information
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
System.out.println("full method description: " + signature.getMethod());
System.out.println("method name: " + signature.getMethod().getName());
System.out.println("declaring type: " + signature.getDeclaringType());
// Method args
System.out.println("Method args names:");
Arrays.stream(signature.getParameterNames())
.forEach(s -> System.out.println("arg name: " + s));
System.out.println("Method args types:");
Arrays.stream(signature.getParameterTypes())
.forEach(s -> System.out.println("arg type: " + s));
System.out.println("Method args values:");
Arrays.stream(joinPoint.getArgs())
.forEach(o -> System.out.println("arg value: " + o.toString()));
// Additional Information
System.out.println("returning type: " + signature.getReturnType());
System.out.println("method modifier: " + Modifier.toString(signature.getModifiers()));
Arrays.stream(signature.getExceptionTypes())
.forEach(aClass -> System.out.println("exception type: " + aClass));
// Method annotation
Method method = signature.getMethod();
AccountOperation accountOperation = method.getAnnotation(AccountOperation.class);
System.out.println("Account operation annotation: " + accountOperation);
System.out.println("Account operation value: " + accountOperation.operation());
}
}
@@ -0,0 +1,29 @@
package com.baeldung.method.info;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.stereotype.Component;
@Component
public class BankAccountService {
@AccountOperation(operation = "deposit")
public void deposit(Account account, Double amount) {
account.setBalance(account.getBalance() + amount);
}
@AccountOperation(operation = "withdraw")
public void withdraw(Account account, Double amount) throws WithdrawLimitException {
if (amount > 500.0) {
throw new WithdrawLimitException("Withdraw limit exceeded.");
}
account.setBalance(account.getBalance() - amount);
}
public double getBalance() {
return RandomUtils.nextDouble();
}
}
@@ -0,0 +1,7 @@
package com.baeldung.method.info;
public class WithdrawLimitException extends RuntimeException {
public WithdrawLimitException(String message) {
super(message);
}
}
@@ -0,0 +1,59 @@
package com.baeldung.performancemonitor;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.interceptor.PerformanceMonitorInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.time.LocalDate;
import java.time.Month;
@Configuration
@EnableAspectJAutoProxy
public class AopConfiguration {
@Pointcut("execution(public String com.baeldung.performancemonitor.PersonService.getFullName(..))")
public void monitor() { }
@Pointcut("execution(public int com.baeldung.performancemonitor.PersonService.getAge(..))")
public void myMonitor() { }
@Bean
public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
return new PerformanceMonitorInterceptor(true);
}
@Bean
public Advisor performanceMonitorAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("com.baeldung.performancemonitor.AopConfiguration.monitor()");
return new DefaultPointcutAdvisor(pointcut, performanceMonitorInterceptor());
}
@Bean
public Person person(){
return new Person("John","Smith", LocalDate.of(1980, Month.JANUARY, 12));
}
@Bean
public PersonService personService(){
return new PersonService();
}
@Bean
public MyPerformanceMonitorInterceptor myPerformanceMonitorInterceptor() {
return new MyPerformanceMonitorInterceptor(true);
}
@Bean
public Advisor myPerformanceMonitorAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("com.baeldung.performancemonitor.AopConfiguration.myMonitor()");
return new DefaultPointcutAdvisor(pointcut, myPerformanceMonitorInterceptor());
}
}
@@ -0,0 +1,39 @@
package com.baeldung.performancemonitor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.springframework.aop.interceptor.AbstractMonitoringInterceptor;
import java.util.Date;
public class MyPerformanceMonitorInterceptor extends AbstractMonitoringInterceptor {
public MyPerformanceMonitorInterceptor() {
}
public MyPerformanceMonitorInterceptor(boolean useDynamicLogger) {
setUseDynamicLogger(useDynamicLogger);
}
@Override
protected Object invokeUnderTrace(MethodInvocation invocation, Log log) throws Throwable {
String name = createInvocationTraceName(invocation);
long start = System.currentTimeMillis();
log.info("Method "+name+" execution started at:"+new Date());
try {
return invocation.proceed();
}
finally {
long end = System.currentTimeMillis();
long time = end - start;
log.info("Method "+name+" execution lasted:"+time+" ms");
log.info("Method "+name+" execution ended at:"+new Date());
if (time > 10){
log.warn("Method execution longer than 10 ms!");
}
}
}
}
@@ -0,0 +1,16 @@
package com.baeldung.performancemonitor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class PerfomanceApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AopConfiguration.class);
Person person = (Person) context.getBean("person");
PersonService personService = (PersonService) context.getBean("personService");
System.out.println("Name is:"+personService.getFullName(person));
System.out.println("Age is:"+personService.getAge(person));
}
}
@@ -0,0 +1,42 @@
package com.baeldung.performancemonitor;
import java.time.LocalDate;
public class Person {
private String lastName;
private String firstName;
private LocalDate dateOfBirth;
public Person() {
}
public Person(String firstName, String lastName, LocalDate dateOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.dateOfBirth = dateOfBirth;
}
public LocalDate getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(LocalDate dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
@@ -0,0 +1,17 @@
package com.baeldung.performancemonitor;
import java.time.LocalDate;
import java.time.Period;
public class PersonService {
public String getFullName(Person person){
return person.getLastName()+" "+person.getFirstName();
}
public int getAge(Person person){
Period p = Period.between(person.getDateOfBirth(), LocalDate.now());
return p.getYears();
}
}
@@ -0,0 +1,7 @@
package com.baeldung.undeclared;
public class SomeCheckedException extends Exception {
public SomeCheckedException(String message) {
super(message);
}
}
@@ -0,0 +1,11 @@
package com.baeldung.undeclared;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ThrowUndeclared {
}
@@ -0,0 +1,12 @@
package com.baeldung.undeclared;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UndeclaredApplication {
public static void main(String[] args) {
SpringApplication.run(UndeclaredApplication.class, args);
}
}
@@ -0,0 +1,16 @@
package com.baeldung.undeclared;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UndeclaredAspect {
@Around("@annotation(undeclared)")
public Object advise(ProceedingJoinPoint pjp, ThrowUndeclared undeclared) throws Throwable {
throw new SomeCheckedException("AOP Checked Exception");
}
}
@@ -0,0 +1,10 @@
package com.baeldung.undeclared;
import org.springframework.stereotype.Service;
@Service
public class UndeclaredService {
@ThrowUndeclared
public void doSomething() {}
}
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<logger name="com.baeldung.performancemonitor.MyPerformanceMonitorInterceptor" level="INFO" />
<logger name="org.springframework.aop.interceptor.PerformanceMonitorInterceptor" level="TRACE" />
<root level="TRACE">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,15 @@
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,49 @@
package com.baeldung.method.info;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
class BankAccountServiceIntegrationTest {
private Account account;
@BeforeEach
public void setup() {
account = new Account();
account.setAccountNumber("12345");
account.setBalance(2000.0);
}
@Autowired
BankAccountService bankAccountService;
@Test
void withdraw() {
bankAccountService.withdraw(account, 500.0);
assertTrue(account.getBalance() == 1500.0);
}
@Test
void withdrawWhenLimitReached() {
Assertions.assertThatExceptionOfType(WithdrawLimitException.class)
.isThrownBy(() -> bankAccountService.withdraw(account, 600.0));
assertTrue(account.getBalance() == 2000.0);
}
@Test
void deposit() {
bankAccountService.deposit(account, 500.0);
assertTrue(account.getBalance() == 2500.0);
}
@Test
void getBalance() {
bankAccountService.getBalance();
}
}
@@ -0,0 +1,25 @@
package com.baeldung.undeclared;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.lang.reflect.UndeclaredThrowableException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = UndeclaredApplication.class)
public class UndeclaredThrowableExceptionIntegrationTest {
@Autowired private UndeclaredService service;
@Test
public void givenAnAspect_whenCallingAdvisedMethod_thenShouldWrapTheException() {
assertThatThrownBy(service::doSomething)
.isInstanceOf(UndeclaredThrowableException.class)
.hasCauseInstanceOf(SomeCheckedException.class);
}
}
@@ -0,0 +1,48 @@
package com.baeldung.undeclared;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class UndeclaredThrowableExceptionUnitTest {
@Test
@SuppressWarnings("unchecked")
public void givenAProxy_whenProxyUndeclaredThrowsCheckedException_thenShouldBeWrapped() {
ClassLoader classLoader = getClass().getClassLoader();
InvocationHandler invocationHandler = new ExceptionalInvocationHandler();
List<String> proxy = (List<String>) Proxy.newProxyInstance(classLoader, new Class[] { List.class }, invocationHandler);
assertThatThrownBy(proxy::size)
.isInstanceOf(UndeclaredThrowableException.class)
.hasCauseInstanceOf(SomeCheckedException.class);
}
@Test
@SuppressWarnings("unchecked")
public void givenAProxy_whenProxyThrowsUncheckedException_thenShouldBeThrownAsIs() {
ClassLoader classLoader = getClass().getClassLoader();
InvocationHandler invocationHandler = new ExceptionalInvocationHandler();
List<String> proxy = (List<String>) Proxy.newProxyInstance(classLoader, new Class[] { List.class }, invocationHandler);
assertThatThrownBy(proxy::isEmpty).isInstanceOf(RuntimeException.class);
}
private static class ExceptionalInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("size".equals(method.getName())) {
throw new SomeCheckedException("Always fails");
}
throw new RuntimeException();
}
}
}