问题描述
我正在将代码库从 java 1.8 更新为 java 11 ,我偶然发现了以下怪物。 我正在使用的项目将 jmock-2.8.4 与junit-4一起使用。 可以正常运行并在jdk 1.8上运行的junit测试在jdk 11上失败,但以下所述。
java.lang.IllegalArgumentException: null
at net.sf.cglib.asm.$ClassReader.<init>(UnkNown Source)
at net.sf.cglib.asm.$ClassReader.<init>(UnkNown Source)
at net.sf.cglib.asm.$ClassReader.<init>(UnkNown Source)
at net.sf.cglib.proxy.BridgeMethodResolver.resolveAll(BridgeMethodResolver.java:61)
at net.sf.cglib.proxy.Enhancer.emitMethods(Enhancer.java:1132)
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:630)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:329)
at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:337)
at org.jmock.lib.legacy.ClassImposteriser.proxyClass(ClassImposteriser.java:121)
at org.jmock.lib.legacy.ClassImposteriser.imposterise(ClassImposteriser.java:66)
at org.jmock.internal.ReturnDefaultValueAction.invoke(ReturnDefaultValueAction.java:82)
at org.jmock.internal.InvocationToExpectationTranslator.invoke(InvocationToExpectationTranslator.java:20)
at org.jmock.internal.FakeObjectMethods.invoke(FakeObjectMethods.java:38)
at org.jmock.lib.legacy.ClassImposteriser$4.invoke(ClassImposteriser.java:136)
at de.t_mobile.crisp.connectors.lbs.Client$$EnhancerBycglib$$9c27175a.profilepformat(<generated>)
at webservices.service.impl.ServiceBeanUnitTest$7.<init>(ServiceBeanUnitTest.java:378)
at webservices.service.impl.ServiceBeanUnitTest.partially
使用jmock进行的junit测试的relevent部分发生了异常
new Expectations() {
{
allowing(client).profileFormat(1);
will(returnValue(LbFormat.RECTANGLE));
}
}
我进行了一些调试,发现了以下详细信息。
在我看来,org.jmock.lib.legacy.ClassImposteriser.proxyClass(ClassImposteriser.java:121)
造成麻烦。
因此,jmock库中的相关Java代码如下-
try {
return enhancer.createClass();
}
catch (CodeGenerationException e) {
// Note: I've only been able to manually test this. It exists to help people writing
// Eclipse plug-ins or using other environments that have sophisticated class loader
// structures.
throw new IllegalArgumentException("Could not imposterise " + mockedType,e);
}
enhancer.createClass();
在jmock库的 ClassImposteriser 中调用 imposterise()方法
public <T> T imposterise(final Invokable mockObject,Class<T> mockedType,Class<?>... ancilliaryTypes) {
if (!mockedType.isInterface() && toStringMethodisFinal(mockedType)) {
throw new IllegalArgumentException(mockedType.getName() + " has a final toString method");
}
try {
setConstructorsAccessible(mockedType,true);
return mockedType.cast(proxy(proxyClass(mockedType,ancilliaryTypes),mockObject));
}
finally {
setConstructorsAccessible(mockedType,false);
}
}
最后,调用了下面的方法,在jmock库中也可以访问构造方法。
private void setConstructorsAccessible(Class<?> mockedType,boolean accessible) {
for (Constructor<?> constructor : mockedType.getDeclaredConstructors()) {
constructor.setAccessible(accessible);
}
}
我观察到的是,当为枚举 LbFormat (私有构造函数作为枚举)调用setConstructorsAccessible时,我们确实得到了异常。
我还发现,即使从jdk 9进行反射访问,jdk的升级也有了更强大的封装。在我看来, ClassImposteriser 的 setConstructorsAccessible()如果存在带有私有Constructor的类/枚举,则jmock库中的Java与jdk-11至少不兼容。
您能建议我如何应对这种情况吗?我们可以得出结论,使用jdk-11时jmock不是一个好主意吗?或者还有其他可以遵循的方法。
谢谢!
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)