2009-10-20 14 views
6

तो, मुझे पता है इसका जवाब शायद है "यह मुश्किल है", लेकिन:जावा: रनटाइम पर प्रकार के नए कार्यान्वयन का निर्माण करें?

मैं एक अजीब विचार मिल गया है, और अगर यह जावा में की तरह एक विधि बनाने के लिए संभव है सोच रहा था:

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

तो मूल रूप से, यदि मेरे इंटरफ़ेस फू ने एक विधि foo() को परिभाषित किया है, तो मैं इस विधि को इस तरह की एक नई कक्षा बनाने के लिए चाहता हूं, जिसने उस वर्ग का एक उदाहरण बनाया है जिसे wrappedObject को कन्स्ट्रक्टर पैरामीटर के रूप में बनाया गया है, और फिर इसे वापस कर दिया गया है :

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

आवेदन मैं सिर्फ कॉल लॉगिंग करने से अधिक जटिल हूं, लेकिन विचार के लिए लॉगिंग पर्याप्त है। मैं इसे बड़ी संख्या में इंटरफ़ेस प्रकारों के साथ करना चाहता हूं, यही कारण है कि मैं हाथ से सभी जेनरेटेड क्लास को नहीं लिखूंगा।

बोनस उन समाधानों के लिए इंगित करता है जिनके लिए अतिरिक्त भाषाई विशेषताओं (AspectJ या उन पंक्तियों के साथ कुछ लाने) की आवश्यकता नहीं होती है, और यदि मानक जेडीके पुस्तकालयों के साथ यह संभव है तो डबल-बोनस-पॉइंट्स की आवश्यकता नहीं होती है।

(मैं एक सटीक, compilable जवाब जरूरत नहीं है,। आदि उपकरण/पुस्तकालयों की सही सेट/कि मुझे ऐसा करते हैं जाएगा करने के लिए सिर्फ एक सूचक)

धन्यवाद!

+0

परावर्तन ('java.lang.Class' सहित) एक अतिरिक्त भाषाई सुविधा है। –

+0

आप [गतिशील प्रॉक्सी कक्षाएं] (http://docs.oracle.com/javase/7/docs/technotes/guides/reflection/proxy.html) में देखना चाहेंगे। –

उत्तर

3

यहां एक बहुत ही सरल कार्यान्वयन है (जो आप करना चाहते हैं उसके लिए काफी अच्छा नहीं है, लेकिन कुछ tweaking के साथ ... मुख्य बात यह है कि वर्ग लोडर मुद्दों होगा, तो कुछ सत्यापन मुद्दों, आदि हो सकता है ।) मैं परीक्षण उद्देश्यों के लिए कोड का उपयोग करता हूं, इसलिए यह वास्तव में उत्पादन गुणवत्ता सामग्री नहीं है।

@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

उत्तर (और नमूना कोड) के लिए धन्यवाद! – Sbodd

1

आपको क्या चाहिए ASM

एएसएम-Guide.pdf से:
2.2.3 उत्पन्न वर्गों
केवल आवश्यक घटक एक वर्ग उत्पन्न करने के लिए ClassWriter घटक है। चलिए इसे चित्रित करने के लिए एक उदाहरण लें।

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

यह छह विधि के साथ एक ClassVisitor करने के लिए कॉल उत्पन्न किया जा सकता: निम्नलिखित इंटरफेस पर विचार करें

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(); 
संबंधित मुद्दे