【问题标题】:ClassFormatError while creating a java proxy for multiple inheritance?为多重继承创建java代理时出现ClassFormatError?
【发布时间】:2014-02-21 15:17:01
【问题描述】:

我有实现接口“I”的“A”类。我有两个类“B”和“C”,每个类都扩展了 A 并添加了一个新方法。 C和B不覆盖A中的任何方法。“B”类中的新方法与“C”的签名不同,新方法是C和B之间的唯一区别。我需要创建一个代理(排序'B' 和 'C' 的对象的组合)应该具有 A 的所有方法以及 'B' 和 'C' 中的新方法。

我尝试在 CGLIB 中使用 Mixin$Generator 创建复合代理,但出现错误“java.lang.ClassFormatError: Duplicate interface name in class file”。

有没有人遇到过类似的情况?有什么解决这个问题的建议吗?

感谢您的宝贵时间。

这里是用接口和所有类更新的代码。

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Mixin;
import net.sf.cglib.proxy.Mixin.Generator;

interface I {
    public boolean testSomething();
}

class A implements I {

    @Override
    public boolean testSomething() {
        boolean isRoot = true;
        System.out.println("Returning '" + isRoot + "' from '" + this + "' ...");
        return isRoot;
    }
}

class B extends A {
    public boolean isB() {
        boolean isRoot1 = true;
        System.out.println("Returning " + isRoot1 + " from : " + this);
        return isRoot1;
    }
}

class C extends A {
    public int getInt() {
        int someInt = 2;
        System.out.println("Returning " + someInt + " from : " + this);
        return someInt;
    }
}
    public class TestMixin {

        public static Object invokeMethod(Object target, String methodName)
                throws Exception {
            Method method = target.getClass().getMethod(methodName);
            return method.invoke(target);
        }

        public static Mixin newInstance(Object[] delegates) {
            return newInstance(null, delegates);
        }

        public static Mixin newInstance(Class[] interfaces, Object[] delegates) {
            Generator gen = new Generator();
            gen.setStyle(Mixin.STYLE_EVERYTHING);
            if(interfaces != null) {
                gen.setClasses(interfaces);
            }
            gen.setDelegates(delegates);
            return gen.create();
        }

        public static void main(String[] args) throws Exception {
           // B and C extend Class 'A' which implements 'I' interface
            B root1 = new B();
            C root2 = new C();
            A[] roots = { root1, root2 };
            Class<?>[] interfaces = new Class[] { B.class, C.class };
            // newInstance causes java.lang.ClassFormatError: Duplicate interface
            // name in class file com/mycom/cglib/B$$MixinByCGLIB$$831a43ec
            Mixin mixin = TestMixin.newInstance(interfaces, roots);
            System.out.println("Mixin Object: " + mixin);
            System.out.println(invokeMethod(mixin, "testSomething"));
            System.out.println(invokeMethod(mixin, "isB"));
            System.out.println(invokeMethod(mixin, "getInt"));
        }
    }

【问题讨论】:

  • 发布你用来生成代理的代码。
  • @John 那篇文章没有回答我的问题。这篇文章讨论了如何使用接口实现/模拟多重继承。我的问题是如何动态创建一个代理类,它可以从同一个父类的两个不同子类继承方法。我不想编写任何代码来使用组合来实现。
  • root1root2 是什么?您上面的代码无法编译。
  • 我已经用 root1 和 root2 更新了代码。

标签: java proxy composite cglib


【解决方案1】:

我想你知道 cglib 不能在 Java 中实现多重继承这一事实。 cglib 所做的只是创建一个代理类,它实现了添加到Mixin 生成器的任何(超)类上的所有方法和所有接口。请注意,代理的超类仍然是Object

由于您要添加两个类CB,它们都继承自实现接口I 的类A,因此该接口将被添加两次到实现代理中。但是,这在 Java 中是不允许的,并且在加载类时验证器会抱怨它。 cglib 的想法是:我创建一个实现n 接口的新类,您为我提供n 反馈类,这些类的方法与这些调用将映射到的签名相同。您定义的映射等效于:

  1. IB
  2. IC

但是 cglib 是如何解决这个问题的呢?它只能实现一次接口I。然而,由于Mixin 通过将任何接口方法调用委托给其注册的反馈对象来工作,这并没有多大帮助。该反馈对象应该是您提供的BC 的实例吗? Cglib 无法为您决定这一点,尽管它当然应该为您提供更好的错误消息来解决这种歧义,而不是简单地遵循协议。

顺便说一句,您正在使用内部 cglib Mixin.Generator 来实现您的目的。您应该正式使用公共Mixin#create(Class&lt;?&gt;[], Object[]) 方法。如果您有兴趣,我在how to use cglib 上写了一点。此外,官方 API 允许您决定将哪个接口映射到哪个反馈对象。此外,它还允许您添加其他未映射的接口来实现,以便您的代理可以转换为这种类型。

【讨论】:

  • 感谢 cmets。我不知道 cglib 不能在 Java 中进行多重继承,尽管我在收到错误后猜到了。现在我知道 cglib 不能做我想做的事情。
  • 我将尝试通过编写一个实现 cglib 的 MethodInterceptor 的类来解决这个问题。在拦截方法中,我将尝试通过查看方法的名称并找出哪个对象具有该方法来委托给适当的对象(B 或 C)。如果该方法在 B 和 C 中可用,我会将调用委托给 B 或 C。在我的情况下,这无关紧要,因为 B 和 C 都扩展了 A。
  • 正如您在此主题的其他线程中一样:您为什么需要 cglib?只需实现一个继承自A 的委托器。如果您的答案已解决,请考虑将我的答案标记为已接受。谢谢!
  • 感谢您的宝贵时间。你说的对。我可以只实现一个从 A 继承的委托器,但就我而言,将来可能会添加 A 的其他子类(D 或 E)。所以我希望委托人是动态的。我认为 MethodInterceptor 实现可以查看在运行时调用的方法,并找出 A(B 或 C 或 D)的哪个子类对象具有该方法并委托给它。希望我已经说清楚了。
  • 请注意,这意味着由于反射方法调用而导致性能损失。
猜你喜欢
  • 2017-06-15
  • 2021-07-02
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 2013-07-24
  • 2012-06-02
  • 2013-06-18
  • 1970-01-01
相关资源
最近更新 更多