Java Jmock与jdk-11
我正在将一个代码库从Java1.8更新到Java11,我偶然发现了下面的怪物。 我正在处理的项目正在junit-4中使用jmock-2.8.4。 junit测试在JDK1.8中运行良好,但在JDK11中开始失败,下面提到了异常Java Jmock与jdk-11,java,java-8,java-11,jmock,Java,Java 8,Java 11,Jmock,我正在将一个代码库从Java1.8更新到Java11,我偶然发现了下面的怪物。 我正在处理的项目正在junit-4中使用jmock-2.8.4。 junit测试在JDK1.8中运行良好,但在JDK11中开始失败,下面提到了异常 java.lang.IllegalArgumentException: null at net.sf.cglib.asm.$ClassReader.<init>(Unknown Source) at net.sf.cglib.asm.$Clas
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
我做了一些调试,发现了以下细节
在我看来,它似乎是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);
}
}
public T imposterise(最终可调用的mockObject、类mockedType、类…辅助类型){
如果(!mockedType.isInterface()&&ToString方法最终版(mockedType)){
抛出新的IllegalArgumentException(mockedType.getName()+“具有最终的toString方法”);
}
试一试{
setConstructorsAccessible(mockedType,true);
返回mockedType.cast(代理(proxyClass(mockedType,辅助类型),mockObject));
}
最后{
setConstructorsAccessible(mockedType,false);
}
}
最后,还有一个对下面方法的调用,其中构造函数也在jmock库中设置为可访问
private void setConstructorsAccessible(Class<?> mockedType, boolean accessible) {
for (Constructor<?> constructor : mockedType.getDeclaredConstructors()) {
constructor.setAccessible(accessible);
}
}
private void setconstructor可访问(类mockedType,布尔可访问){
for(构造函数:mockedType.getDeclaredConstructors()){
constructor.setAccessible(可访问);
}
}
我观察到的是,当为enumLbFormat调用setConstructorsAccessible(私有构造函数作为枚举)时,我们确实会得到异常
此外,我还发现jdk中有一些升级,具有更强的封装性,即使是来自JDK9的反射访问。在我看来,jmock库中的ClassImposteriser的setConstructorsAccessible()至少在存在带有私有构造函数的类/枚举时与jdk-11不兼容
您能建议我应该如何处理这种情况吗?我们是否可以得出结论,使用jdk-11时jmock不是一个好主意,或者我们可以采用其他方法
谢谢 您是否正在使用支持升级的?
private void setConstructorsAccessible(Class<?> mockedType, boolean accessible) {
for (Constructor<?> constructor : mockedType.getDeclaredConstructors()) {
constructor.setAccessible(accessible);
}
}