It is indeed possible to create such class files via byte-code manipulation. Here is an example program which does this using the ASM library:
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.objectweb.asm.*;
public class EnumHack {
interface Foo {
public void bar();
}
enum MyEnum {
A {
public void bar() {
System.out.println("Hello!");
}
},
B,
C;
}
public static void main(String... arg) {
try {
patch();
} catch (IOException|URISyntaxException ex) {
System.err.println("patching failed: "+ex);
return;
}
test();
}
static void test() {
for(MyEnum e: MyEnum.values()) {
System.out.println(e.name());
if (e instanceof Foo) {
System.out.println("\timplements Foo");
((Foo)e).bar();
}
}
}
static void patch() throws IOException, URISyntaxException {
URL url = MyEnum.class.getResource("EnumHack$MyEnum$1.class");
ClassReader cr=new ClassReader(url.openStream());
ClassWriter cw=new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
if(interfaces.length==0) // not patched yet
interfaces=new String[] { Foo.class.getName() };
super.visit(version, access, name, signature, superName, interfaces);
}
}, 0);
Files.write(Paths.get(url.toURI()), cw.toByteArray());
}
}
It prints
A
implements Foo
Hello!
B
C
When running under Oracles’s Java 8 with the class files residing in the file system. When running under different JVMs or bundled in a Jar file writing back the modified class file may fail or the enum
might have been loaded eagerly and not reflect the modification (but it would on the next run then).
But it shows that generally, that byte-code manipulation is possible and when performed before starting the application, it will work even in the more complicated scenarios.
Still, I see this only as an interesting fun hack, but nothing you should build applications on. There is no problem this hack will solve that you couldn’t solve using a delegation object which implements the interface…