spring-boot - Spring + Lombok + @SneakyThrows

标签 spring-boot lombok cglib

我正在使用 @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/

相关文章:

java - 需要显示特定名称而不是用户名作为通过 Spring boot smtp 发送邮件的显示名称?

java - Spring Boot Web MVC 应用程序无法解析 View

java - Lombok 没有添加方法

Java Web 启动 : unsigned cglib

spring-mvc - 需要手动创建没有密码的oAuth2 token

java - 如何绕过 JDBCTemplate org.springframework.dao.DuplicateKeyException

java - Lombok 具有配置中的默认值

java - 将 Lombok 插件添加到 IntelliJ

Maven - 无法解析 Artifact - cglib :cglib-nodep:jar:null

java - 未找到 hibernate 类