0

I'm writing an application which requires the dynamic implementation of an interface. I had no (obvious) issues regarding generating the class: I verified it with both javap and a decompiler.

The problem is, after I generate the class I define and instantiate. Finally, I cast it to the type of the implemented interface.

The problem is that I am being hit with a java.lang.ClassCastException: MyGeneratedClass cannot be cast to MyInterface, though I do add MyInterface as an interface when I call ClassWriter.visit.

Below is an SSCCE demonstrating the issue for an interface named MyInterface full of void methods.

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

cw.visit(V1_6,
        ACC_PUBLIC | ACC_SUPER,
        "MyGeneratedClass",
        null,
        "java/lang/Object",
        new String[]{MyInterface.class.getName().replace(".", "/"});

{
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL,
            "java/lang/Object",
            "<init>",
            "()V");
    mv.visitInsn(RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}

for (Method call : MyInterface.class.getDeclaredMethods()) {
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, call.getName(), Type.getMethodDescriptor(call),  null, null);
    // ...
    mv.visitInsn(RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}
cw.visitEnd();
byte[] raw = cw.toByteArray();

try {
    return (MyInterface) new ClassLoader() {
        public Class defineClass(byte[] bytes) {
            return super.defineClass("MyGeneratedClass", bytes, 0, bytes.length);
        }
    }.defineClass(raw).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
    return null;
}

Printing out the generatedObject.getClass().getInterfaces() does indeed show that MyInterface is implemented. But generatedObject instanceof MyInterface returns false, something which I find a contradiction.

Can anyone shed some light on whats happening here? Any help would be greatly appreciated.

1 Answer 1

4

I'd guess it's because the new classloader isn't a child of the classloader that loaded MyInterface, which means you end up with two different classes which aren't the same despite being to all appearances identical. Try changing

return (MyInterface) new ClassLoader() {

to

return (MyInterface) new ClassLoader(MyInterface.class.getClassLoader()) {
Sign up to request clarification or add additional context in comments.

2 Comments

That did it, thanks. Looking back it seems glaringly obvious that the class wouldn't be visible to the system classloader. Thanks again!
Remember: a class is defined by it's FQCN and the classloader it came from!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.