2009-10-20 14 views
6

So merke ich, die Antwort auf diese wahrscheinlich ist „es ist hart“, aber:Java: neue Implementierung des Typs zur Laufzeit erstellen?

Ich habe eine seltsame Idee, und frage mich, ob es in Java möglich ist wie ein Verfahren zu schaffen:

<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; 
    } 
} 

Also, wenn meine Schnittstelle Foo eine Methode foo() definiert, möchte ich, dass diese Methode eine neue Klasse erstellt, die ungefähr so ​​aussieht, eine Instanz dieser Klasse mit WrappedObject als Konstruktorparameter erstellt und dann zurückgegeben hat :

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(); 
    } 
} 

Die Anwendung Ich denke, ist komplizierter als nur den Anruf zu protokollieren, aber Protokollierung ist ausreichend für die Idee. Ich würde das gerne mit einer großen Anzahl von Schnittstellentypen machen, weshalb ich nicht alle GeneratedClasses von Hand schreiben würde.

Bonuspunkte für eine Lösung, die keine extralinguistischen Funktionen erfordert (AspectJ oder ähnliches) und doppelte Bonuspunkte, wenn dies nur mit den Standard-JDK-Bibliotheken möglich ist.

(Ich brauche keine präzise, ​​übersetzbar Antwort,. Nur einen Zeiger auf den richtigen Sätze von Tools/Bibliotheken/etc, die mich das tun lassen würde)

Dank!

+0

Reflection (einschließlich 'java.lang.Class') ist eine außersprachliche Funktion. –

+0

Sie können sich [dynamische Proxy-Klassen] (http://docs.oracle.com/javase/7/docs/technotes/guides/reflection/proxy.html) ansehen. –

Antwort

3

Hier ist eine sehr einfache Implementierung (nicht gut genug wahrscheinlich für das, was Sie tun möchten, aber mit ein paar Optimierungen ... Die Hauptsache wäre Klassenlade Probleme, dann könnte es einige Validierungsprobleme, etc .) Ich benutze den Code für Testzwecke, es ist also nicht genau Produktionsqualität.

@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(); 
      } 
     } 
    } 
+0

Danke für die Antwort (und den Beispielcode)! – Sbodd

1

Was Sie brauchen, ist ASM.

Von asm-guide.pdf:
2.2.3 Generieren von Klassen
Die einzige erforderliche Komponente eine Klasse zu erzeugen, ist die ClassWriter Komponente. Nehmen wir ein Beispiel, um dies zu veranschaulichen. Betrachten Sie die folgende Schnittstelle:

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

Es erzeugt werden kann, mit sechs Verfahren auf ein ClassVisitor ruft:

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(); 
Verwandte Themen