Reflection - wie kann ich eine Methode benutzen

Status
Nicht offen für weitere Antworten.

y0dA

Top Contributor
Hi!
Ich versuche gerade ein externes Jar nachzuladen, nachladen dürfte funktionieren, jedoch gibt es wohl Verständnisprobleme wie ich nun eine Methode einer nachgeladenen Klasse benutzen kann.

Code:
public void loadExternalLibary() {
		try {
			URL jarURL = new File(this.path + this.jar).toURL();
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			
			if (classLoader != null && (classLoader instanceof URLClassLoader)) {
				URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
				 Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
				 addURL.setAccessible(true);
				 addURL.invoke(urlClassLoader, new Object[]{jarURL});
				 
				 Class tempClass = classLoader.loadClass(this.className);
				 /* check if class really implements needed interface */
				 Class[] interfaceArray = tempClass.getInterfaces();
				 for (int i = 0; i < interfaceArray.length; i++) {
					 if (interfaceArray[i].equals(ITrackParser.class)) {
						 /* external class implements needed interface */
						 this.c = tempClass;
						 break;
					 }
				 }
				 if (this.c == null) {
					 throw new Exception("external class " + this.className + " does not implement needed "
							 + ITrackParser.class);
				 }	
				 
				 final String hh =
						"C:\\work\\projects\\StreetDetection\\src\\main\\resources\\files\\20071207_1sekunde.LOG";
				 
				 Class[] parameterTypes = new Class[] {String.class};
				 Method m = this.c.getMethod("getReceiverId");
				 String ss = (String) m.invoke(this.c);

			}
Hier bekomme ich bei invoke eine Exception:
Code:
java.lang.IllegalArgumentException: object is not an instance of declaring class
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.pcd.wam.gegenstandsbereich.streetDetection.locating.controller.OfflineProcessor.loadExternalLibary(OfflineProcessor.java:117)
	at org.pcd.wam.test.TestOfflineProcessor.main(TestOfflineProcessor.java:16)

Die nachgeladene Klasse sieht so aus:
Code:
package org.pcd.wam.technologie.nmea.parser;

import java.util.LinkedList;
import java.util.List;

import org.pcd.wam.gegenstandsbereich.streetDetection.locating.model.Track;
import org.pcd.wam.gegenstandsbereich.streetDetection.locating.parser.ITrackParser;

public class DummyParser implements ITrackParser {

	public String getReceiverId() {
		// TODO Auto-generated method stub
		return "dummy wert!";
	}

	public List<Track> getTracks(String s) {
		List<Track> tList = new LinkedList<Track>();
		Track t = new Track();
		t.setCmt("dummy wert");
		return tList;
	}

}


aufgerufen wird das ganze mit:
Code:
public static void main(String[] args) {
		String path = "C:\\work\\";
		String jarName = "test.jar";
		String className = "org.parser.DummyParser";

		FileSystemProcessor f = new FileSystemProcessor(path, jarName, className);
		f.loadExternalLibary();
	}
Kann mir jemand verraten was ich falsch mache bzw wie ich die Methoden getReceiverId und getTracks ansprechen kann per Reflection
 
Code:
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        Class c = DummyParser.class;
        if (!ITrackParser.class.isAssignableFrom(c))
        {
            System.out.println("aus die Maus");
            return;
        }

        ITrackParser it = (ITrackParser)c.newInstance();
        System.out.println(it.getReceiverId());
        System.out.println(it.getTracks("Auto"));
    }
}


interface ITrackParser
{

    public String getReceiverId();

    public List<String> getTracks(String s);
}


class DummyParser
    implements ITrackParser
{

    public String getReceiverId()
    {
        return "dummy wert!";
    }

    public List<String> getTracks(String s)
    {
        List<String> tList = new LinkedList<String>();
        tList.add("dummy wert");
        tList.add(s);
        return tList;
    }
 
SlaterB hat gesagt.:
Code:
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        Class c = DummyParser.class;
        if (!ITrackParser.class.isAssignableFrom(c))
        {
            System.out.println("aus die Maus");
            return;
        }

        ITrackParser it = (ITrackParser)c.newInstance();
        System.out.println(it.getReceiverId());
        System.out.println(it.getTracks("Auto"));
    }
}


interface ITrackParser
{

    public String getReceiverId();

    public List<String> getTracks(String s);
}


class DummyParser
    implements ITrackParser
{

    public String getReceiverId()
    {
        return "dummy wert!";
    }

    public List<String> getTracks(String s)
    {
        List<String> tList = new LinkedList<String>();
        tList.add("dummy wert");
        tList.add(s);
        return tList;
    }

Ich kenne zur Laufzeit nicht den Namen der Klasse (also DummyParser).

Die Lösung zu meinem Problem war dass ich bei invoke keine Instanz der Klasse hatte, welche die Methode ausführt:
Code:
m.invoke(this.c.newInstance());

Trotzdem gefällt mir dein Code besser (muss ihn nur adaptieren) - habe mich heute erstmal an dieses Thema gewagt.

Dankeschön.
 
dass du die Klasse mit dem ClassLoader usw. laden musst ist klar,
aber ab dem Zeitpunkt, ab dem du das Class-Objekt hast,
kannst du meinen einfacheren Weg verwenden,

der Test auf das Interface ist viel einfacher,
und die Operation musst du nicht per Reflection aufrufen,
caste das Objekt auf das Interface und arbeite ganz normal weiter
 
jo jo, hast Recht!

Hab meinen Post eh schon editiert.

Danke dir.


**EDIT**
Eine Frage hätte ich dann doch noch:

Code:
if (!ITrackParser.class.isAssignableFrom(c)) {					
				/* class does not implement needed interface */
				try {
					throw new Exception("external class " + this.className + " does not implement needed "
							+ ITrackParser.class);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

Welche Art von Exception sollte ich hier werfen, sprich gibt es eine spezifierte Exception dafür, dass eine Klasse nicht "korrekt" ist bzw nicht das richtige Interface implementiert? Oder muss ich mit ne eigene Exception Klasse schreiben?

mfg

**EDIT**
Gut werfe nun eine UnsupportedOperationException.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben