2014-01-09 3 views
0

Я пишу приложение, которое требует динамической реализации интерфейса. У меня не было (очевидных) проблем в отношении создания класса: я проверил его как с javap, так и с декомпилятором.Внедрить интерфейс с ASM: ClassCastException

Проблема заключается в том, что после создания класса я определяю и создаю экземпляр. Наконец, я применил его к типу реализованного интерфейса.

Проблема в том, что меня поражают java.lang.ClassCastException: MyGeneratedClass cannot be cast to MyInterface, хотя я добавляю MyInterface в качестве интерфейса, когда я звоню ClassWriter.visit.

Ниже приведен SSCCE, демонстрирующий проблему для интерфейса с именем MyInterface, полным методов void.

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; 
} 

распечатав generatedObject.getClass().getInterfaces() действительно показывают, что MyInterface реализуется. Но generatedObject instanceof MyInterface возвращает false, то, что я нахожу противоречие.

Может ли кто-нибудь пролить свет на то, что здесь происходит? Любая помощь будет принята с благодарностью.

ответ

4

Я предполагаю, что это связано с тем, что новый загрузчик классов не является потомком загрузчика классов, загружаемого MyInterface, что означает, что вы получаете два разных класса, которые не совпадают, несмотря на то, что они выглядят одинаково. Попробуйте изменить

return (MyInterface) new ClassLoader() { 

в

return (MyInterface) new ClassLoader(MyInterface.class.getClassLoader()) { 
+0

Это сделал это, спасибо. Оглядываясь назад, кажется очевидным, что класс не будет виден системному загрузчику. Еще раз спасибо! – Xyene

+1

Помните: класс определяется его FQCN и загрузчиком классов, из которого он пришел! –

Смежные вопросы