diff --git a/spring-aop/pom.xml b/spring-aop/pom.xml index 69de2d66fd..74b6f48b46 100644 --- a/spring-aop/pom.xml +++ b/spring-aop/pom.xml @@ -18,6 +18,11 @@ org.springframework.boot spring-boot-starter-aop + + org.springframework.boot + spring-boot-starter-test + test + diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/SomeCheckedException.java b/spring-aop/src/test/java/com/baeldung/undeclared/SomeCheckedException.java new file mode 100644 index 0000000000..bbb28681fa --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/SomeCheckedException.java @@ -0,0 +1,7 @@ +package com.baeldung.undeclared; + +public class SomeCheckedException extends Exception { + public SomeCheckedException(String message) { + super(message); + } +} diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/ThrowUndeclared.java b/spring-aop/src/test/java/com/baeldung/undeclared/ThrowUndeclared.java new file mode 100644 index 0000000000..dd6436e722 --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/ThrowUndeclared.java @@ -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 { +} diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredApplication.java b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredApplication.java new file mode 100644 index 0000000000..37a0ec89b5 --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredApplication.java @@ -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); + } +} diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredAspect.java b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredAspect.java new file mode 100644 index 0000000000..076fdff66c --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredAspect.java @@ -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"); + } +} diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredService.java b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredService.java new file mode 100644 index 0000000000..6cc16c1ceb --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredService.java @@ -0,0 +1,10 @@ +package com.baeldung.undeclared; + +import org.springframework.stereotype.Service; + +@Service +public class UndeclaredService { + + @ThrowUndeclared + public void doSomething() {} +} diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredThrowableExceptionIntegrationTest.java b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredThrowableExceptionIntegrationTest.java new file mode 100644 index 0000000000..e64a45d418 --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredThrowableExceptionIntegrationTest.java @@ -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); + } +} diff --git a/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredThrowableExceptionUnitTest.java b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredThrowableExceptionUnitTest.java new file mode 100644 index 0000000000..464239d12d --- /dev/null +++ b/spring-aop/src/test/java/com/baeldung/undeclared/UndeclaredThrowableExceptionUnitTest.java @@ -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 proxy = (List) 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 proxy = (List) 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(); + } + } +}