我正在使用 @SneakyThrows Lombok我的 SpringBoot 中的功能项目。
当 CGLIB 代理实现时,我遇到了这个功能的问题
它抛出
java.lang.Exception:意外异常,
预期但是
它可以以某种方式修复吗?
提供例子。
有接口(interface)和两种实现。
public interface SneakyThrowsExample {
void testSneakyThrows();
}
简单的实现
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component(value = "simpleSneakyThrowsExample")
public class SimpleSneakyThrowsExample implements SneakyThrowsExample {
@Override
@SneakyThrows
public void testSneakyThrows() {
throw new IOException();
}
}
和 @事务 实现。 CGLIB 将代理此实现。
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
@Component(value = "transactionalSneakyThrowsExample")
public class TransactionalSneakyThrowsExample implements SneakyThrowsExample {
@Override
@SneakyThrows
@Transactional
public void testSneakyThrows() {
throw new IOException();
}
}
创建@SpringBootTest 测试并注入(inject)这两个实现
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DefaultSneakyThrowsExampleTest {
@Autowired
@Qualifier(value = "transactionalSneakyThrowsExample")
SneakyThrowsExample transactionalSneakyThrowsExample;
@Autowired
@Qualifier(value = "simpleSneakyThrowsExample")
SneakyThrowsExample simpleSneakyThrowsExample;
@Test(expected = IOException.class)
public void testSneakyThrowsSimple() throws Exception {
this.simpleSneakyThrowsExample.testSneakyThrows();
}
@Test(expected = IOException.class)
public void testSneakyThrowsTransactional() throws Exception {
this.transactionalSneakyThrowsExample.testSneakyThrows();
}
}
测试 testSneakyThrowsTransactional 因错误而失败
java.lang.Exception: Unexpected exception, expected<java.io.IOException> but was<java.lang.reflect.UndeclaredThrowableException>
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.reflect.UndeclaredThrowableException
at fine.project.TransactionalSneakyThrowsExample$$EnhancerBySpringCGLIB$$57df642e.testSneakyThrows(<generated>)
at fine.project.DefaultSneakyThrowsExampleTest.testSneakyThrowsTransactional(DefaultSneakyThrowsExampleTest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
... 20 more
Caused by: java.io.IOException
at fine.project.TransactionalSneakyThrowsExample.testSneakyThrows(TransactionalSneakyThrowsExample.java:21)
at fine.project.TransactionalSneakyThrowsExample$$FastClassBySpringCGLIB$$e5429d83.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
... 31 more
最佳答案
当您使用 @事务 然后 Spring 将通过 AOP 代理为您的 bean 创建一个代理 - Spring Framework’s declarative transaction
UndeclaredThrowableException原因:
Thrown by a method invocation on a proxy instance if its invocation handler's invoke method throws a checked exception (a Throwable that is not assignable to RuntimeException or Error) that is not assignable to any of the exception types declared in the throws clause of the method that was invoked on the proxy instance and dispatched to the invocation handler.
隆博克 @SneakyThrows :
Can be used to sneakily throw checked exceptions without actually declaring this in your method's throws clause
这意味着您的
TransactionalSneakyThrowsExample.testSneakyThrows()
抛出已检查异常(未在方法签名中的 throws
中声明)当实例包装在代理中时,这是非法行为在这种情况下,您可以将预期异常更改为
Exception.class
: @Test(expected = Exception.class)
public void testSneakyThrowsTransactional() throws Exception {
this.transactionalSneakyThrowsExample.testSneakyThrows();
}
或者您可以使用
ExpectedException.expectCause()
检查IOException.class
在你的测试中,看看JUnit expect a wrapped exception
关于spring-boot - Spring + Lombok + @SneakyThrows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47017259/