0

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"));
        }
    }
Kannan
  • 15
  • 7
  • Post the code you are using to generate the proxy. – Sotirios Delimanolis Jan 29 '14 at 16:56
  • This has been answered before. http://stackoverflow.com/q/5003285/3224483 http://stackoverflow.com/q/3556652/3224483 – Rainbolt Jan 29 '14 at 17:10
  • @John That post does not answer my question. The post discusses how to implement/simulate multiple inheritance using interfaces. My question is how to create dynamically a proxy class that can inherit methods from two different subclasses of the same parent class. I do not want to write any code to accomplish that using composition. – Kannan Jan 29 '14 at 18:31
  • What are `root1` and `root2`? Your above code does not compile. – Rafael Winterhalter Jan 30 '14 at 07:55
  • I have updated the code with root1 and root2. – Kannan Jan 30 '14 at 17:07

1 Answers1

1

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.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Thanks for the comments. I was not aware that cglib cannot make multiple inheritance happen in Java though I guessed it after I got the error. Now I get that cglib cannot do what I am trying to do. – Kannan Jan 30 '14 at 17:48
  • I will try to solve this by writing a class that implements MethodInterceptor of cglib. In the intercept method, I will try to delegate to the appropriate object (B or C) by looking at the name of the method and finding which object has the method. If the method is available in B and C, I will delegate the call to B or C. In my case it does not matter since both B and C extend A. – Kannan Jan 30 '14 at 17:54
  • As in your other thread on this topic: Why do you need cglib for that? Just implement a delegator that inherits from `A`. If your answer is solved, consider marking my answer as accepted. Thanks! – Rafael Winterhalter Jan 31 '14 at 13:03
  • Thanks for your time. You are right. I can just implement a delegator that inherits from A but in my case, other subclasses of A (D or E) may be added in future. So I want the delegator to be dynamic. I think a MethodInterceptor implementation can look at the method being invoked at runtime and figure out which subclass object of A (B or C or D) has the method and delegate to it. Hope I have made it clear. – Kannan Feb 02 '14 at 02:04
  • Be aware that this implies a performance penalty due to the reflective method invocation. – Rafael Winterhalter Feb 02 '14 at 09:09