Interface mittels Reflection implementieren

Status
Nicht offen für weitere Antworten.

rapthor

Bekanntes Mitglied
Hallo,

ich weiß nicht, ob der Titel überhaupt mit dem übereinstimmt, was ich suche. Ich will eine Methode schreiben, die als Argument ein Interface bekommt. Dieses Interface möchte ich nun innerhalb des Methodenkörpers implementieren. Etwa so:

Code:
public Class getImplementation(Class interface)
{
        return new  ........ ??
}

Wie bewekrstellige ich diese Funktionalität mittels Reflection?

Danke im Voraus,
Rapthor
 
*kratzamkopf*

Ich wüsste nicht, dass das in Java geht. Wäre wohl eher was für Smalltalk...

Darf man fragen warum du meinst sowas zu benötigen und wozu es gut sein soll?
 
AlArenal hat gesagt.:
*kratzamkopf*

Ich wüsste nicht, dass das in Java geht. Wäre wohl eher was für Smalltalk...

Darf man fragen warum du meinst sowas zu benötigen und wozu es gut sein soll?

Der Vorschlag eine Factory zu bauen und darin ein Interface zu einer Implementierung zu machen, habe ich von einem Apache Projekt für XML RPC. Auf einem Server existieren bestimmte Methoden, die ausgeführt werden können. Das Interface beschreibt diese Methoden. Der Client erhält nur das Interface und in dessen Implementierung findet der Kontakt zum Server statt.

Das Ganze ist nicht so wichtig zu verstehen. Es wird klarer, wenn man sich folgende Beschreibung von Apache ansieht:

The factory can take an interface as input and returns an implementation, which internally calls the server by using the XmlRpcClient.

Perhaps some code shows more than words. First of all, let's create a request processor interface.

Code:
    package com.foo;

    public interface Adder {
      public int add(int pNum1, int pNum2);
    }

The server contains the request processors implementation:

Code:
    package com.foo;

    public class AdderImpl implements Adder {
      public int add(int pNum1, int pNum2) {
        return pNum1 + pNum2;
      }
    }

And here is how the client would use this:

Code:
    import com.foo.Adder;
    import org.apache.xmlrpc.client.XmlRpcClient;
    import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
    import org.apache.xmlrpc.client.util.ClientFactory;

    XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
    config.setServerUrl("http://127.0.0.1:8080/xmlrpc");
    XmlRpcClient client = new XmlRpcClient();
    client.setConfig(config);
    ClientFactory factory = new ClientFactory(client);
    //hier ist der Knackpunkt !!!!
    Adder adder = (Adder) factory.newInstance(Adder.class);
    // da war der Knackpunkt
    int sum = adder.add(2, 4);

Im letzten Ausschnitt zwischen den Kommentaren ist das, woran ich gerade arbeite .... es interessiert mich, wie ich das umsetzen könnte.

Oder habe ich einen gänzlich falschen Ansatz gewählt?
 
normalerweise generieren solche Tools doch wohl neue .java-Dateien und kompilieren die,
kenn ich zwar nicht zur Laufzeit mit Factory, aber so werden doch Stubs aus WSDL-Beschreibungen usw. erstellt,

also in deinem Fall vielleicht Datei schreiben, kompilieren und instanziieren
 
wie gesagt, guck dir mal javassist an... damit kann man zur Laufzeit Quellcode kompilieren und ausführen lassen... benutzen wir hier, um Java-Ausdrücke in einer eigenen Sprache in tatsächliche Java-Methoden zu überführen, die dann ausgewertet werden... - damit sollte auch obiges machbar sein, da du ja tatsächlich reflektiv quellcode generieren möchtest und am Ende eine Quasi-Stub-Klasse dem Interface entsprechend willst... diese injiziert dann vermutlich Methoden von wo ganz anders? Evtl. ne entsprechende Remote-Verbindung?
Wie Slater schon sagte, ist der übliche Weg für sowas eigentlich aus den Interfaces entsprechende Stub und Skelleton-Klassen zu erzeugen, die den Zugriff auf ein Remote oder Home-Interface ermöglichen... diese werden aber vorher generiert aus einem übergebenen Interface... z.B. in IDL bei Corba oder WSDL... etc.
 
Wie wär's mit einem Proxy?
Code:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyExample
{
   static interface MyInterface
   {
      public void a();
      public void b();
      public void c();
   }
   
   private static Object implement(Class clazz)
   {
      return Proxy.newProxyInstance(
         clazz.getClassLoader(), 
         new Class[]{ clazz }, 
         new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
            {
               System.out.println(method.getName());
               return null;
            }
         }
      );
   }
   
   public static void main(String[] args)
   {
      MyInterface intf = (MyInterface)implement(MyInterface.class);
      intf.a();
      intf.b();
      intf.c();
   }
}
 
Alles klar, ich sehe es ein. Es geht wohl nicht ohne Code Generierung. Ich muss mal sehen, dass ich das auf eine andere Art und Weise löse.

Danke euch beiden.
 
Jetzt habe ich doch noch eine einfachere Lösung gefunden:

"java.lang.reflect.Proxy" ermöglicht es mir ein Interface zu übergeben, das ich mittels InvocationHandler implementieren kann. Hier ist eine konkrete Anwendung dazu, wie ich sie umgesetzt habe:

Code:
/*
 * Factory to retrieve RPC handlers from interfaces. You must provide a valid XMLRPCClient to the constructor.
 * After calling createHandler() cast the resulting object to the interface you provided. 
 */
public class RPCHandlerFactory
{
	private InvocationHandler invocationHandler;
	private Map<String, Object> handlerImplementations;
	
	public RPCHandlerFactory(final XmlRpcClient client)
	{
		// Map storing implementations for faster access.
		handlerImplementations = new HashMap<String, Object>();
		
		invocationHandler = new InvocationHandler()
		{
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
			{
				return client.execute(method.getDeclaringClass().getSimpleName() + "." + method.getName(), args);
			}
		};		
	}
	
	public Object createHandler(Class handlerInterface)
	{
		// Look for implementation in the map, caused by former calls. 
		Object handlerImplementation = handlerImplementations.get(handlerInterface.toString());
 
		if (handlerImplementation != null)
			return handlerImplementation;
		
		Class proxyClass = Proxy.getProxyClass(handlerInterface.getClassLoader(), new Class[] { handlerInterface });
		
		try
		{
			handlerImplementation = proxyClass
			.getConstructor(new Class[] { InvocationHandler.class })
			.newInstance(new Object[] { invocationHandler });
		}
		catch (....)
		{
			....
		}		
		// Put implementation into map for faster access next time.
		if (handlerImplementation != null)
			handlerImplementations.put(handlerInterface.toString(), handlerImplementation);
		
		return handlerImplementation;
	}
}
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben