JDK与JDK-11

问题描述

我正在将代码库从 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 (将#修改为@)