Skip navigation

Sometimes static code isn't enough and you need to build code dynamically, at run time. That's usually a hefty proposition, but if the code you need to build is just an interface, it's actually relatively simple. Here are some of the reasons you might want to build interfaces at run time and how you might go about it.

Static and dynamic code

The first thing to remember before launching into dynamic code generation is that it is nearly always a much better idea to use static code generation if you can. Static code generation just means writing code as .java files and compiling them with the Java compiler in the usual way. Dynamic code generation means creating code at run time that didn't exist when you compiled your program. Dynamically-created code can often only be run using reflection.

To make the distinction clearer, suppose you have an interface that looks like this:

public interface SomeInterface {
    public void doSomething();
}

If SomeInterface is known at compile time, then you can invoke its doSomething() just by writing Java code:

    SomeInterface object = ...whatever...;
    object.doSomething();

Suppose, though, that your application creates theSomeInterface class at run time. It might do this by writing the code above to a file, invoking the Java compiler on that file, then loading the resultant class. Then your application couldn't contain the code above because SomeInterfacedidn't exist when your application was compiled. So you would have to use reflection instead:

    Class<?> someInterfaceClass =
        Class.forName("SomeInterface", false, someClassLoader);
    ...get an instance of someInterfaceClass somehow...
    Method doSomethingMethod = someInterfaceClass.getMethod("doSomething");
    doSomethingMethod.invoke(instance);

I'm deliberately omitting a lot of detail for the moment. The point is just that the code to invoke the method looks completely different, and a lot more complicated. Hence my advice to avoid dynamic code generation if you can.

The class java.lang.reflect.Proxy

The Java SE platform already contains some support for dynamic code generation, notably in the class java.lang.reflect.Proxy. This class allows you to take any interface and produce a class that implements that interface, where calling any method results in a call to an invoke method that you supply. So for example you could use this to produce a dummy implementation of any interface, where every method just returns null, or where every method throws an exception. Or you could perform some action in every method before calling the same method in a "real" implementation of the same interface, such as logging the method call, performing security checks, or setting a ThreadLocal.

The way Proxy works might be clearer with an example. Suppose you do something like this:

MBeanServer proxy =
    (MBeanServer) Proxy.newProxyInstance(...details omitted..., myHandler);
proxy.registerMBean(someObject, someObjectName);

Then the call to proxy.registerMBean will result in a call like this:

myHandler.invoke(proxy, method, new Object[] {someObject, someObjectName});

where method is a java.lang.reflect.Method representing MBeanServer.registerMBean. This is where you could execute arbitrary code that throws an exception or logs the call or whatever.

Dynamically generating an interface suddenly becomes more interesting in conjunction with this Proxy class. Once we have the interface, we can use Proxy to get an implementation of it.

Dynamic code generation and the JMX API

The JMX API uses reflection heavily. If we can dynamically generate an interface, then we can give that interface to a JMX method that will use reflection on it. Here are a couple of ways we can exploit this.

Recall that a Standard MBean is a Java class that implements an interface called the MBean interface. That interface determines which methods in the class are management methods. When you register an instance of the class with the JMX Agent (MBean Server), these methods can be called by a management client such as JConsole.

Here's an example of an MBean class and its accompanying interface:

public class Cache implements CacheMBean {
    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getUsed() {
        return used;
    }
    ...
}

public interface CacheMBean {
    public int getSize();
    public void setSize(int size);
    public int getUsed();
}

It can be troublesome to maintain two different source files, for the public class Cache and the public interfaceCacheMBean. We often hear people ask for the ability to specify the managed methods with an annotation instead. In other words, to get rid of CacheMBean and instead writeCache like this:

public class Cache {
    @Managed
    public int getSize() {
        return size;
    }

    @Managed
    public void setSize(int size) {
        this.size = size;
    }

    @Managed
    public int getUsed() {
        return used;
    }
    ...
}

How might we implement that?

Model MBeans

One possibility is to use Model MBeans. Model MBeans allow you to link MBean attributes and operations to arbitrary public methods of any class. We could use reflection to pick out the methods with the @Managed annotation, and give these methods to the RequiredModelMBean class to make an MBean out of them.

That's fine as far as it goes, but suppose we want to add a further feature where you can add @Managed to a field and have that field be exposed as a read-only MBean attribute. In other words, we'd replace the getUsed method above with this:

public class Cache {
    @Managed
    private int used;

    @Managed
    public int getSize() {
        return size;
    }

    @Managed
    public void setSize(int size) {
        this.size = size;
    }
    ...
}

RequiredModelMBean allows you to expose public methods of a class, but not fields (public or otherwise). So it is not powerful enough to handle this extension.

Annotation processors

A second possibility is to use an annotation processor to generate an MBean wrapper from theCache class. This wrapper might look something like this:

public interface Cache$WrapperMBean {
    public int getSize();
    public void setSize(int size);
    public int getUsed();
}

public class Cache$Wrapper implements Cache$WrapperMBean {
    private final Cache wrapped;
    private final Field usedField;

    public Cache$Wrapper(Cache wrapped) {
        this.wrapped = wrapped;
        try {
            usedField = Cache.class.getDeclaredField("used");
            usedField.setAccessible(true);
        } catch (Exception e) {
            throw new IllegalArgumentException("Field 'used' inaccessible", e);
        }
    }

    public int getSize() {
        return wrapped.getSize();
    }

    public void setSize(int size) {
        wrapped.setSize(size);
    }

    public int getUsed() {
        try {
            return usedField.getInt(wrapped);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("Field 'used' inaccessible", e);
        }
    }
}

We use reflection to bypass the usual Java language checks that would prevent the generated Cache$Wrapper class from accessing the private used field of theCache class. This is not very good practice in general but is harmless in this particular case because we have explicitly annotated the field to make it happen, and we are only reading the field.

We're still talking about static code generation here, because annotation processors run at compile time.Cache$Wrapper.java andCache$WrapperMBean.java would be generated by the Java compiler via the annotation processor, and immediately compiled.

Dynamically generating the MBean interface

A third possibility, then, is to generate the equivalent of theCache$Wrapper and Cache$WrapperMBeanclasses at run time. That is, when somebody asks to register theCache class, we use reflection to discover the methods and fields that have the @Managed annotation, and we generate the Cache$WrapperMBean interface that we saw above. Once we have this interface, we can use java.lang.reflect.Proxy to produce the equivalent of theCache$Wrapper class.

So how do we go about generating the interface dynamically? There are at least three ways.

  1. Write the Java source code to a file and invoke the Java compiler on that file. You might do this using Runtime.exec, for example. As of Java SE 6, you can use the javax.tools package to invoke the compiler. Strictly speaking though, you're not absolutely guaranteed to find a Java compiler in either case.

  2. Use a standard byte-code generation library, such as Apache BCEL. Pulling in the whole of BCEL just to generate an interface seems a bit like overkill, though.

  3. Generate the byte code yourself. This is usually a major undertaking. But in fact most of the difficulty in generating byte code is involved in generating executable code. Interfaces don't contain any executable code, so it is not unreasonably difficult to generate the byte code for an interface. Plus you get lots of extra Geek Cred, so that's what I'll show here.

Generating the byte code for an interface

(If you're not interested in the details of byte code generation, you'll still need to know how to load the generated class, which is the subject of the next section.)

Before generating byte code, you do need to have an understanding of the class file format. The reference here is Chapter 4 of the Java VM Spec. (There's an update containing the changes needed for Generics, but that doesn't concern us here.)

The main difficulty is that the class file is in two main parts, the constant pool, and "everything else". Everything else here is the class properties (such as its name and superclass) and the contained fields and methods. Every time there is a class name, string, or other constant in this second part, it is actually a reference to the constant pool, as illustrated below.

The class file is in two main parts 

So this means that when generating a class file, you are actually generating two blocks of data in parallel, the constant pool and the rest. Typically this means generating everything in a buffer while recording the constant pool entries, then writing the constant pool followed by the buffer.

Without further ado, let's look at the outline of theInterfaceBuilder class.

public class InterfaceBuilder {
    public static byte[] buildInterface(String name, XMethod[] methods) {...}
}

The idea here is that you callInterfaceBuilder.buildInterface with the name of the interface you want to fabricate and the list of methods you want it to contain. We're using our own class XMethod here rather than java.lang.reflect.Method, because there is no way to fabricate a Method other than to reflect on a class that contains it. In the case of @Managedapplied to the used field above, we want to generate agetUsed() method even though no class contains that method.

The XMethod class is just a tedious wrapper for a bunch of values. Here's the outline.

/**
 * Object encapsulating the same information as a Method but that we can
 * instantiate explicitly.
 */
public class XMethod {
    public XMethod(Method m) {
        this(m.getName(), m.getParameterTypes(), m.getReturnType());
    }

    public XMethod(String name, Class<?>[] paramTypes, Class<?> returnType) {
        this.name = name;
        this.paramTypes = paramTypes;
        this.returnType = returnType;
    }

    public String getName() {
        return name;
    }

    public Class<?>[] getParameterTypes() {
        return paramTypes.clone();
    }

    public Class<?> getReturnType() {
        return returnType;
    }

    // ...define equals, hashCode, toString here...

    private final String name;
    private final Class<?>[] paramTypes;
    private final Class<?> returnType;
}

Now let's look at InterfaceBuilder in more detail. When you call its buildInterface method, it will construct a private instance of InterfaceBuilder that it will use to store the constant pool. We can expand the outline as follows.

public class InterfaceBuilder {
    private static final int CONSTANT_Utf8 = 1, CONSTANT_Class = 7;

    /**
     * Return the byte code for an interface called {@code name} that
     * contains the given {@code methods}.  Every method in the generated
     * interface will be declared to throw {@link Exception}.
     */
    public static byte[] buildInterface(String name, XMethod[] methods) {
        try {
            return new InterfaceBuilder().build(name, methods);
        } catch (IOException e) {
            // we're only writing arrays, so this "can't happen"
            throw new RuntimeException(e);
        }
    }

    private InterfaceBuilder() {
    }

    private byte[] build(String name, XMethod[] methods) throws IOException {
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(bout);

        dout.writeInt(0xcafebabe);     // u4 magic
        dout.writeShort(0);            // u2 minor_version
        dout.writeShort(45);           // u2 major_version (Java 1.0.2)

        byte[] afterConstantPool = buildAfterConstantPool(name, methods);

        writeConstantPool(dout);
        dout.write(afterConstantPool);
        return bout.toByteArray();
    }

    // ...

    private final Map<List<?>, Integer> poolMap =
            new LinkedHashMap<List<?>, Integer>();
    private int poolIndex = 1;
}

This corresponds to the approach described above, where we generate everything into a buffer (afterConstantPool) while recording the constants, then write the constant pool, then write the buffer.

I've somewhat capriciously chosen to write a class file in the format from Java 1.0.2, way back when the Java platform didn't even have reflection. In fact nothing we are going to use has changed in the class file format since then. But you might prefer to use the format from Java 1.n here, in which case you should use 44+n instead of 45 here, for example 48 for Java 1.4.

Now let's take a look at buildAfterConstantPool, which will generate the meat of the class file, and in particular the methods. You might want to have a look at that chapter from the JVM spec in another window if you really want to understand what's going on here.

    private byte[] buildAfterConstantPool(String name, XMethod[] methods)
    throws IOException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        dout.writeShort(Modifier.PUBLIC|Modifier.INTERFACE|Modifier.ABSTRACT);
                                         // u2 access_flags
        dout.writeShort(classConstant(name));
                                         // u2 this_class
        dout.writeShort(classConstant(Object.class.getName()));
                                         // u2 super_class
        dout.writeShort(0);              // u2 interfaces_count
        dout.writeShort(0);              // u2 fields_count

        dout.writeShort(methods.length); // u2 methods_count
        for (int i = 0; i < methods.length; i++) {
            dout.writeShort(Modifier.PUBLIC|Modifier.ABSTRACT);
                                              // u2 access_flags
            dout.writeShort(stringConstant(methods[i].getName()));
                                              // u2 name_index
            dout.writeShort(stringConstant(methodDescriptor(methods[i])));
                                              // u2 descriptor_index
            dout.writeShort(1);               // u2 attributes_count
            dout.writeShort(stringConstant("Exceptions"));
                                                    // u2 attribute_name_index
            dout.writeInt(4);                       // u4 attribute_length:
            dout.writeShort(1);                     // (u2 number_of_exceptions
            dout.writeShort(classConstant(Exception.class.getName()));
                                                    //  + u2 exception_index)
        }

        dout.writeShort(0);              // u2 attributes_count (for class)
        return bout.toByteArray();
    }

We generate the equivalent of athrows Exception clause in each method. This is because if a Proxy handler throws a checked exception that is not declared in the throws clause, the exception will be wrapped in an UndeclaredThrowableException. With a bit more effort we could add the list of exceptions to XMethod and generate it here, but it doesn't seem to be worth that effort.

This method requires a couple of other methods to generate the cryptic codes that are used for method signatures in the class file format.

    private String methodDescriptor(XMethod method) {
        StringBuilder sb = new StringBuilder("(");
        for (Class<?> param : method.getParameterTypes())
            sb.append(classCode(param));
        sb.append(")").append(classCode(method.getReturnType()));
        return sb.toString();
    }

    private String classCode(Class<?> c) {
        if (c == void.class)
            return "V";
        Class<?> arrayClass = Array.newInstance(c, 0).getClass();
        return arrayClass.getName().substring(1).replace('.', '/');
    }

The Array.newInstance business is a simple if extravagant way to get the right type code for every Java type, primitive or otherwise. Due presumably to a historical oversight, the JVM's internal codes leaked out through Class.getName() for array classes. This is usually a pain, but here it proves useful!

Finally, we need to manage the constant pool. There are 11 different types of constant and the obvious approach would be to define an interface or abstract class Constantwith 11 subclasses. However, it turns out that nearly all these types of constant are only needed when generating code. Since we're just generating an interface, we only need two of the types, for strings and class names. So I've used a Lisp-like approach where each constant is represented by a List. The first element of the List is the constant tag, and the rest of the List is the data specific to that tag. A switch statement does the right thing for each tag. (This is not very Objectly Correct. Sue me.)

The constants are stored in a Map so that if the same constant is needed more than once we can reuse it. The use of List for each constant gives us the right behaviour for lookups. A LinkedHashMap ensures that the constants come out in the right order when we iterate through the Map to write the constant pool.

    private int stringConstant(String s) {
        return constant(CONSTANT_Utf8, s);
    }

    private int classConstant(String s) {
        int classNameIndex = stringConstant(s.replace('.', '/'));
        return constant(CONSTANT_Class, classNameIndex);
    }

    private int constant(Object... data) {
        List<?> dataList = Arrays.asList(data);
        if (poolMap.containsKey(dataList))
            return poolMap.get(dataList);
        poolMap.put(dataList, poolIndex);
        return poolIndex++;
    }

    private void writeConstantPool(DataOutputStream dout) throws IOException {
        dout.writeShort(poolIndex);
        int i = 1;
        for (List<?> data : poolMap.keySet()) {
            assert(poolMap.get(data).equals(i++));
            int tag = (Integer) data.get(0);
            dout.writeByte(tag);          // u1 tag
            switch (tag) {
                case CONSTANT_Utf8:
                    dout.writeUTF((String) data.get(1));
                    break;                // u2 length + u1 bytes[length]
                case CONSTANT_Class:
                    dout.writeShort((Integer) data.get(1));
                    break;                // u2 name_index
                default:
                    throw new AssertionError();
            }
        }
    }

    private final Map<List<?>, Integer> poolMap =
            new LinkedHashMap<List<?>, Integer>();
    private int poolIndex = 1;

Loading the generated interface

We now have a byte array containing a class file. How do we go from that to an actual java.lang.Class? This problem is the same whether the byte array came from the code above, or was generated by invoking the compiler, or was created by Apache BCEL.

We're going to need a ClassLoader. The job of a ClassLoader is to take a class name (such ascom.example.Cache$WrapperMBean) and produce the corresponding Class. It can do this by forwarding the request to another ClassLoader or by constructing the Class itself using the defineClass method.

The simplest way to manage this is to write the byte array to a file with the appropriate name, say/tmp/code/com/example/Cache$WrapperMBean.class, and use a URLCLassLoader that can find the file. Something like this:

    OutputStream out =
        new FileOutputStream("/tmp/code/com/example/Cache$WrapperMBean");
    out.write(bytes);
    out.close();

    URL codeDir = new File("/tmp/code").toURI().toURL();
    ClassLoader loader = new URLClassLoader(new URL[] {codeDir});
    Class<?> c =
        Class.forName("com.example.Cache$WrapperMBean", false, loader);

But in fact it is not much harder to create your own ClassLoader that directly fabricates and loads the byte code without requiring any files:

public class InterfaceClassLoader extends ClassLoader {
    public InterfaceClassLoader(ClassLoader parent) {
        super(parent);
    }
    
    public Class<?> findOrBuildInterface(String name, XMethod[] methods) {
        Class<?> c;
        c = findLoadedClass(name);
        if (c != null)
            return c;
        byte[] classBytes = InterfaceBuilder.buildInterface(name, methods);
        return defineClass(name, classBytes, 0, classBytes.length);
    }
}

MBeans from annotations

We now have nearly everything we need in order to be able to build MBeans from @Managed annotations. A reminder that given a class like this...

public class Cache {
    @Managed
    public int getSize() {
        return size;
    }

    @Managed
    public void setSize(int size) {
        this.size = size;
    }

    @Managed
    public int getUsed() {
        return used;
    }
    ...
}

...we want to build a Standard MBean interface like this...

public interface Cache$WrapperMBean {
    public int getSize();
    public void setSize(int size);
    public int getUsed();
}

...and implement that interface to make a Standard MBean that we can register in the MBean Server. Rather than generating a classCache$Wrapper that implementsCache$WrapperMBean, following the Standard MBean conventions, we're going to create a java.lang.reflect.Proxy. We can't make the class name of the proxy beCache$Wrapper, but the class javax.management.StandardMBean exists for when the class name and the interface name don't match.

The class MBeanBuilder can be used to make MBeans in this way. The usage is similar to this:

    ClassLoader thisLoader = this.getClass().getClassLoader();
    MBeanBuilder builder = new MBeanBuilder(thisLoader);
    ...
    Object cacheMBean = builder.buildMBean(cache);
    ObjectName cacheMBeanName = ...;
    mbeanServer.registerMBean(cacheMBean, cacheMBeanName);

For best results, when a class constructs anMBeanBuilder it should supply its ownClassLoader as argument, as shown here.

Here's what MBeanBuilder looks like:

public class MBeanBuilder {
    private final InterfaceClassLoader loader;

    public MBeanBuilder(ClassLoader parentLoader) {
        loader = new InterfaceClassLoader(parentLoader);
    }

    public StandardMBean buildMBean(Object x) {
        Class<?> c = x.getClass();
        Class<?> mbeanInterface = makeInterface(c);
        InvocationHandler handler = new MBeanInvocationHandler(x);
        return makeStandardMBean(mbeanInterface, handler);
    }

    private static <T> StandardMBean makeStandardMBean(Class<T> intf,
                                                       InvocationHandler handler) {
        Object proxy =
                Proxy.newProxyInstance(intf.getClassLoader(),
                                       new Class<?>[] {intf},
                                       handler);
        T impl = intf.cast(proxy);
        try {
            return new StandardMBean(impl, intf);
        } catch (NotCompliantMBeanException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private Class makeInterface(Class implClass) {
        String interfaceName = implClass.getName() + "$WrapperMBean";
        try {
            return Class.forName(interfaceName, false, loader);
        } catch (ClassNotFoundException e) {
            // OK, we'll build it
        }
        Set<XMethod> methodSet = new LinkedHashSet<XMethod>();
        for (Method m : implClass.getMethods()) {
            if (m.isAnnotationPresent(Managed.class))
                methodSet.add(new XMethod(m));
        }
        if (methodSet.isEmpty()) {
            throw new IllegalArgumentException("Class has no @Managed methods: "
                    + implClass);
        }
        XMethod[] methods = methodSet.toArray(new XMethod[0]);
        return loader.findOrBuildInterface(interfaceName, methods);
    }
}

The first time it sees a given class, such ascom.example.Cache, it will generate an interface,com.example.Cache$WrapperMBean. Every other time, it will reuse the previously-generated interface.

The @Managed annotation is defined like this:

@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
public @interface Managed {
}

In this version, we don't allow @Managed on fields. That's certainly possible, but would complicate the code considerably.

The MBeanInvocationHandler used in the constructed Proxy looks like this:

public class MBeanInvocationHandler implements InvocationHandler {
    public MBeanInvocationHandler(Object wrapped) {
        this.wrapped = wrapped;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
        Class<?> wrappedClass = wrapped.getClass();
        Method methodInWrapped =
            wrappedClass.getMethod(method.getName(), method.getParameterTypes());
        try {
            return methodInWrapped.invoke(wrapped, args);
        } catch (InvocationTargetException e) {
            throw e.getCause();
        }
    }
    
    private final Object wrapped;
}

That's everything you need! I've collected the various classes into a zip file for convenience.

MXBean mappings

Another possible application of dynamic interface generation appears in Java SE 6 with the addition of MXBeansto the platform. MXBeans map arbitrary Java types to a fixed set of types, the so-called Open Types defined in javax.management.openmbean. But the MXBean framework operates on MXBean interfaces, not on individual types. It sometimes happens that you need to find out the mapping for a certain type.

If you know the type at compile time, you can just put it in an interface, create an MXBean that implements that interface. Suppose you want to know the mapping for java.lang.management.MemoryUsage, for example. Then you can create an interface like this...

public interface MemoryUsageTestMXBean {
    public MemoryUsage getMemoryUsage();
    public void setMemoryUsage(MemoryUsage x);
}

...and implement it like this...

public class MemoryUsageTest implements MemoryUsageTestMXBean {
    volatile MemoryUsage memoryUsage;

    public MemoryUsage getMemoryUsage() {
        return memoryUsage;
    }

    public void setMemoryUsage(MemoryUsage x) {
        memoryUsage = x;
    }
}

Then you can make an MXBean like this...

MemoryUsageTest memoryUsageTest = new MemoryUsageTest();
StandardMBean mxbean =
    new StandardMBean(memoryUsageTest, MemoryUsageTestMXBean.class, true);

...and use it like this...

// Discover the OpenType that MemoryUsage is mapped to
MBeanAttributeInfo ai = mxbean.getMBeanInfo().getAttributes()[0];
assert(ai.getName().equals("MemoryUsage");
OpenType<?> memoryUsageOpenType = (OpenType<?>)
    ai.getDescriptor().getFieldValue("openType");

// Convert a MemoryUsage into a value of this Open Type
MemoryUsage mu = ...something...;
memoryUsageTest.memoryUsage = mu;
Object openValue = mxbean.getAttribute("MemoryUsage");

// Convert a value of the Open Type back into a MemoryUsage
mxbean.setAttribute(new Attribute("MemoryUsage", openValue));
mu = memoryUsageTest.memoryUsage;

We can make this work for an arbitrary type discovered at run time, by generating the equivalent of theMemoryUsageTestMXBean for the type in question. The code below shows this.

public class MXBeanMapper {
    private final StandardMBean mxbean;
    private final MXBeanInvocationHandler handler;

    public MXBeanMapper(Class<?> originalType) {
        InterfaceClassLoader loader =
                new InterfaceClassLoader(originalType.getClassLoader());
        XMethod getter = new XMethod("getX", new Class<?>[0], originalType);
        XMethod setter = new XMethod("setX", new Class<?>[] {originalType},
                                     void.class);
        Class<?> mxbeanInterface =
            loader.findOrBuildInterface("X", new XMethod[] {getter, setter});

        handler = new MXBeanInvocationHandler();
        mxbean = makeMXBean(mxbeanInterface, handler);
    }

    private static <T> StandardMBean makeMXBean(Class<T> intf,
                                                InvocationHandler handler) {
        Object proxy =
                Proxy.newProxyInstance(intf.getClassLoader(),
                                       new Class<?>[] {intf},
                                       handler);
        T impl = intf.cast(proxy);
        return new StandardMBean(impl, intf, true);
    }

    public OpenType<?> getOpenType() {
        MBeanAttributeInfo ai = mxbean.getMBeanInfo().getAttributes()[0];
        assert(ai.getName().equals("X"));
        return (OpenType<?>) ai.getDescriptor().getFieldValue("openType");
    }

    public synchronized Object toOpenValue(Object javaValue) {
        handler.javaValue = javaValue;
        try {
            return mxbean.getAttribute("X");
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }

    public synchronized Object fromOpenValue(Object openValue) {
        try {
            mxbean.setAttribute(new Attribute("X", openValue));
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
        return handler.javaValue;
    }

    private static class MXBeanInvocationHandler implements InvocationHandler {
        volatile Object javaValue;

        public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
            if (method.getName().equals("getX"))
                return javaValue;
            else if (method.getName().equals("setX")) {
                javaValue = args[0];
                return null;
            } else
                throw new AssertionError("Bad method name " + method.getName());
        }
    }
}

Conclusions

Generating interfaces is possible and allows us to solve some interesting problems. This is especially true for APIs like the JMX API that use reflection heavily.

The source code for the classes above is in this zip file, with the exception of MXBeanMapper.java, which I separated because it requires the Java SE 6 platform.