Alle Klassen ermitteln, die Interface implementieren / Reflection

R

reflector4sure

Gast
Hi,

wie kann ich in herausfinden, welche Klassen ein bestimmtes Interface implementieren? Angeblich soll es mit Java Reflection funktionieren, habe aber noch nicht herausgefunden wie. Hat jemand vielleicht ein Beispiel parat oder ist die Antwort auf meine Frage gar nicht so banal?

Danke euch.
 
I

irgendjemand

Gast
du müsstest also über alle klassen die der ClassLoader geladen hat *kommt man da überhaupt ran ?* durchiterieren und prüfen ob das im returnten Class-array mit [c]getSimpleName()[/c] der name deines interfaces auftaucht
 

tfa

Top Contributor
Es heißt java.lang.Class.
Damit kannst du alle Interfaces ermitteln, die eine bestimmte Klasse implementiert. Aber ich glaube, das wolltest du nicht.
 
R

reflector4sure

Gast
Das ist wirklich nicht das, was ich möchte. Ich habe in meinem Package z.B. 5 Klassen, die ein bestimmtes Interface implementieren.

Das würde ich gerne geschickt machen, ohne explizit in Eclipse alle Klassen nachzuschauen, welche Klasse was für ein Interface hat.
 

knoppers

Bekanntes Mitglied
Das ist wirklich nicht das, was ich möchte. Ich habe in meinem Package z.B. 5 Klassen, die ein bestimmtes Interface implementieren.

Das würde ich gerne geschickt machen, ohne explizit in Eclipse alle Klassen nachzuschauen, welche Klasse was für ein Interface hat.


Wenn du dieses nur in der Eclipse wissen möchtest, dann öffne dein Interface, öffne das Kontextmenü und klicke auf "Open Type Hierachy". Dann werden dir alle Klassen angezeigt, die dieses Interface implementieren.

Wenn das nicht deine Frage beantwortet, dann solltest du deine Frage etwas genauer beschreiben was du machen möchtest.
 
R

reflector4sure

Gast
Ja, ich kenne sie, da ich explizit im Package nachgeschaut habe, welche Klasse sie implementiert.

Wofür ich das brauche? Ich möchte eine bestimmte Operation mit der Klasse durchführen, falls sie genau das Interface auch wirklich implementiert.
 

knoppers

Bekanntes Mitglied
Wenn ich deine Sache jetzt richtig interpretiere würde doch schon ...

Java:
if ( klasse instanceof interface) {
      macheirgendetwas...
}

vollkommen ausreichen.
 
I

irgendjemand

Gast
java.lang.reflect.Class gibt es nicht.

ja sorry ... habe mich in der doc verklickt ... dachte wäre in java.lang.reflect .. war aber in werklichkeit nur in java.lang ... und natürlich gibt es java.lang.reflect.Class nicht *warum ist mir das nicht aufgefallen ?* und natürlich muss es java.lang.Class heißt ...

da aber java.lang das base-package ist *z.b. Object, Class, System, Runtime, Thread, Throwable, Exception und Error* braucht man dies nicht explizit implementieren


wofür du das nun aber brauchst wird leider trotzdem nicht klar ...

@knoppers
VORSICHT : funktioniert NUR wenn du auch wirklich ne instanz einer klasse hast ...
bei Class.getInterfaces() reicht es wenn du durch ein objekt von Class<?> eine referenz auf die klasse selbst im ClassLoader hast ... brauchst also keine instanz der klasse selbst *was z.b. bei factory-klassen unmöglich wäre wenn diese nach singleto-pattern mit privatem null-konstruktor programmiert sind*
 

knoppers

Bekanntes Mitglied
@knoppers
VORSICHT : funktioniert NUR wenn du auch wirklich ne instanz einer klasse hast ...
bei Class.getInterfaces() reicht es wenn du durch ein objekt von Class<?> eine referenz auf die klasse selbst im ClassLoader hast ... brauchst also keine instanz der klasse selbst *was z.b. bei factory-klassen unmöglich wäre wenn diese nach singleto-pattern mit privatem null-konstruktor programmiert sind*

Stimmt.
 
B

bygones

Gast
Ja, ich kenne sie, da ich explizit im Package nachgeschaut habe, welche Klasse sie implementiert.

Wofür ich das brauche? Ich möchte eine bestimmte Operation mit der Klasse durchführen, falls sie genau das Interface auch wirklich implementiert.
wenn du schon mit reflections arbeitest hol dir direkt die gewuenschte methode ueber getMethod(...) oder so...
 
I

irgendjemand

Gast
Vermutlich für ein plugin system....

gut .. sowas löst an aber in der regel anderst da man bei sowas in der regel vorgibt wie dem system bekannt zu machen ist welche klasse das interface implementiert *und wenns nur über einen missbrauchten "main-class" eintrag im manifest ist *was man mit dem java.util.jar-package auslesen kann*
 

faetzminator

Gesperrter Benutzer
Man kann sich auch eine kleine Config schreiben, in welcher steht, was zu laden ist und wo es sich befindet. XML würde sich da sehr eignen. Denn das Konstrukt wird normalerweise immer komplexer, als man anfangs dachte ;)
 
I

irgendjemand

Gast
@TO
und warum sagst du das dann nicht gleich ?
dann hätte ich dir sofort einen code an den kopf werfen können

Java:
		try
		{
			File pluginDir=new File(PATH);
			File[] pluginJars=pluginDir.listFiles(pluginFilenameFilter);
			for(File pluginJar : pluginJars)
			{
				String name="FAIL";
				JarFile jarFile=new JarFile(pluginJar);
				for(Enumeration<JarEntry> entries=jarFile.entries(); entries.hasMoreElements(); )
				{
					JarEntry entry=entries.nextElement();
					if(entry.getName().endsWith("Plugin.rsf"))
						name=(new BufferedReader(new InputStreamReader(jarFile.getInputStream(entry)))).readLine();
				}
				jarFile.close();
				if(name.equals("FAIL"))
					continue;
				URLClassLoader urlCL=new URLClassLoader(new URL[] { pluginJar.toURI().toURL() });
				Class<?> clazz=urlCL.loadClass(name);
				Plugin plugin=(Plugin)clazz.newInstance();
				plugin.loadPlugin(this);
				plugins.add(plugin);
			}
			for(Plugin plugin : plugins) { plugin.startPlugin(); }
		}

das ist die innere klasse PluginFilenameFilter *welche in meinem code vorher instanziert wird*
Java:
static final class PluginFilenameFilter implements FilenameFilter
	{
		public boolean accept(File path, String name)
		{
			if(name.toLowerCase().endsWith(".jar"))
				return true;
			else
				return false;
		}
	}

dazu gehören dann noch diese interfaces
Java:
public interface Plugin
{
	public void loadPlugin(PluginLoader loader) throws Exception;
	public void startPlugin() throws Exception;
	public void stopPlugin() throws Exception;
}
Java:
public interface PluginLoader
{
	public Object invoke(String pluginName, String pluginMethod, Object... args) throws Exception;
	public String getPath();
	public String getVersion();
	public void shutdown();
}

ein sample-plugin
Java:
public class zGUIShow implements Plugin
{
	private PluginLoader pluginLoader=null;
	public void loadPlugin(PluginLoader pluginLoader) throws Exception { this.pluginLoader=pluginLoader; }
	public void startPlugin() throws Exception
	{
		//code
	}
	public void stopPlugin() throws Exception { }
}
das ganze kannst du dann in JAR-files verpacken ...
in die plugin-jars muss zusätzliche eine datei welche auf "Plugin.rsf" endet und den namen der plugin-klasse samt package enthält
also z.b. : "plugins.gui.zGUIShow"
 
R

reflector4sure

Gast
Die Idee mit dem XML-File gefällt mir ziemlich gut. Das werde ich glaube ich bauen.
 
R

reflector4sure

Gast
Sorry, ich dachte das wäre nicht von Belang. :) Daher hatte ich es nicht erwähnt.

Danke für den Code, werd ihn mir anschauen!!
 
I

irgendjemand

Gast
falls du genaue erklärungen zum code brauchst *ist leider un-doc da ich ihn mal eben so aus meiner code-sammlung kopiert hab* kannst du dich gerne via icq : 345-169-219 melden ... hab das ganze mit hilfe des Java @ tutorials.de: Tutorials, Forum & Hilfe - forums in langer arbeit entworfen und weitreichend getestet ...
auch bei beispielen kannst du gerne noch mal nachfragen ... hab im aktuellen projekt genug davon rumfliegen ...
nur eine fertige lib als JAR zum einbinden in eine IDE hab ich noch nicht ... könnt ich dir aber zusammenbauen
 
R

reflector4sure

Gast
@irgendjemand: Ich adde dich gleich morgen früh! Bin gerade am Rechner meiner Freundin. :D

Danke nochmals an alle!
 
I

irgendjemand

Gast
kein problem ...

wie gesagt ... die basis des codes stammt nicht von mir allein ... da haben bestimmt 20 user über 3 wochen dran gesessen um was halbwegs vernünftiges auf die beine zu stellen ...

ich hatte es nur so schnell parat da ich damit viel arbeite und es auch in meinem aktuellen projekt wieder eine große rolle spielt ...

alternativ melde dich mal im tut.de forum und sprich das "plugin-system" des users "SPiKEe" an *müsste mal die links der threads raussuchen"
 

schalentier

Gesperrter Benutzer
habe ich mit dem user "Thomas Diramont" im tut.de - forum erörtert ...

problem : es muss beim start von java der CP manuell auf alle gewünschten jars festgelegt werden damit der service loader diese finden kann ... was gerade beim dynamischen laden/entladen von plugins hinderlich ist

Biste da sicher? Wozu gibts dann die ServiceLoader.load(Class<S> service, ClassLoader loader) Methode? Sollte das nicht klappen, kann man auch den Classpath zur Laufzeit um Eintraege erweitern (URLClassLoader.addURL).
 
I

irgendjemand

Gast
genau DAS habe ich mit genanntem user lang und breit erörtert und auch selbst sehr viel getestet ...
zumindest in J6 und den pre-builds von J7 ging genau DAS eben NICHT ... habe es seit dem final von J7 auch nicht noch mal versucht ...

das war auch der grund warum ich dort damals eine thread losgetreten habe um ein halbwegs vernünftiges plugin-system zu entwickeln ... anfangs wurde auch ich auf den ServiceLoader verwiesen ... da ich aber beispiele posten konnte die damals auch bei anderen nicht funktionierten hat sich dann die gruppe der interessenten *mich eingeschlossen* daran gemacht etwas eigenes zu entwickeln ...


@TO
ich weis das der code so erstmal nicht schön aussieht *throws Exception* ...
es macht aber durch aus sinn durch den reflection-ähnlichen aufbau alle fehler bis zum caller weiter zu werfen so lange man das aufgetretene problem nicht innerhalb der methode in der es aufgetreten ist vollständig beheben kann und eventuell eine meldung an den user machen muss
 
I

irgendjemand

Gast
@schalentier
mal noch ein anderes beispiel wesshalb ServiceLoader für dynamische systeme ausscheidet

mach dir mal den spass den aktuellen mysql-jdbc-driver zu laden ...
den packst du an einen ort der NICHT in deinem classpath steht ...
dann nimmst du folgenden code
Java:
import java.io.*;
import java.net.*;
import java.sql.*;
public class Test
{
	public static void main(String[] args) throws Exception { (new Test()).test(); }
	private Test() { }
	private void test() throws Exception
	{
		URLClassLoader cl=new URLClassLoader(new URL[] { (new File("G:/java/lib/mysql-con.jar")).toURI().toURL() });
		cl.loadClass("com.mysql.jdbc.Driver");
		Connection con=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "mysql");
		con.close();
	}
}
und compilest ihn ...

dann machst du eine instanz von CMD.exe auf und löschst erstmal temporär deinen classpath durch eingabe von
Code:
set CLASSPATH=
dadurch wird der variable CLASSPATH für diese instanz kein wert zugewiesen und sie wird aus der liste entfernt *durch
Code:
echo %CLASSPATH%
zu prüfen ... wenn du alles richtig gemacht hast wird %CLASSPATH% ausgegeben*

dann startest du die klasse *natürlich vor dem compilen pfad und user angepasst*

du wirst überrascht sein das du eine SQLException bekommst das angeblich kein brauchbarer treiber vorhanden sei obwohl du diesen durch einen URLClassLoader geladen hast *da das DriverManager.register() in einem static-block von Driver steht sollte dieser ja eigentlich registriert werden*

der grund liegt daran das java nur jdbc-driver verwenden kann welche zum zeitpunkt des starts der vm auch im classpath liegen ... *was ja durch die explizite aufhebung des classpath's ausgeschlossen wird*

und so ein ähnliches problem würdest du auch beim ServiceLoader erhalten wenn die zu ladenen plugins beim start NICHT im classpath liegen ...

nun kann man sich bei beiden zum glück abhilfe verschaffen ...

zum jdbc-driver *für java7* :
Java:
import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.*;
import java.util.logging.*;
public class DummyDriver implements Driver
{
	private Driver driver=null;
	public DummyDriver(Driver driver) { this.driver=driver; }
	public boolean acceptsURL(String url) throws SQLException { return driver.acceptsURL(url); }
	public Connection connect(String url, Properties info) throws SQLException { return driver.connect(url, info); }
	public int getMajorVersion() { return driver.getMajorVersion(); }
	public int getMinorVersion() { return driver.getMinorVersion(); }
	public Logger getParentLogger() throws SQLFeatureNotSupportedException { return driver.getParentLogger(); }
	public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return driver.getPropertyInfo(url, info); }
	public boolean jdbcCompliant() { return driver.jdbcCompliant(); }
}

wenn du nun folgenden code verwendest
Java:
import java.io.*;
import java.net.*;
import java.sql.*;
public class Test
{
	public static void main(String[] args) throws Exception { (new Test()).test(); }
	private Test() { }
	private void test() throws Exception
	{
		URLClassLoader cl=new URLClassLoader(new URL[] { (new File("G:/java/lib/mysql-con.jar")).toURI().toURL() });
		Object o=cl.loadClass("com.mysql.jdbc.Driver").newInstance();
		DriverManager.registerDriver(new DummyDriver((Driver)o));
		Connection con=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "mysql");
		con.close();
	}
}
wirst du sehen das die verbindung fehlerfrei hergestellt werden kann

das liegt daran das du den jdbc-driver-loader damit austrickst das eine Driver-klasse während des startens der VM im classpath liegt ...
diese kannst du auf grund ihrer beschaffenheit das sie lediglich alle aufrufe an den darunterliegenden driver druchleitet zum laden von jdbc-drivern während der runtime nutzen ...


und ähnlich verhält es sich auch mit einem plugin-system und dem oben von mir gepostetem code ...
dadurch das du gegen das interface Plugin programmierst ... welches ja zum start der VM im classpath liegt kannst du jede intanz die durch einen URLClassLoader geladen wurde durch diese klasse kapseln und mit ihr arbeiten ...


ich hoffe ich konnte dir was deinen hinweis auf den ServiceLoader und die damit verbundenen schwierigkeiten beim dynamischen laden angeht etwas neues beibringen ...
 

schalentier

Gesperrter Benutzer
Ja klar, du machst das dort auch nicht richtig ;-) Der URLClassLoader, den du dir dort erzeugst, wird ja nicht vom SystemClassLoader benutzt.

So funktionierts und auf analogem Wege sollte es auch mit dem ServiceLoader klappen:

Java:
public class LoaderTest {
    public void addURL( URL url ) {
        URLClassLoader loader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class cls = URLClassLoader.class;
        try {
            Method method = cls.getDeclaredMethod("addURL", new Class[]{URL.class});
            method.setAccessible(true);
            method.invoke(loader, url);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
    public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, SQLException {
        try {
            ClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");
        } catch( ClassNotFoundException e) {
            System.out.println("NOT FOUND");
        }
        LoaderTest l = new LoaderTest();
        l.addURL(new File("mysql-con.jar").toURI().toURL());
        ClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");
        Connection con= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "mysql");
        System.out.println(con);
        con.close();
    }
}
Achtung, Code is HAAAAESSLICH ;-)

Ausgabe:
Code:
NOT FOUND
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
	at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116)
	at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:344)
	at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2332)
	at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2369)
	at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2153)
	at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:792)

(Ich hab hier keine mysql Datenbank, aber der Connect Aufruf wurde vom mysql Treiber versucht)
 
I

irgendjemand

Gast
ok ... proof of concept ...

ja klar ... funktioniert ... ist aber wirklich nicht schön ...
und meines erachtens um ein plugin-system zu bauen *wofür man eh interfaces braucht* mit reflections am SystemClassLoader rumspielen ... ja klar : würde mit sicherheit auch in richtung ServiceLoader funktionieren ... *habs jetzt leider nicht ausgetestet da mir ein KSKB dafür auch grad leider nicht einfällt* ... aber ich denke das das in falsche richtung für eine doch sehr simple aufgabe geht ...
wie gesagt : es wäre im weitesten sinne nur eine nachträgliche manipulation des classpath während der runtime ... und dafür gibt es ja eigentlich den URLClassLoader : um eben während der runtime daten dynamisch nachzuladen *das es hier und da natürlich kleine schwierigkeiten gibt ist klar* ...

aber hab trotzdem wieder was gelernt =D ... *symbolisch DANKE-button drück*
 
B

bygones

Gast
ok hab nicht alles genau gelesen, daher vielleicht redundant.

Wenn man schon ein PluginSystem entwickelt, dann sollte man einfach gewisse Regeln aufsetzen, wie alle Plugins muessen in einen Folder rein (notfalls in der Applikation ein "Install Plugin" Aktion anbieten die das erledigt. In dem Jar selber muss im manifest oder irgendeiner Datei die Klasse angegeben werden, die das PluginInterface implementiert angegeben werden.

Alles andere ist imo unsinn wenn man schon ein PluginSystem baut
 
I

irgenjemand

Gast
ok hab nicht alles genau gelesen, daher vielleicht redundant.

Wenn man schon ein PluginSystem entwickelt, dann sollte man einfach gewisse Regeln aufsetzen, wie alle Plugins muessen in einen Folder rein (notfalls in der Applikation ein "Install Plugin" Aktion anbieten die das erledigt. In dem Jar selber muss im manifest oder irgendeiner Datei die Klasse angegeben werden, die das PluginInterface implementiert angegeben werden.

Alles andere ist imo unsinn wenn man schon ein PluginSystem baut

full ack

wobei gerade das mit "im manifest" angeben dank java.util.jar.Manifest sehr einfach ist ...
zur not könnte man sogar soweit rumtricksen das man die plugins als runnable jar baut und sich dann im loader den main-class eintrag holt *sind ide's in der lage runnable jar mit einer main-class zu erzeugen welche KEIN public static void main(String[]) enthält ?*
oder man nutzt halt andere key's ...
ist auf jeden fall besser als mein rumgemurkse da mit durchs jar laufen und versuchen irgendein file zu laden ...

ich werds mal soweit umbauen ... macht auch irgendwie mehr sinn ...
 
I

irgendjemand

Gast
ich denke doch das wir mitlerweile wissen was TO vorhat und wie man das eleganz lösen kann ...
sowohl dein quote als auch die antwort sind zeitlich etwas veraltet und so nicht mehr relevant
 
B

bygones

Gast
Damit funktioniert das ziemlich gut. Das Problem ist natürlich immer die Zeit, die dafür benötigt wird. Darum sollte man das vorsichtig und paketeinschränkend verwenden.
fuer mich klingt das ein bisschen wie "habe einen hammer gefunden, nun ist alles ein Nagel". Wie schon geschrieben, nur weil etwas moeglich ist, sollte man sich mehrfach ueberlegen, ob es auch das richtige fuer einen ist.
Und fuer das Szenario hier ist es def. nicht die erste Wahl
 

schalentier

Gesperrter Benutzer
Ich raffs irgendwie nicht. Ich hab doch nun schon ein Stueckel Code gepostet, wie man das machen kann, damit es mit dem ServiceLoader funktioniert. Wieso willst du/wollt ihr das nun doch alles selbst implementieren? Wo ist der Vorteil?
 
I

irgendjemand

Gast
der vorteil ist das wir den nachteil den du mit der reflection-manipulation des systemclassloaders erzeugst umgehen ...

wie gesagt : ja - es ist proof-of-concept ... es funktioniert ... aber wenn du schon sowas machst um alleine die plugins zu laden *welche ja dann im endeffekt auch nur ein gemeinsames interface implementieren *Service** dann würde es darauf hinaus laufen das dann das gesamte system mit reflections vollgestopft wird ... und das ist auch nicht gerade die beste wahl ...

es ist halt einfacher mit zwei interfaces , einem loader und plugin-implementierungen etwas dynamisches zubasteln als mit dem ServiceLoader ... welcher wie ich bereits gesagt habe den nachteil entweder muss man den classpath beim start angeben ... oder über solche "tricks" den system-CL manipulieren ...
 
S

Spacerat

Gast
@Schalentier: Ich raff's auch nicht, denn faktisch funktioniert der ServiceLoader, sogar ohne die grossen Verrenkungen, die du in deinem Code anstellst.
Man benötigt lediglich Kenntnis über ein spezielles API genannt ServiceProviderInterface (SPI). Na, klingelts?
Hier mal der ClassLoader mit dem ich alle möglichen Datentypen zur Laufzeit lade sofern dafür ein Codec gefunden wurde.
Java:
package datatypes;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.JarEntry;

import datatypes.codecs.system.JarFile;


final class DTClassLoader
extends URLClassLoader
{
	private static final String SERVICE = "META-INF/services/datatypes.CodecProviderService";

	DTClassLoader()
	{
		super(new URL[0], ClassLoader.getSystemClassLoader());
	}

	protected void registerDatatypes(URL url)
	throws Exception
	{
		JarFile jar = DataType.getFile(url); // ist nicht das JarFile auf welches die Forum API-DOC zeigt!
		jar.extract(new JarEntry(SERVICE));
		addURL(url);
	}
}
Leider ist er so nicht zum testen geeignet, da er Teil einer bereits recht umfangreichen API ist.
[EDIT]@Schalentier: Da fällt's mir auf... kann es sein, das du auch den gerne genommenen Kardinalfehler begehst und diese [c]META-INF/services[/c]-Geschichte einfach missachtest?
@all: Tut ihr dieses vllt. sogar alle? :bahnhof:[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
I

irgendjemand

Gast
@Spacerat
gut ... und dein code ist jetzt WO GENAU anderst als meiner ?
der einzige unterschied ist das du anstatt ein eigenes interface eines aus der API nimmst und anstatt nach einem eigenen file / dem manifest zu suchen den service-descriptor verwendest ... macht summa sumarum auch nichts anderes als mein code oder der reflection-"hack" des System-CL

btw : ich habe mich wie gesagt nur soweit mit der ganzen ServiceLoader sache befasst um sagen zu können das zum zeitpunkt meines letzten tests das problem beim dynamischen laden OHNE manipulation des system-CL bestand ... verdeutlich auch durch das jdbc-driver beispiel ...

da es in einem dynamischen system eher unerwünscht ist parameter anzugeben *z.b. modifizierter CP* bzw diese durch reflections während der runtime zu manipulieren ... ist es eh ein etwas krasser eingriff ins system nur um eine klasse dynamisch zu laden ...
das geht auch einfacher mit nem URLClassLoader und einem dem loader und damit der VM bekannten interface ... weil nichts anderes ist der serviceloader wenn man ihn mal aus ein ander nehmen würde ... mit dem unterschied das dieser intern von java beim start durch die app gejagt wird und man ihn nicht selber schreiben muss ...

@TO
da du dich bis jetzt nicht gemeldet hast und wir uns hier nur noch gegenseitig mit "hacks" der VM belagern wäre mal eine stellungnahme deiner seits ganz hilfreich um den sinn hinter der diskusion noch zu haben ...
dir wurden jetzt 3 möglichkeiten gegeben
1) ServiceLoader
2) manipulation des system-CL
3) eigener code
alle 3 funktionieren ... und sollte man nach möglichkeit nicht mischen *hab da schon einiges gesehen ... dann hast du plötzlich 2 oder 3 instanzen der selben klasse ... ist auch eher sub-optimal* ... aber ohne konkrete fragen zur umsetzung und einer entscheidung welches system du nun benutzen möchtest wird es dir eher weniger bringen wenn wir hier mal eben die VM auseinander nehmen ...

daher nur die bitte *@rest : bitte nicht als destruktive kritik verstehen* : sag uns einfach welche der möglichkeiten du dir ausgesucht hast / für dich am ehesten in frage kommt ... und dann können wir uns speziell darauf konzentrieren ...

ich möchte mich hier nur ungern mit dem rest anlegen *mal wieder* ohne wenigstens eine antwort zu bekommen ob meine vorschläge (nicht) gebraucht werden ...
 
S

Spacerat

Gast
Damit da keine Misverständnisse aufkommen... die Zeilen 5, 7, 13, 23 und 24 können getrost aus meinem Code entfernt werden, denn sie prüfen nur die Presents dieses Eintrags. Ohne diese Prüfung würde jede beliebige URL schlicht geaddet, auch die, die keinen Service-Eintrag haben. Über den ServiceLoader aber bekommt man sie aber trotzdem erst, wenn dieser Eintrag vorhanden ist - ganz ohne Reflection und ganz ohne andere Tricks. Ich habe auch alles zunächst alles über Reflection gelöst, bis ich mir zwecks Inspiration Quellcode von [c]java.sound.sampled.spi[/c] und [c]java.imageIO.spi[/c] näher betrachtete. Getestet hab' ich das dann auch zur Genüge, denn es gibt nur noch sehr wenig Dateien (in der Theorie nämlich gar keine, kommt halt auf die registrierten Codecs an), welche ich nicht per [c]Datatype.getFile(URL url)[/c] geladen und instanziert bekomme.
[EDIT]
... dann hast du plötzlich 2 oder 3 instanzen der selben klasse ...
[IRONIE]"die alle samt und sonders auch nicht mal annäherd funktionieren"[/IRONIE] hast du vergessen zu erwähnen :lol:
...und zum "mit dem Rest anlegen"... Nun ja, mit mir nicht, warum auch, mir ist deine bzw. eure "fehlerhafte" Nutzung des SPI hinlänglich bekannt und mehr als diesen Hinweis auf diesen dubiosen [c]META-INF/service[/c]-Eintrag habe ich ohnehin nicht.[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Gast
Sorry für den Doppelpost, aber ich hab' mich mal daran versucht, euch die "Magie" des SPIs ([c]META-INF/service[/c]) näher zu bringen.
1. Klassen des PlugInLoaders: (2; das PlugIn-Interface und der PlugInProviderService
1.1. Der PlugInProviderService
Java:
package spiplugin.loader;

import java.util.List;


public abstract class PlugInProviderService
{
	public abstract List<PlugIn> getPlugIns();
}
1.2. Das PlugIn Interface
Java:
package spiplugin.loader;

public interface PlugIn
{
	void start();
	void stop();
}

2. Klassen für PlugIn Tests
2.1. SimpleTest1 (Single PlugIn)
Java:
package spiplugin.plugintest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import spiplugin.loader.PlugInProviderService;
import spiplugin.loader.PlugIn;

public class SimpleTest1
extends PlugInProviderService
{
	private static final List<PlugIn> plugins;

	static {
		ArrayList<PlugIn> rc = new ArrayList<PlugIn>();
		rc.add(new PlugIn()
		{
			@Override
			public void stop()
			{
				System.out.println("Single PlugIn stopped");
			}

			@Override
			public void start()
			{
				System.out.println("Single PlugIn started");
			}
		});
		plugins = Collections.unmodifiableList(rc);
	}

	@Override
	public List<PlugIn> getPlugIns()
	{
		return plugins;
	}
}
2.2. SimpleTest2 (10 PlugIns)
Java:
package spiplugin.plugintest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import spiplugin.loader.PlugInProviderService;
import spiplugin.loader.PlugIn;

public class SimpleTest2
extends PlugInProviderService
{
	private static final List<PlugIn> plugins;

	static {
		final MutableInt number = new MutableInt();
		ArrayList<PlugIn> rc = new ArrayList<PlugIn>();
		for(int n = 0; n < 10; n++) {
			rc.add(new PlugIn()
			{
				private final int value;

				{
					value = number.value++;
				}
				
				@Override
				public void stop()
				{
					System.out.println("PlugIn " + value + " stopped");
				}
				
				@Override
				public void start()
				{
					System.out.println("PlugIn " + value + " started");
				}
			});
		}
		plugins = Collections.unmodifiableList(rc);
	}

	@Override
	public List<PlugIn> getPlugIns()
	{
		return plugins;
	}

	private static final class MutableInt
	{
		private int value;
	}
}

3. Eine Test Klasse
Java:
package spiplugin;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ServiceLoader;

import spiplugin.loader.PlugIn;
import spiplugin.loader.PlugInProviderService;

public class SPIPlugInTest
{
	public static void main(String[] args)
	throws Throwable // Tests bitte ohne Try-Catch ;)
	{
		// Ermitteln des nächst höheren Verzeichnisses.
		// wenn man keinen ClassPath angibt, dürfte dieses
		// standardmässig kaum darin enthalten sein.
		final URL parentPath = new File("..").getAbsoluteFile().toURI().toURL();
		// instanzieren des eigenen URLClassLoaders
		final MyURLClassLoader classLoader = new MyURLClassLoader();
		// hinzufügen der Plugin-Archive, welche sich
		// im parentPath befinden sollten.
		classLoader.addURL(new URL(parentPath, "plugIns1.jar"));
		classLoader.addURL(new URL(parentPath, "plugIns2.jar"));
		// und jetzt... TESTEN
		for(PlugInProviderService pps : ServiceLoader.load(PlugInProviderService.class, classLoader)) {
			for(PlugIn pi : pps.getPlugIns()) {
				pi.start();
				pi.stop();
			}
		}
	}

	// Der hauseigene URLClassLoader... (freischalten der add-Methode)
	private static final class MyURLClassLoader
	extends URLClassLoader
	{
		private MyURLClassLoader()
		{
			super(new URL[0]);
		}

		@Override
		protected void addURL(URL url)
		{
			super.addURL(url);
		}
	}
}

4. PlugInService Descriptoren (jeweils die Datei im PI-Archiv [META-INF/services/spiplugin.loader.PlugInProviderService[/c]
4.1. plugIns1.jar
Code:
spiplugin.plugintest.SimpleTest1
4.2. plugIns2.jar
Code:
spiplugin.plugintest.SimpleTest2

5. Klassen und Dateien der Archive
5.1. Hauptarchiv (muss logischerweise im CP sein)
- Die Testklasse mit der "main()"
- Alle Klassen des Paketes spiplugin.loader
Das Archiv evtl. startbar machen.
5.2. PlugInArchive
Lt. Testklasse ein Verzeichnis über dem Hauptarchiv und dafür sorgen, dass dieses nicht im CP auftaucht, damit der Effekt sichtbar wird.
5.2.1. PlugIns1.jar
- Die PlugInProvider Klasse SimpleTest1
- Der erste Servicedescriptor (4.1)
5.2.1. PlugIns2.jar
- Die PlugInProvider Klasse SimpleTest1
- Der zweite Servicedescriptor (4.2)

6. Ausgabe
Code:
PlugIn 0 started
PlugIn 0 stopped
PlugIn 1 started
PlugIn 1 stopped
PlugIn 2 started
PlugIn 2 stopped
PlugIn 3 started
PlugIn 3 stopped
PlugIn 4 started
PlugIn 4 stopped
PlugIn 5 started
PlugIn 5 stopped
PlugIn 6 started
PlugIn 6 stopped
PlugIn 7 started
PlugIn 7 stopped
PlugIn 8 started
PlugIn 8 stopped
PlugIn 9 started
PlugIn 9 stopped
Single PlugIn started
Single PlugIn stopped
Bei Fragen einfach fragen... viel Erfolg ;)
[EDIT]Zu guter Letzt sei noch erwähnenswert, dass das Interface [c]PlugIn[/c] eigentlich überflüssig ist, solange die PlugIns nicht andere Klassen erweitern sollen.[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
I

irgendjemand

Gast
gut .. auch wenn dein post schon etwas her ist möchte ich noch mal ein grundlegendes problem einwerfen

java hat leider probleme bei der korrekten unterstützung von URLs ...

wenn man in nem pfad z.b. leerzeichen hat werden diese ja noch halbwegs korrekt mit %20 codiert ... so bald es aber an sonderzeichen geht gibts probleme ...
alles was im ASCII steht geht noch ... aber spätestens bei deutschen umlauten wird es katastrophal ...
wenn man sich mal die ausgabe von File.toURI().toURL() eines pfades ansieht der z.b. leerzeichen , deutsche umlaute , das euro-zeichen und meinet wegen noch andere ungültige zeichen enhält ist nicht mal mehr der URLDecoder in der lage diese wieder richtig darzustellen ...

am schlimmsten fällt dies unter Windows auf ... da wir ja alle wissen das Windows sowas grundsätzlich in Win-1251 codiert ... java sowas aber rfc getreu mit utf-8 macht kommt es zu schweren fehlern welche zu nicht mehr auflösbaren pfaden führen ...

soweit wie es meine tests gezeigt haben mag es wohl noch möglich sein eine URL welche aus einem File-objekt generiert wurde zu verwenden ... so bald man aber den umgekehrten weg versucht , also ein File-objekt zu erstellen dem man z.b. URL.toString() übergibt scheitern viele operationen an FileNotFoundException oder anderen ...


@Spacerat
na das beispiel ist wohl eher schlecht gewählt ... weil mehr als anonyme objekte erstellen machst du da auch nicht ...
ein richtiges beispiel für ein plugin fehlt leider bei dir ...
und ob es wirklich so sinnvoll ist [c]extends Provider[/c] anstatt [c]implements Plugin[/c] zu nutzen ... naja kommt auf den anwendungsfall an ..


@Mod
da sich TO weder bei mir noch scheinbar bei jemand anderen gemelt hat könnte man dieses thema ruhig mal als "erledigt" makieren ...
 
S

Spacerat

Gast
java hat leider probleme bei der korrekten unterstützung von URLs ...
Äehm... [c]java.net.URLEncoder[/c] und [c]java.net.URLDecoder[/c] funktionierten bei mir bisher immer prächtig.
@Spacerat
na das beispiel ist wohl eher schlecht gewählt ... weil mehr als anonyme objekte erstellen machst du da auch nicht ...
ein richtiges beispiel für ein plugin fehlt leider bei dir ...
und ob es wirklich so sinnvoll ist [c]extends Provider[/c] anstatt [c]implements Plugin[/c] zu nutzen ... naja kommt auf den anwendungsfall an ..
Klassennamen sind in Beispielen [c]extends Schall[/c] und [c]implements Rauch[/c]. Provider kann man für echte Projekte auch in Plugin umbenennen, wie man es macht, bleibt jedem selbst überlassen. Die PlugIns fehlen auch nicht, sondern manifestieren sich in den Klassen SimpleTest1 und SimpleTest2. Dort werden die PlugIns zwar anonym instanziert, aber wer sagt denn, dass man das in echten Projekten so machen muss? Fakt ist, dass wenn man das SPI (ServiceLoader) verwenden will, es so verwenden sollte und nicht anders, zumindest lt. den meisten Tutorials oder gar [c]javax.sound.sampled.spi[/c] bzw. [c]javax.imageio.spi[/c]. Auf jeden Fall aber ist es besser, als irgend etwas unnötig mit Reflection verhunzen zu müssen, sogar [c]PluginClass.class.newInstance()[/c] entfällt.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S IntelliJ geht alle Klassen durch Java Basics - Anfänger-Themen 9
N Variable für alle Klassen Java Basics - Anfänger-Themen 6
J Subklasse soll alle Klassen/Pakete der Superklasse importieren Java Basics - Anfänger-Themen 3
S Bildschirm für alle Klassen erstellen Java Basics - Anfänger-Themen 8
S Hibernate Session: Wie in alle Klassen Java Basics - Anfänger-Themen 19
E Infos für alle Klassen eines Projekts Java Basics - Anfänger-Themen 5
J Aufbau von Klassen und zugriff auf alle Variablen Java Basics - Anfänger-Themen 7
V int-Wert für alle Klassen verfügbar machen Java Basics - Anfänger-Themen 7
L JAR-Datei: alle notwendigen Klassen einbinden lassen Java Basics - Anfänger-Themen 2
K Warum wird hier nur etwas in eine txt Datei geschrieben und nicht in alle drei (InputStream/OutputStream/Reader/Writer) Java Basics - Anfänger-Themen 1
H Nutzt Eclipse alle CPU-Threads beim Ausführen von Java-Programmen? Java Basics - Anfänger-Themen 4
B Alle Strings bis zu einer Maimallänge aufzählen, die Bedingung erfüllen Java Basics - Anfänger-Themen 13
D Apache HTTPClient für alle Fälle Java Basics - Anfänger-Themen 41
missy72 Methoden Alle rekusiven Aufrufe abbrechen Java Basics - Anfänger-Themen 21
B Alle Zahlen finden, die 3 bestimmte Ziffern enthalten? Java Basics - Anfänger-Themen 9
K wie kann ich alle Attribute von dem Objekt(pagode) ausgeben lassen ? Java Basics - Anfänger-Themen 3
I Greenscreen, funktioniert nicht zu 100%... nicht alle Pixel werden geändert Java Basics - Anfänger-Themen 1
Butzibu Image Loader lädt nicht alle Bilder: Java Basics - Anfänger-Themen 4
sserio Wieso werden nicht alle Primzahlen bis 1000 in meine Liste gepackt ? Java Basics - Anfänger-Themen 8
E Select nimmt nicht alle Where /AND befehlen an Java Basics - Anfänger-Themen 4
K Erste Schritte Wie schnell ist LinkedHashMap im Vergleich zur ArrayList, wenn alle Entries durchlaufen werden? Java Basics - Anfänger-Themen 47
R Methoden Eclipse schlägt mir nicht alle Möglichkeiten vor Java Basics - Anfänger-Themen 4
melisax Alle Möglichkeiten eines Wortes angeben Java Basics - Anfänger-Themen 3
B Programm, dass alle 3 Tage eine Webseite öffnet? Java Basics - Anfänger-Themen 20
J Alle .java Dateien von einem Verzeichnis in eine Zip speichern Java Basics - Anfänger-Themen 2
J Alle Dateien aus einem Verzeichnis laden Java Basics - Anfänger-Themen 10
Bademeister007 Operatoren Alle Zahlen einer ArrayList die durch 5 teilbar ist Java Basics - Anfänger-Themen 2
E Wie gebe ich alle Daten zwischen zwei Zeitpunkten aus? Java Basics - Anfänger-Themen 2
crrnogorka Letzte Zeile einer Tabelle "überschreibt" alle anderen Zeilen Java Basics - Anfänger-Themen 1
C alle möglichen Kombinationen zweier Ziffern auf drei / vier / und 'n" Stellen Java Basics - Anfänger-Themen 11
H Alle Geraden zahlen bis 10 ausgeben Java Basics - Anfänger-Themen 11
L Alle Ziele in einem Raster abknallen Java Basics - Anfänger-Themen 17
J Alle Werte eines Strings zusammen addieren Java Basics - Anfänger-Themen 15
S Laufzeit Quicksort wenn alle Elemente gleich sind Java Basics - Anfänger-Themen 4
B Alle Links in einem Text suchen und ersetzen mit einem neuen Link Java Basics - Anfänger-Themen 18
K Array alle Werte aufsummieren und ausgeben Java Basics - Anfänger-Themen 6
Dimax Erste Schritte String replace alle Zeichen Java Basics - Anfänger-Themen 10
L Wie vergrößere ich ein Rechteck in alle Richtungen um eins und bekomme dessen Rand? Java Basics - Anfänger-Themen 2
L Breadth-First Search statt einem Pfad, alle Pfade herausfinden Java Basics - Anfänger-Themen 4
X Erste Schritte String: Alle doppelten Leerzeilen entfernen Java Basics - Anfänger-Themen 21
M Regex-Ausdruck: Alle Zeichen bis auf ein bestimmtes erlauben (p{L}) Java Basics - Anfänger-Themen 5
I Alle Elemente von zwei Listen vergleichen Java Basics - Anfänger-Themen 1
Kirby.exe Alle möglichen Error Möglichkeiten abfangen Java Basics - Anfänger-Themen 33
M Unterklasse soll nicht alle Methoden erben Java Basics - Anfänger-Themen 3
V Erste Schritte for-Schleife; Ausgabe soll alle 5 Sekunden erfolgen. Java Basics - Anfänger-Themen 4
A Alle true Werte eines boolean Arrays herausfiltern Java Basics - Anfänger-Themen 19
D Alle Möglichkeiten, n-Anzahl aus Elementen aus einem Array zu wählen, ausgeben? Java Basics - Anfänger-Themen 23
M prüfen ob alle array werte gleich sind Java Basics - Anfänger-Themen 27
F Alle Zeichenkombinationen eines Strings iterativ herausfinden Java Basics - Anfänger-Themen 26
L Classpath Alle Dateien im Classpath finden Java Basics - Anfänger-Themen 4
G Überprüfen ob alle Ziffern von 1-9 in einem Integer vorhanden sind Java Basics - Anfänger-Themen 6
J Erste Schritte Alle möglichen ausgaben von 5 Zahlen als Vector Java Basics - Anfänger-Themen 7
R Methoden Entferne alle identische Knoten (Typ String) aus verkettete Liste Java Basics - Anfänger-Themen 8
D Methoden Eigene Methode um alle Ausgaben aufzurufen Java Basics - Anfänger-Themen 17
F Ordner auf alle Unterdatein abfragen Java Basics - Anfänger-Themen 3
A In einem String alle Eigennamen zählen Java Basics - Anfänger-Themen 6
B Klassen Alle Unter-Objekte durchlaufen in der Hauptklasse Java Basics - Anfänger-Themen 10
W ArrayList löscht alle Elemente bis auf eines Java Basics - Anfänger-Themen 2
B Webservice -> alle parameter bekommen von form Java Basics - Anfänger-Themen 2
das_leon Alle Zeilen einer CSV-Datei auslesen Java Basics - Anfänger-Themen 1
C HashMap - alle keys haben values der letzten put-Anweisung Java Basics - Anfänger-Themen 3
F Eclipse alle Projekt weg Java Basics - Anfänger-Themen 6
V Alle Komponenten eines JPanels Java Basics - Anfänger-Themen 14
I gemeinsame Config-Datei für alle Windows-User Java Basics - Anfänger-Themen 5
H JButton - Wechsel der Textfarbe alle 500ms Java Basics - Anfänger-Themen 10
DaCrazyJavaExpert Alle Zahlenkombinationen aus 9 zahlen finden Java Basics - Anfänger-Themen 17
F Alle Objekte einer Klasse nach Eigenschaft durchsuchen Java Basics - Anfänger-Themen 8
M Alle Instanzen einer Klasse ansprechen Java Basics - Anfänger-Themen 4
S Problem: Array alle Einträge gleich Java Basics - Anfänger-Themen 10
Z Enter Taste alle 0,5 Sekunden ausführen Java Basics - Anfänger-Themen 1
U RegEx alle Kommas bei den Zahlen in Punkt umwandeln Java Basics - Anfänger-Themen 3
K alle Vorkommen einer bestimmten Ziffer in einer Zahl zählen Java Basics - Anfänger-Themen 2
X Minimax-Algorithmus über alle Kanten möglich? - Kanten darstellen Java Basics - Anfänger-Themen 1
C Alle Zweierpotenzen bis 2^10 ausgeben lassen Java Basics - Anfänger-Themen 15
B Alle Attribute von Klasse bekommen und ändern Java Basics - Anfänger-Themen 12
M Input/Output Alle Zeilen auslesen und in Variable speichern Java Basics - Anfänger-Themen 5
W Mozilla Thunderbird email an alle Kontakte Java Basics - Anfänger-Themen 3
F Methode alle 15min ausführen Java Basics - Anfänger-Themen 5
D Alle möglichen Kombinationen in einem Array ausgeben Java Basics - Anfänger-Themen 2
I Alle Laufwerke und deres Pfade ausgeben Java Basics - Anfänger-Themen 6
S Classpath: Alle .jars innerhalb eines Ordners einbinden Java Basics - Anfänger-Themen 4
G Alle Objekte und Variablen automatisch ausgeben Java Basics - Anfänger-Themen 7
I Programm, welches eine Textzeile einliest und alle darin enthaltenen Buchstaben umwandelt Java Basics - Anfänger-Themen 3
G Wie bekomme ich alle Ausgaben von runTime.exec() Java Basics - Anfänger-Themen 7
L Best Practice Alle Kombinationen aus Listenelementen, Anzahl Listen unterschiedlich Java Basics - Anfänger-Themen 6
M Compiler-Fehler Alle Methoden eines Interfaces Implementiert dennoch Fehler Java Basics - Anfänger-Themen 3
I Alle Zeitzonen in Liste speichern Java Basics - Anfänger-Themen 4
F alle 100ms Befehle ausführen Java Basics - Anfänger-Themen 26
M Alle Sublisten einer bestimmten Laenge berechnen Java Basics - Anfänger-Themen 2
F Alle DEMOS fast veraltet...? Java Basics - Anfänger-Themen 13
J Alle Leerzeichen aus String entfernen Java Basics - Anfänger-Themen 13
D Methoden Alle Siebenstelligen Primpalidrome von PI Java Basics - Anfänger-Themen 6
K Durch alle Attribute eines Objektes iterieren Java Basics - Anfänger-Themen 6
P Klassen Alle Strings einer ArrayList<eigeneKlasse> anspre Java Basics - Anfänger-Themen 2
W String von hinten alle drei Zeichen abschneiden und in umgekehrter Reihenfolge ausgeben. Java Basics - Anfänger-Themen 9
M Stürzen alle Rekursive Methoden irgendwann ab? Java Basics - Anfänger-Themen 11
M Alle möglichen Strings Java Basics - Anfänger-Themen 5
J Alle Wörter der Länge n mit 0 und 1 Java Basics - Anfänger-Themen 17
T Alle Threads .notify() Java Basics - Anfänger-Themen 13
G Methoden Alle Objekte der ArrayList ausgeben funktioniert nicht. Java Basics - Anfänger-Themen 12

Ähnliche Java Themen

Neue Themen


Oben