gpt4 book ai didi

java - 为什么cglib调用MethodInterceptor回调失败?

转载 作者:行者123 更新时间:2023-11-30 04:34:26 24 4
gpt4 key购买 nike

在下面显示的单元测试类中,其中一个测试失败,另一个测试成功。这两个测试都会创建一个带有拦截器模拟的 CGLIB 对象,并尝试验证拦截器是否与之交互。对于使用 CGLIB 动态子类化的类,测试有所不同。成功的测试子类化了一个普通的 Java 接口(interface);失败的子类是一个动态子类(使用 Mockito 创建)。为什么第一次测试失败?

谢谢。

public class ATest {

@Test
// This test fails.
public void cannotCallMethodOnMockWrapper() throws Throwable {
final Class<? extends Bar> c = Mockito.mock(Bar.class).getClass();
verifyInterceptorIsInvokedOnCallToObjectOfEnhanced(c);
}

@Test
// This test succeeds.
public void interceptorIsCalled() throws Throwable {
final Class<? extends Bar> c = Bar.class;
verifyInterceptorIsInvokedOnCallToObjectOfEnhanced(c);
}

private void verifyInterceptorIsInvokedOnCallToObjectOfEnhanced(
final Class<? extends Bar> c) throws Throwable {
final MethodInterceptor interceptor = Mockito.mock(
MethodInterceptor.class);
final Bar wrapper = (Bar) Enhancer.create(c, interceptor);

// Here is where the failing test chokes with exception:
// NoSuchMethodError
wrapper.foo();

verifyInterceptIsCalledOn(interceptor);
}

private void verifyInterceptIsCalledOn(
final MethodInterceptor interceptor) throws Throwable {
verify(interceptor).intercept(any(), any(Method.class),
any(Object[].class), any(MethodProxy.class));
}

public static interface Bar {
void foo();
}

}

更新:

失败的堆栈跟踪

java.lang.NoSuchMethodError: java.lang.Object.foo()V
at ATest$Bar$$EnhancerByMockitoWithCGLIB$$2e1d601f.foo(<generated>)
at ATest.verifyInterceptorIsInvokedOnCallToObjectOfEnhanced(ATest.java:37)
at ATest.cannotCallMethodOnMockWrapper(ATest.java:19)

此外,至于 Mockito 模拟是否是 CGLIB 增强类,下面的测试(失败)似乎表明它不是:

public class ATest {

@Test
public void mockitoMockIsCGLIBEnhanced() {
assertTrue(Enhancer.isEnhanced(Mockito.mock(Bar.class).getClass()));
}

public static interface Bar {
void foo();
}

}

最佳答案

如果没有堆栈跟踪,我会假设您有一个 net.sf.cglib.core.CodeGenerationException ,原因可能是 InvocableTargetExceptionClassFormatError ,

发生这种情况是因为 CGLIB 无法增强它自己创建的已经增强的类。由于 Mockito 在 JVM 内部使用 CGLIB,因此您无法增强 Mockito 类。你需要增强原来的类。 此外,即使回调是一个实例,您也需要传递给生成的类,因此通过创建自己的增强器,您就没有上层类的 Mockito 回调。所以mockito模拟功能甚至无法工作。不管怎样,我偏离了主题。

所以基本上你不能用CGLIB增强增强类,如果这个问题在运行时发生,因为你传递了一个模拟,我相信你应该有这样的代码,检查它是否增强,如果是使用父类(super class)(原始类)和/或接口(interface):

public class CGLIBEnhancerEnhancer implements TypeEnhancer {
public void Object enhance(Object objectCandidateToEnhance, MethodInterceptor interceptor) {
Class classCandidateToEnhance = classCandidateToEnhance.getClass();
if(Enhancer.isEnhanced(classCandidateToEnhance)
|| Mockito.mockingDetails(objectCandidateToEnhance).isMock()) {
// safe with CGLIB (2.x) enhanced class
return (Bar) Enhancer.create(
classCandidateToEnhance.getSuperclass(),
classCandidateToEnhance.getInterfaces(),
interceptor
);
} else
return (Bar) Enhancer.create(classCandidateToEnhance, interceptor);
}
}
}

编辑:我运行了给定的示例,它确实给了我 CodeGenerationException,您可以在本答案的末尾看到。尽管根据环境的不同,您可能会看到不同的堆栈跟踪,例如您发布的堆栈跟踪。

考虑到您的异常,我相信您可能在运行时遇到如何创建双增强类的问题。由于堆栈跟踪表明该实例甚至没有 foo 方法,因此就像该对象(似乎是真正的 mockito 模拟)是从错误的类型生成的。我会查看增强器的 API,以正确使用类型和接口(interface)来创建增强类,您可以使用 Enhancer 的新实例或使用静态方法。

此外,如果您自己证明拦截器,并且想要执行给定实例的行为(模拟或非模拟),则应该精心设计您的拦截器,使其保存对原始对象的引用。

编辑2:实际上,由于技术原因,Mockito正在重新打包/jarjar/内联CGLIB,这意味着net.sf.cglib.proxy.Enhancer无法检测到mockito mock 。相反,人们应该使用 1.9.5 中新引入的 API Mockito.mockingDetails(instance).isMock() 来检测 mockito 模拟。或者使用重新打包/jarjared/内联的org.mockito.cglib.proxy.Enhancer。最后,您需要在类路径中使用 Mockito 来检测 Mockito 模拟。

希望有帮助

org.mockito.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:238)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.create(Enhancer.java:286)
at org.mockito.cglib.proxy.Enhancer.create(Enhancer.java:664)
at ATest.verifyInterceptorIsInvokedOnCallToObjectOfEnhanced(ATest.java:32)
at ATest.cannotCallMethodOnMockWrapper(ATest.java:18)
... removed
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
... removed
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:385)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:220)
... 31 more
Caused by: java.lang.ClassFormatError: Duplicate method name&signature in class file ATest$Bar$$EnhancerByMockitoWithCGLIB$$58a2468b$$EnhancerByCGLIB$$9232d1df
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
... 37 more

关于java - 为什么cglib调用MethodInterceptor回调失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13826705/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com