Klasse aus Package auslesen

  • Themenstarter Themenstarter Gast2
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Gast2

Gast
Moin,

wie kann ich die Klassen aus einem Package wärend der Laufzeit auslesen?

mit etwas Glaskugel habe ich folgendes gefunden

Code:
	private void KlassenListe()
	{
        // Code from JWhich
        // ======
        // Translate the package name into an absolute path
		String pckgname = "de.x8bit.Fantasya.Atlantis.Items";
        String name = new String(pckgname);
        if (!name.startsWith("/")) {
            name = "/" + name;
        }        
        name = name.replace('.','/');
        
        // Get a File object for the package
        URL url = Launcher.class.getResource(name);
        File directory = new File(url.getFile());
        
        // New code
        // ======
        if (directory.exists()) {
            // Get the list of the files contained in the package
            String [] files = directory.list();
            for (int i=0;i<files.length;i++) {
                 
                // we are only interested in .class files
                if (files[i].endsWith(".class")) {
                    // removes the .class extension
                    String classname = files[i].substring(0,files[i].length()-6);
                    System.out.println(classname);
                }
            }
        }
	}

funktioniert super in Eclipse ... wenn ich das Projekt aber als JAR exportiere und starte, dann funktiniert es nicht ... und zwar läd er die Resource nicht

Code:
URL url = Launcher.class.getResource(name); // trööööt

starte ich das Projekt über die Console (also nicht als JAR) funktioniert es wieder



hand, mogel



 
Das geht nicht. Ein Package ist kein Verzeichnis und in einem jar gibt es ebenfalls keine Verzeichnisse.
 
Moin,

Ein Package ist kein Verzeichnis und in einem jar gibt es ebenfalls keine Verzeichnisse

das ist mir schon klar ... es funktioniert zwar, aber ich hätte gerne eine Java-Lösung ... daher auch meine Frage

hand, mogel
 
Was meinst du mit java Lösung? Was du vorhast funktioniert nunmal nicht so wie du es gerne hättest.
 
Moin,

Was meinst du mit java Lösung?

das ich mittels Java wärend der Laufzeit mich durch die Packages "hangle", via Reflection ... so wie es mit dem .NET Framework funktioniert

Was du vorhast funktioniert nunmal nicht so wie du es gerne hättest

irgendwie schon ... ich bekomme ja die Klassen-Namen im entsprechenden Package ... unter Eclipse bzw. nur wenn das Projekt nicht als JAR gepackt ist ... der JAR-Browser liefert mir auch alle Klassen im Package ... allerdings liest er das JAR-File auch als ZIP aus

mein Problem ist, das ich zum einem mehre Packages habe die ich so durchlaufen muss ... zum Anderen werden je nach Fortschirtt verschiedene Klassen hinzugefügt ... da ich ja anscheinend nicht durch die Packages iterieren kann, muss ich das Ganze in eine extra Klasse auslagern und neue Klassen zu einer großen Liste von Hand hinzufügen ... und genau das möchte ich vermeiden (weil Regel #1: Programmierer sind faule Menschen)



hand, mogel
 
Ein Package kann gar nicht wissen welche Klassen in ihm definiert sind, weil ein Package nichts anderes als ein Namespace ist.
Es ist nicht immer nur der einfache Fall alle Klassen von Package XY liegen in jar x oder noch besser, als Dateien in Verzeichnis YX.
Eine Klasse kann auch aus einem byte[] definiert werden, aus einer Datenbank, oder dem Netzwerk gestreamt werden und, und, und.
ich bekomme ja die Klassen-Namen im entsprechenden Package
Nein, du bekommst Dateien in einem Verzeichnis.
 
Moin,

Wildcard hat gesagt.:
Ein Package kann gar nicht wissen welche Klassen in ihm definiert sind, [..]

theoretisch schon ... ist aber von Sun anscheinend nicht vorgesehen worden ... dazu müssen einfach nur die entsprechenden Meta-Daten verfügbar sein ... die VM verwaltet irgendwo in ihren Tiefen die ganzen Klassen passend zum Package ... nur darauf zugreifen darf anscheinend keiner

Es ist nicht immer nur der einfache Fall alle Klassen von Package XY liegen in jar x oder noch besser, als Dateien in Verzeichnis YX.

in meinem Fall schon, daher funktioniert auch ..........

Nein, du bekommst Dateien in einem Verzeichnis.

....... der Zugriff auf den Datei Namen ... da die VM vorrausetzt das Dateiname und Klassenname gleich sind ... ich weis nicht ob Du schon unter Windows versuchst hast eine Klasse zu verwenden wärend der Dateiname klein geschrieben ist aber die Klasse mit einem großen Buchstaben anfängt ... das funktioniert nicht



Fazit: unter Java funktioniert das Auslesen der Packages, wie unter .NET, mittels Reflection nicht ... das Auslesen der JAR/ZIP bzw. Verzeichnisstruktur funktioniert bedingt und erfüllt bei mir den Zweck



hand, mogel
 
Du wirfst hier einiges durcheinander.
theoretisch schon ... ist aber von Sun anscheinend nicht vorgesehen worden ... dazu müssen einfach nur die entsprechenden Meta-Daten verfügbar sein ... die VM verwaltet irgendwo in ihren Tiefen die ganzen Klassen passend zum Package ... nur darauf zugreifen darf anscheinend keiner
Nein. Die bereits geladenen und daher bekannten Klassen sind eine Teilmenge Menge der Klassen die im Lebenszyklus der Anwendung geladen werden. Die Information welche Klassen in das Package XY definiert wurden ist also (wie bei XML Namespaces) schlicht nicht vorhanden (auch bei .NET nicht).

....... der Zugriff auf den Datei Namen ... da die VM vorrausetzt das Dateiname und Klassenname gleich sind ... ich weis nicht ob Du schon unter Windows versuchst hast eine Klasse zu verwenden wärend der Dateiname klein geschrieben ist aber die Klasse mit einem großen Buchstaben anfängt ... das funktioniert nicht
1. Es gibt nicht die VM
2. Sollten wir hier von der SUN VM reden, dann setzt sie das definitiv nicht vorraus. (nur bestimmte Classloader tun das).
 
Moin,



schön das ich das bei der Suche nicht gefunden habe ???:L ... naja ... muss ich mir was einfallen lassen das das Ganze irgendwie dynamisch funktioniert



Nachtrag:

was mir aber gerade einfällt ... da ja alle Klassen in dem Package (zumindest bei mir) von einer Oberklasse erben ... kann man das Ganze evt. als Plugins lösen ... damit habe ich die Liste die ich benötige ... und wunderbar dynamisch ist das Ganze auch ... welches Package die Klassen haben, ist ja eigentlich egal



hand, mogel



PS: Gebäudetypen habe ich in einem anderen Package ^^
 
Code:
/**
 * This class lists ALL (REALLY ALL!!!) classes the Java VM could load, 
 * by iterating over ALL! available JAR-Files and reading class information from there ...
 * I KNOW it's a hack, but there is no other way to get this information ...
 */
package java.damn;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import sun.misc.Launcher;

public class ClassLister {

	public static void main(String[] args) {
		for(Package p : Package.getPackages() ) {
			System.out.println("Package:" + p);
			String pn = "/" + p.getName().replace('.', '/');
			URL url = ClassLoader.class.getResource(pn);
			if(url!=null) {
				if(url.getProtocol().equals("jar")) {
					System.out.println("URL:" + url.toString());
					String jfn = url.getFile().substring(0, url.getFile().indexOf('!'));
					String jfp = url.getFile().substring(url.getFile().indexOf('!') + 2);
					System.out.println(jfp);
					
					try {
						JarFile jar = new JarFile(new File(new URI(jfn)));
						Enumeration<JarEntry> jee = jar.entries();
						while(jee.hasMoreElements()) {
							JarEntry je = jee.nextElement();
							if(!je.isDirectory() && je.getName().endsWith(".class") //&& je.getName().startsWith(jfp)
									) {
								try {
									Class<?> jec = Class.forName(je.getName().substring(0, je.getName().length() - 6).replace('/', '.'));
									System.out.println("Class:" + jec);
								} catch (ClassNotFoundException e) {
									// TODO Automatisch erstellter Catch-Block
									e.printStackTrace();
								}
							}
						}
					} catch (IOException e2) {
						// TODO Automatisch erstellter Catch-Block
						e2.printStackTrace();
					} catch (URISyntaxException e) {
						// TODO Automatisch erstellter Catch-Block
						e.printStackTrace();
					}
					continue;
				}
				File f;
				try {
					f = new File(url.toURI());
				} catch (URISyntaxException e1) {
					// TODO Automatisch erstellter Catch-Block
					e1.printStackTrace();
					continue;
				}
				File[] l = f.listFiles();
				for(File fc: l) {
					String fcn = fc.getName();
					if(fcn.endsWith(".class")) {
						fcn = fcn.substring(0, fcn.length()-6);
						try {
							Class<?> classinfo = Class.forName(p.getName() + "." + fcn);
							System.out.println("Class:" + classinfo.getName());
						} catch (ClassNotFoundException e) {
							// TODO Automatisch erstellter Catch-Block
							e.printStackTrace();
						}
					}
				}
			}
		}
		for(URL u : Launcher.getBootstrapClassPath().getURLs()) {
			System.out.println(u);
			try {
				JarFile jar = new JarFile(new File(u.toURI()));
				Enumeration<JarEntry> jee = jar.entries();
				while(jee.hasMoreElements()) {
					JarEntry je = jee.nextElement();
					if(!je.isDirectory() && je.getName().endsWith(".class")
							) {
						try {
							Class<?> jec = Class.forName(je.getName().substring(0, je.getName().length() - 6).replace('/', '.'));
							System.out.println("Class:" + jec);
						} catch (ClassNotFoundException e) {
							// TODO Automatisch erstellter Catch-Block
							e.printStackTrace();
						} catch (UnsatisfiedLinkError e) {
							// TODO Automatisch erstellter Catch-Block
							e.printStackTrace();
						}
					}
				}
			} catch (IOException e2) {
				// TODO Automatisch erstellter Catch-Block
				e2.printStackTrace();
			} catch (URISyntaxException e) {
				// TODO Automatisch erstellter Catch-Block
				e.printStackTrace();
			}
		}
	}

}

Dazu mal noch ein Hinweis: Man sollte sich im Klaren sein, dass dieser Source jegliche Klassen initialisiert und daher der Speicherverbrauch der Java-VM schnell gegen die Limits läuft. Wer also nur die Namen der Klassen brauch um dann nur nach einem bestimmten Muster zu entscheiden, ob eine bestimmte Klasse geladen werden soll, sollte den Teil Class.forName im Beispiel auskommentieren und statt jec den als Argument für forName angegebenen String ausgaben\weiterverarbeiten.

Ich hab nach dem Prinzip einen vollständigen Loader geschrieben, der automatisch anhand eines RegExp Klassen filtert und deren Namen zurückgibt. Die gesamten VM-Klassen brauchen dann etwa eine Sekunde zum Filtern. Man muss aber für eine sinnvolle Verwendung des Ganzen jeglichen zu ladenden Klassen eine Namenskonvention aufdrücken. Das vollständige Laden ALLER Klassen geht zumindest NICHT, sei denn man gibt seiner JavaVM vollen Speicherzugriff auf >1GB RAM ...
 
Moin,

ick lasse jetzt die Ameise für mich arbeiten ... die erstellt mir eine Liste aller Klassen in dem Verzeichnis und dann habe die in einer Datei die ich einlesen kann ... damit kann ich auch leben bzw. arbeiten

hand, mogel
 
@Gast1337
This class lists ALL (REALLY ALL!!!) classes the Java VM could load
Ist natürlich Unsinn. Es ist ja kein Problem alle Klassen aller jar Files im Classpath zu lesen, aber das muss noch lange nichts mit allen Klassen im laufenden System zu tun haben.
Klassen können on-thy-fly im Speicher erstellt und geladen werden, aus einer DB, oder aus dem Internet nachgeladen werden, mit eigenen Classloadern von Netzwerkfreigabe XY geladen werden und und und.
Ausserdem verwendest du Klassen aus dem sun Package, damit ist der Code sowieso schon nutzlos.
 
Dann sollte die JavaVM eine saubere Methode für solche Aufgaben anbieten.

Und zu deinem anderen Punkt: Wenn ich eine Klasse aus einer DB erstelle, so habe ich im Anschluss eine Referenz auf diese, die ich kurz registrieren kann. Gleiches gilt aus Netzwerk-Quellen. In meinem Source ging es ja darum, Klassen, die im Bootstrap-Code vorhanden sind, und deren Quelle also nicht ohne Weiteres direkt eine Klassen-Referenz liefern, aufzulisten; und dafür funktioniert der Code sehr gut.

Und bzgl. Sun-Package: Dann zeig mal nen besseren Weg auf :meld:

@Wildcard: Sinnlos Rumschwafeln und Leute belegen, die eine Lösung suchen oder anderen Versuchen Hinweise zu geben, wie es gehen kann, ist keine Art, sich in einem Forum zu verhalten ;-)
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben