Question

I have class 'A' that implements interface 'I'. I have two classes 'B' and 'C', each extends A and adds a new method. C and B do not override any method in A. The new method in Class 'B' has a signature different from that of 'C' and the new method is the only difference between C and B. I need to create a Proxy (sort of composite of objects of 'B' and 'C') that should have all the methods of A and the new methods in 'B' and 'C'.

I tried to use Mixin$Generator in CGLIB to create a composite proxy but I get Error "java.lang.ClassFormatError: Duplicate interface name in class file".

Has anyone encountered a similar situation? Any suggestions for solving this issue?

Thanks for your time.

Here is the code updated with the interface and all the classes.

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"));
        }
    }
Was it helpful?

Solution

I guess you are aware of the fact that cglib cannot make multiple inheritence happen in Java. All that cglib does is creating a proxy class which implements all the methods and all the interfaces found on any (super)class that is added to the Mixin generator. Note that the super class of the proxy will still Object.

Since you are adding two classes C and B which both inherit from class A which implements interface I, this interface will be added twice to the implementing proxy. However, this is not allowed in Java and the verifier will complain about it when the class is loaded. The idea of cglib is: I create a new class implementing n interfaces and you provide me n feedback classes with methods of the same signature to which these calls will be mapped. You defined a mapping equivalent to:

  1. I to B
  2. I to C

But how could cglib solve this problem? It could implement interface I only once. However, since the Mixin works by delegating any interface method calls to its registered feedback objects, thiis would not help much. Should this feedback object be the instance of B or of C that you provided? Cglib cannot decide this for you, even though it should of course give you a better error message over this ambiguity instead of plainly following the protocol.

By the way, you are using the internal cglib Mixin.Generator for your purposes. You are officially supposed to use the public Mixin#create(Class<?>[], Object[]) method. I wrote a little bit on how to use cglib, if you are interested. Also, the official API allows you to decide which interface is mapped to which feedback object. Furthermore, it allows you to add additional, unmapped interfaces to implement such that your proxy can be casted to this type.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top