java - 具有复杂通用类层次结构的 ClassCastException 和 NoSuchMethodException

标签 java generics jmockit

以下测试类包含我的项目的基于泛型的复杂类层次结构的简化版本。 genericsFailure_NoSuchMethod()genericsFailure_ClassCast1()genericsFailure_ClassCast2() 这 3 个测试都通过了 JMockit 1.6,但是从 JMockit 1.7 和 1.8 开始,我不断从 JMockit 中获取不同类型的 ClassCastExceptionNoSuchMethodException

package tests;

import mockit.Cascading;
import mockit.Mocked;
import mockit.NonStrictExpectations;

import org.testng.annotations.Test;

public class JMockitTests
{
    public static interface IAppBound<APP extends IApp<?, ?>>
    {
        APP getApp();
    }

    public static interface IBase<APP extends IApp<APP, ?>> extends IAppBound<APP>
    {

    }

    public static interface IApp<APP extends IApp<APP, ?>, BACK extends IBack<APP>> extends IBase<APP>
    {
        BACK getBack();
    }

    public static interface IBack<APP extends IApp<APP, ?>> extends IBase<APP>
    {

    }

    public static abstract class BaseImpl<APP extends AppImpl<APP, ?>> implements IBase<APP>
    {
        private APP app;

        @Override
        public APP getApp()
        {
            return app;
        }
    }

    public static class AppImpl<APP extends AppImpl<APP, ?>, BACK extends BackImpl<APP>> extends BaseImpl<APP> implements IApp<APP, BACK>
    {
        private BACK    b;

        @Override
        public BACK getBack()
        {
            return b;
        }
    }

    public static class BackImpl<APP extends AppImpl<APP, ?>> extends BaseImpl<APP> implements IBack<APP>
    {

        private Registry<APP, BackImpl<APP>>    reg;

        public Registry<APP, BackImpl<APP>> getRegistry()
        {
            return reg;
        }

        @Override
        public APP getApp()
        {
            return super.getApp();
        }
    }

    public static class Registry<APP extends AppImpl<APP, ?>, BACK extends BackImpl<APP>>
    {
        public BACK getBack(APP app)
        {
            return null;
        }

        public BACK getBack(BACK app)
        {
            return null;
        }

        public BACK getBack(String app)
        {
            return null;
        }
    }

    public static class SpecificApp extends AppImpl<SpecificApp, BackImpl<SpecificApp>>
    {

    }

    @Test
    public void genericsFailure_NoSuchMethod(@Mocked @Cascading AppImpl<?, ?> app, @Mocked @Cascading IBack<?> back)
    {
        new NonStrictExpectations()
        {
            {
                back.getApp();
                result = app;
            }
        };
    }

    @Test
    public void genericsFailure_ClassCast1(@Mocked @Cascading BackImpl<SpecificApp> back)
    {
        SpecificApp app = new SpecificApp();

        new NonStrictExpectations()
        {
            {
                back.getRegistry().getBack(app);
                result = back;
            }
        };
    }

    @Test
    public void genericsFailure_ClassCast2(@Mocked @Cascading BackImpl<SpecificApp> back)
    {
        SpecificApp app = new SpecificApp();

        new NonStrictExpectations()
        {
            {
                back.getApp();
                result = app;
            }
        };
    }
}

我认为要么是 JMockit 对泛型的处理发生了变化,要么是我完全遗漏了 JMockit 的基本概念。可以肯定的是,我同时咨询了version historydocumentation再一次,但没有任何东西引起我的注意。

我必须提到,我已经用 JDK8 和 JDK7 对此进行了测试,但问题仍然存在。我将 TestNG (6.8.6) 作为 eclipse 插件运行。

下面是TestNG的测试结果:

FAILED: genericsFailure_ClassCast1(tests.JMockitTests$BackImpl@883ce7)
java.lang.ClassCastException: java.lang.Object cannot be cast to tests.JMockitTests$BackImpl
    at tests.JMockitTests$Registry.getBack(JMockitTests.java)
    at tests.JMockitTests$2.<init>(JMockitTests.java:113)
    at tests.JMockitTests.genericsFailure_ClassCast1(JMockitTests.java:110)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:483)

FAILED: genericsFailure_ClassCast2(tests.JMockitTests$BackImpl@a7e666)
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
    at tests.JMockitTests$BackImpl.getApp(JMockitTests.java)
    at tests.JMockitTests$3.<init>(JMockitTests.java:127)
    at tests.JMockitTests.genericsFailure_ClassCast2(JMockitTests.java:124)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:483)

FAILED: genericsFailure_NoSuchMethod(tests.JMockitTests$AppImpl@4f6be2, tests.$Impl_IBack@aac163)
java.lang.RuntimeException: java.lang.NoSuchMethodException: tests.JMockitTests$IBack.getApp()
    at tests.JMockitTests$1.<init>(JMockitTests.java:99)
    at tests.JMockitTests.genericsFailure_NoSuchMethod(JMockitTests.java:96)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:483)
Caused by: java.lang.NoSuchMethodException: tests.JMockitTests$IBack.getApp()
    at java.lang.Class.getDeclaredMethod(Class.java:2117)
    ... 4 more

如果有人可以批准这是一个问题或可以指出我的解决方案,我将不胜感激。

编辑:我打开了一个 issue (issue 350)在项目上进一步跟踪这个。

最佳答案

我很惊讶这样的测试在 JMockit 1.6 中有效,因为它在级联模拟期间没有太多显式支持泛型的方式。

无论如何,自 1.7 以来的变化与 issue 333 有关。 ,它仍然是开放的。不过,这两个问题都将在 JMockit 1.9 中得到解决。

关于java - 具有复杂通用类层次结构的 ClassCastException 和 NoSuchMethodException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23437406/

相关文章:

java - 使用 JMockit 模拟被测类的私有(private)方法

java - 在 TestNG 单元测试中初始化 Autowiring 对象

Java 中的 Java 多重比较

c# - 使用泛型类型作为泛型参数的最优雅的方法是什么?

java - 有和没有分配给变量的未经检查的强制转换行为

Java 构造函数模型

java - 具有泛型类型的哈希码

java - 为什么在 Tomcat 和独立运行时 Spring 不注入(inject) @PersistenceContext entityManager

java - Java 中的静态变量启动器

ios - 使用协议(protocol)作为属性存储 UIViewController 泛型