Java: create a new type implementation at runtime?

So, I understand that the answer to this is probably β€œit's complicated,” but:

I have a strange idea, and I was wondering if it is possible to create a method in Java such as:

<T> T wrapInterface (Class<T> interfaceClass, T wrappedObject) { if (mClass.isInterface()) { //create a new implementation of interfaceClass that, in each method, //does some action before delegating to wrappedObject return thatImplementation; } } 

Basically, if my Foo interface defined the foo () method, I would like this method to create a new class that looks something like this, instantiate this class with wrappedObject as a constructor parameter, and then return this:

 public class GeneratedClass implements Foo { private Foo wrapped; public GeneratedClass (Foo wrapped) { this.wrapped = wrapped; } @Override public void foo () { System.out.println("Calling Foo.foo() on wrapped object " + wrapped.toString()); wrapped.foo(); } } 

The application that I am considering is more complex than just writing to a log, but a log is enough for this idea. I would like to do this with a lot of interface types, so I would not just write all the GeneratedClasses manually.

Bonus points for a solution that does not require additional linguistic functions (bringing AspectJ or something like that) and double bonus points, if this is possible only using standard JDK libraries.

(I don’t need an exact compiled answer, just a pointer to the necessary toolboxes / libraries / etc that would allow me to do this.)

Thanks!

+6
java interface code-generation wrapping
source share
2 answers

Here is a very simplified implementation (the probability of what you want to do, but with some tweaking is not good enough ... The main thing to look at will be problems with loading classes, then some problems with validation may occur, etc.) I use the code for testing purposes, so this is not entirely quality material.

  @SuppressWarnings("unchecked") public static <T> T generateProxy(Object realObject, Class<?>... interfaces) { return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject)); } private static class SimpleInvocationHandler implements InvocationHandler { private Object invokee; public SimpleInvocationHandler(Object invokee) { this.invokee = invokee; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes()); if (!method.isAccessible()) { method.setAccessible(true); } try { return method.invoke(invokee, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } 
+3
source share

You need ASM .

From asm-guide.pdf:
2.2.3 Creating classes
The only necessary component for creating a class is the ClassWriter component. Let's illustrate this with an example. Consider the following interface:

 package pkg; public interface Comparable extends Mesurable { int LESS = -1; int EQUAL = 0; int GREATER = 1; int compareTo(Object o); } 

It can be generated using six calls to the ClassVisitor method:

 ClassWriter cw = new ClassWriter(0); cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Comparable", null, "java/lang/Object", new String[] { "pkg/Mesurable" }); cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I", null, new Integer(-1)).visitEnd(); cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I", null, new Integer(0)).visitEnd(); cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I", null, new Integer(1)).visitEnd(); cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo", "(Ljava/lang/Object;)I", null, null).visitEnd(); cw.visitEnd(); byte[] b = cw.toByteArray(); 
+1
source share

All Articles