Java Jmock与jdk-11

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

我正在将一个代码库从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.$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库中的ClassImposterisersetConstructorsAccessible()至少在存在带有私有构造函数的类/枚举时与jdk-11不兼容

您能建议我应该如何处理这种情况吗?我们是否可以得出结论,使用jdk-11时jmock不是一个好主意,或者我们可以采用其他方法

谢谢

您是否正在使用支持升级的?
private void setConstructorsAccessible(Class<?> mockedType, boolean accessible) {
        for (Constructor<?> constructor : mockedType.getDeclaredConstructors()) {
            constructor.setAccessible(accessible);
        }
    }