Nicht noch ein JUnit-Thread

um das Testen gehts momentan gar nicht… ich will ein einfach zu bedienendes Programm haben, welches durch Pfadangaben die jeweiligen Klassen findet und initialisieren könnte. Siehe Reflections. Das ist aber nur mit erheblichen Einschränkungen machbar. So muss ich beispielsweise die aufgabensourcecodes auch im Projekt enthalten haben, welches diese Sources einlesen will… total dämlich

thats life

einfach so mal irgendwas einlesen was irgendwo liegt geht halt einfach nicht. das muss nicht zwingend im selben Projekt sein, es muss nur um Classpath sein

es lässt sich aber nicht kompilieren, denn wenn du mit reflections arbeitest muss es im Projekt enthalten sein. Wie willst du denn sonst die forName-Methode aufrufen? Er findet die Klasse ja zur CompileZeit nicht. Wenn ich meinem Compiler noch beibringen kann, dass doch hinzubekommen, bin ich die größten Probleme erstmal los. Aber wie gesagt, ich habe noch keinen Weg gefunden, die Methode Class.forName(“packagename.foo.bar.NameJavaKlasse”) ohne einbinden ins Projekt lauffähig zu bekommen. Er schmeisst dann sofort eine ClassNotFound-Excpt. Wenn jemand weiß, wie man dem entgegenkommen kann, immer her damit. Mir gehen langsam die Ideen aus.

zum compilen muss die Klasse “packagename.foo.bar.NameJavaKlasse” in den Ordnern packagename/foo/bar liegen und du musst auf der Ebene wo der Ordner packagename ist den Compiler aufrufen. Sonst geht NIX

yap, wusst ichs doch… nunya. Ich habe mir auch schon eine Variante überlegt, mit der ich zurecht kommen sollte. Rein vom Stil finde ich das zwar nicht elegant, aber wenn mir Java diese Restriktionen auferlegt - die sicher nicht aus heiterem Himmel fallen, muss ich mich damit arrangieren. Vielen dank für die Hilfe hier.

du verwechselst hier Compilezeit und laufzeit.

Zur Compilezeit funktioniert Class.forName(“irgendwas.irgendwo.irgendwie”)

Zur Laufzeit muss natuerlich diese Klasse dann im Classpath sein, nicht unbedingt im Projekt, aber natuerlich im Classpath.

Und was heisst hier Restriktion ?

Woher soll er denn diese Klasse zaubern ? Wenn du n Urlaub planst ist der Flieger auch noch nicht auf der Startbahn. Wenn du dann einsteigst muss er natuerlich da sein, sonst geht nix.

Ist ueberall und keine Restriktion

Muss nicht unbedingt im Classpath sein, es gibt ja noch den URLClassLoader.

Gruß,
pcworld

ok lass es mich spezifizieren… es muss mit einem (beliebigen) ClassLoader erreichbar sein :wink:

mit Restriktion meine ich, dass es zur Compilezeit im Projekt enthalten sein muss. Ich weiß schon warum. Nur, jeder der mal mit EJB gearbeitet hat, weiß, dass es für dieses Problem auch Lösungen geben kann. Ums mal extremst zu vereinfachen:
Ich wünschte mir, dass der Compiler unabhängig der Tatsache, ob die Klasse vorhanden ist oder nicht, das Programm kompiliert. Der Fehler entsteht dann erst, wenn bei Ausführung eine solche Klasse nicht gefunden werden kann. Das wäre das, was man sich wünscht. Es würde mir einen hohen Grad an Aufwand ersparen - und ich könnte mein Programm viel freier gestalten. Genau das meine ich mit Restriktion. Wenn man das auf mein Problem bezieht, macht das auch sehr viel Sinn. Ich könnte einfach den Classpath anpassen und schon kann er alles testen, was er will. So aber muss ich das Programm neu kompilieren, mit den Aufgaben darin. Oder ich nehme leere Hüllen, die nur als Platzhalter fungieren.

Ich arbeite auch oft mit dem URLClassLoader. Und dem Compiler ist es dabei völlig Wurst, ob es die Dateien (Klassen) gibt, auf die ich mit ihm zugreifen will… :slight_smile:

Gruß,
pcworld

kann man das mit reflections kombinieren?

ya natürlich geht das. Ich frage mich allerdings worin der Sinn von dem URLClassLoader besteht. Der kann auch nicht das was ich brauche. Die aufzurufenden Klassen müssen dennoch im Projekt enthalten sein. Langsam aber sicher gebe ich auf… anscheinend geht das, was ich möchte, einfach nicht. Oder es liegt daran, dass ich mit einer IDE kompiliere. Vielleicht kann man noch was an den Systemproperties einstellen, damit er die benötigten Klassen vorher finden kann.
Die classpath-Property tuts zumindest schonmal nicht.

Ich versteh dich irgendwie nicht ganz… Wie/Warum willst du Klassen laden, die du nicht einmal hast, auch nicht zum Zeitpunkt des Ausführens (so hört es sich an)?

Die Klassen müssen nur zum Zeitpunkt des Ausführens auf irgendeinem erreichbaren Filesystem sein. Können auch aus einer JAR kommen.

[QUOTE=necro;11630]anscheinend geht das, was ich möchte, einfach nicht. Oder es liegt daran, dass ich mit einer IDE kompiliere. Vielleicht kann man noch was an den Systemproperties einstellen, damit er die benötigten Klassen vorher finden kann.
Die classpath-Property tuts zumindest schonmal nicht.[/QUOTE]
Dem URLClassLoader ist es Wurst, wo die zu ladende Klasse sich befindet, ob im Classpath, oder nicht, ob in einer JAR… und vermutlich sogar aus dem Internet! :slight_smile:
Und der Compiler interessiert sich nicht dafür, ob es die Klasse gibt.

Gruß,
pcworld

Habe dir mal ein Beispiel vom URLClassLoader zusammengestellt. Die zu ladende Klasse befindet sich in einer JAR namens “example.jar” im selben Verzeichnis, wobei das Verzeichnis auch ein beliebiges anderes sein könnte (musst du halt anpassen).

CLInterface: dieses Interface muss implementiert werden von den Klassen, auf die du “zugreifen” willst.


public interface CLInterface {

	public void doSomething();

}```

Eine Implementierung:
```package urlcldemo;

public class CLImpl implements CLInterface {

	@Override
	public void doSomething() {
		System.out.println("und? geht doch!");
	}

}```
Diese Klasse steckst du jetzt in eine JAR namens "example.jar" und gibst als Main-Class diese Klasse an.

Jetzt die Klasse, die die Klasse aus der JAR lädt und die Methode doSomething() ausführt:
```package urlcldemo;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.jar.Attributes.Name;

public class URLClassLoaderDemo {

	public static void main(String[] args) {
		File jarFile = new File("example.jar");
		try {
			URL jarURL = jarFile.toURI().toURL();
			JarFile jar = new JarFile(jarFile);
			Manifest manifest = jar.getManifest();
			String main = manifest.getMainAttributes()
					.getValue(Name.MAIN_CLASS);
			ClassLoader cl = new URLClassLoader(new URL[] { jarURL });
			Class<?> cls = (Class<?>) cl.loadClass(main);
			CLInterface inst = (CLInterface) cls.newInstance();
			inst.doSomething();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

Habe das Beispielprogramm angehängt. Beide JARs kommen in dasselbe Verzeichnis, auszuführen ist “urlclassloaderexample.jar”.

Gruß,
pcworld

ich verweis gern nochmal auf meinen Beitrag von oben.

Wenn man mit Reflections arbeitet IST das dem Compiler mehr als egal… Class.forName(“my.funny.weird.Class”) kompiliert und somit KEINE restriktion.

wenn dann zur Laufzeit die klasse nicht gefunden wird, dann gibts n Fehler das ist richtig.

also nochmal:

Dem Compiler ist es absolut egal welche Klasse du laden willst, hoechstens du machst solche spielchen

MyConcreteClass c = (MyConcreteClass)Class.forName("de.what.MyConcreteClass"); // wie auch immer

danke für euer Bemühen.
1.) auf jar sollte ich verzichten, wie ich bereits sagte… die Schüler sollen ihren Quellcode einfach in den Ordner schmeißen. Das ist im besten Fall eine einzige .java pro Schüler.
2.) dann erklärt mir bitte, wieso das Programm trotz anpassen des classpaths nicht in der Lage ist die Klasse zu finden? Das geht IMMER nur, wenn ich dem Projekt den Ordner mitgebe, wo sich diese Klassen befinden. Andernfalls wirft er immer eine ClassNotFound-Excpt.

Wer nett ist, kann das ja bei sich mal reproduzieren.

{
    public void doSth()
    { System.out.println("Es gayt");}
}

und


public class SucherKlasse
{
    public SucherKlasse()
    {
          Class c = Class.forName("GesuchteKlasse");
          //try-catch wird eure IDE einfügen
    }
 
    public static void main(String[] args)
     {
           SucherKlasse sc = new SucherKlasse();
     }
}

So, nun darf natürlich GesuchteKlasse.java nicht im Projekt der SucherKlasse enthalten sein. Die soll sonstwo auf eurem PC sein. Die Angabe wo sich die Klasse befindet wird nur über den classpath gemacht. Ya, macht das mal. Bei mir funktioniert es nach wie vor nicht. Wie gesagt erst, wenn ich den Ordner, wo sich die Klasse GesuchteKlasse.java befindet, im Projekt einbinde. Ich habe sogar schon mit System.setProperty(“java.class.path”, +neuerPfad) versucht, aber selbst dann gibts die ClassNotFound-Excpt.
@DeathByClown: nein diesen Spezialfall versuche ich nicht. Ich wills ja allgemein halten.

Mit dem Classpath habe ich es auch nicht hinbekommen, aber damit habe ich noch nie gearbeitet.
GesuchteKlasse liegt bei mir in C:\cls, natürlich in kompilierter Form.

Um die Klasse zu laden, habe ich den URLClassLoader benutzt - erfolgreich.
Hier ein Beispiel:

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class SucherKlasse {
	public SucherKlasse() {
		try {
			URLClassLoader cl = new URLClassLoader(new URL[] { new File(
					"C:\\cls").toURI().toURL() });
			Class c = Class.forName("GesuchteKlasse", true, cl);
			Object o = c.newInstance();
			c.getMethod("doSth").invoke(o, null);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		SucherKlasse sc = new SucherKlasse();
	}
}```

Ich hoffe, ich konnte dir damit helfen! :)

Gruß,
pcworld

woa toll, das könnte der Durchbruch sein. Ich habe ja dort gar keine Class-Dateien liegen >_< sondern .java Sogesehen ist die Exception sogar eindeutig. Man sieht manchmal echt den Wald vor lauter Bäumen nicht. Testen werde ich das erst morgen, aber ich bin zumindest zuversichtlich. Vielen Dank.

Ist das zu fassen… seit über einer Woche suche ich nach des Rätsels Lösung und dann kommt ein pcworld und stößt mich mit der Nase drauf.

**noch einmal zur Zusammenfassung:

!!! Möchte man auf Klassen mit Reflections zugreifen, müssen diese in kompilierter Form, d.h. als class-Datei an dem jeweiligen Ort vorliegen. Liegen diese Dateien als java-Datei vor, wird das Programm erst funktionieren, wenn dieser Ordner im Projekt enthalten ist !!!
**

Vielen Dank an alle Helfer

[QUOTE=necro]Ist das zu fassen… seit über einer Woche suche ich nach des Rätsels Lösung und dann kommt ein pcworld und stößt mich mit der Nase drauf.

**noch einmal zur Zusammenfassung:

!!! Möchte man auf Klassen mit Reflections zugreifen, müssen diese in kompilierter Form, d.h. als class-Datei an dem jeweiligen Ort vorliegen. Liegen diese Dateien als java-Datei vor, wird das Programm erst funktionieren, wenn dieser Ordner im Projekt enthalten ist !!!
**

Vielen Dank an alle Helfer[/QUOTE]

ich moechte deine Euphorie nicht schmaelern, aber korrekt heisst es:

Es muss IMMER die .class datei vorhanden sein, anders geht es nicht.

Das phaenomen was du beobachtest ist, dass Eclipse (bzw jede andere IDE), im Hintergrund deine java Dateien IMMER sofort in .class kompiliert, ergo arbeitest du auch in Eclipse NIE mit .java sondern immer mit .class

Generell gesagt: Willst du irgendwas mit java machen (ausser quellcode schreiben) brauchst du IMMER die Compilate !