Question

I need to generate an interface at runtime. This interface will be used in a dynamic proxy. At first, I found this article from Google, but then I found I could just use ASM instead. Here is my code that gets the bytecode of the interface:

private static byte[] getBytecode(String internalName, String genericClassTypeSignature, Method[] methods, Class<?>... extendedInterfaces) throws IOException {
    ClassWriter cw = new ClassWriter(0);
    String[] interfaces = new String[extendedInterfaces.length];
    int i = 0;
    for (Class<?> interfac : extendedInterfaces) {
        interfaces[i] = interfac.getName().replace('.', '/');
        i++;
    }
    cw.visit(V1_6, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, internalName, null, "java/lang/Object", interfaces);
    ArrayList<String> exceptions = new ArrayList<String>();
    for (Method m : methods) {
        exceptions.clear();
        for (Class<?> exception : m.getExceptionTypes()) {
            exceptions.add(getInternalNameOf(exception));
        }
        cw.visitMethod(removeInvalidAbstractModifiers(m.getModifiers()) + ACC_ABSTRACT, m.getName(), getMethodDescriptorOf(m), getTypeSignatureOf(m), exceptions.toArray(new String[exceptions.size()]));
    }
    cw.visitEnd();
    return cw.toByteArray();
}

private static int removeInvalidAbstractModifiers(int mod) {
    int result = 0;
    if (Modifier.isProtected(mod)) {
        result += ACC_PROTECTED;
    }
    if (Modifier.isPublic(mod)) {
        result += ACC_PUBLIC;
    }
    if (Modifier.isTransient(mod)) {
        result += ACC_VARARGS;
    }
    return result;
}

Just for test purposes, I tried to convert JFrame to an interface. But when I load my generated interface, it gives me a java.lang.ClassFormatError:

java.lang.ClassFormatError: Method paramString in class javax/swing/JFrame$GeneratedInterface has illegal modifiers: 0x404
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
    // ...

Modifier.toString(0x404) tells me that 0x404 means protected abstract. As far as I know, a protected abstract method in an abstract class is perfectly legal.

Here is the code for the paramString method (see above) in JFrame:

/**
 * Returns a string representation of this <code>JFrame</code>.
 * This method
 * is intended to be used only for debugging purposes, and the
 * content and format of the returned string may vary between
 * implementations. The returned string may be empty but may not
 * be <code>null</code>.
 *
 * @return  a string representation of this <code>JFrame</code>
 */
protected String paramString() {
    String defaultCloseOperationString;
    if (defaultCloseOperation == HIDE_ON_CLOSE) {
        defaultCloseOperationString = "HIDE_ON_CLOSE";
    } else if (defaultCloseOperation == DISPOSE_ON_CLOSE) {
        defaultCloseOperationString = "DISPOSE_ON_CLOSE";
    } else if (defaultCloseOperation == DO_NOTHING_ON_CLOSE) {
        defaultCloseOperationString = "DO_NOTHING_ON_CLOSE";
    } else if (defaultCloseOperation == 3) {
        defaultCloseOperationString = "EXIT_ON_CLOSE";
    } else defaultCloseOperationString = "";
    String rootPaneString = (rootPane != null ?
                             rootPane.toString() : "");
    String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ?
                                            "true" : "false");

    return super.paramString() +
    ",defaultCloseOperation=" + defaultCloseOperationString +
    ",rootPane=" + rootPaneString +
    ",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString;
}

I see no reason why I should be getting this error. Could someone explain this to me?

Était-ce utile?

La solution

Methods in an interface must be public.

Also, in your removeInvalidAbstractModifiers() method, you should be using |= to set a flag, rather than +=. The latter will cause problems if the flag is already set (which I realize it won't be if starting from 0, but it's a good habit to get into). Although why you're setting the flag in a method called "remove," I have no idea.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top