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?

Was it helpful?

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.

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