Wie erzeuge ich aus einem Dateinamen-String eine Klasse ?

MariusMeuser

Mitglied
Hallo,
ich habe folgendes Problem:

Wir schreiben ein Programm, das über Plugins erweiterbar sein soll. Diese Plugin liegen in Form von *.class Dateien in dem Verzeichnis plugins. Eine Liste der verfügbaren Plugins in der Form String[] bekomme ich, indem ich das Verzeichniss auslese und alle namentlich korrekten Plugins filtere.

Nun will ich aus diesem String[] eben diese Plugins, die in dem Ordner liegen instanziieren und diese Objekte anschließend in einen Vector legen. Ich wollte das Array in einer Schleife abarbeiten, allerdings fehlt mir das Wissen, wie ich aus diesen String, die exakt den Dateinamen entsprechen, die jeweiligen Objecte erzeugen.

Ich hoffe ihr könnt mir dabei helfen und danke schonmal im Vorraus für die Hilfe.

MfG

MariusMeuser
 
Hallo,

dafür gibt es die methode Class.ForName(String),

um eine Instanz von dieser klasse zu bekommen machst du dann:

Object newObject = Class.forName(<Klassennamen>).newInstance();

wie es mit dem casten aussieht, weiss ich jetzt nicht allzu genau.

Hiermit hast du jetzt eine Instanz erzeugt die aber nicht auf die Funktionen der klasse zurückgreifen kann, dazu musst du noch einen type-cast machen.

Such mal hier im Forum nach dem stichwort:

Reflection, das ist nämlich das was Du hier machen willst....

Gruss
Torsten.
 
Oder auch so:

Code:
class TestClassApp{

        Object o;
        Class cl;

        public TestClassApp(String className){

                try{
                        cl = ClassLoader.getSystemClassLoader().loadClass(className);
                }
                catch(ClassNotFoundException e){ 
                        System.out.println("Class not found :-(");      
                        e.printStackTrace(); 
                }
        }
    
        public void instanceObject(Object[] param){

                try{
                        o = cl.getConstructor().newInstance(param);
                }
                catch(Exception e){  
                        System.out.println("could not instantiate object from class :-(");
                        e.printStackTrace(); 
                }
        }                    
                
        public void executeMethod(String methodName, Object[] param){

                try{
                        o = cl.getMethod(methodName).invoke(o, param);
                }
                catch(Exception e){  
                        System.out.println("could not execute method on object");
                        e.printStackTrace(); 
                }
        }
        
        public static void main(String[] args){ 
        
                TestClassApp test = new TestClassApp("TestClass");
                test.instanceObject((Object[])null);
                test.executeMethod("foo", (Object[])null);
        }
}

Wobei natürlich zu beachten ist, das der CLASSPATH auf dem entsprechenden Verzeichniss
wo deine *.class Klassen liegen gesetzt ist...

//edit siehe dazu auch:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html
Gruß

RedWing
 
Zuletzt bearbeitet:
Erstmal THX.

Ich bekomme hierbei leider 2 Fehlermeldungen beim compilieren des Codes. (siehe Code)

Wäre echt toll, wenn ihr das nochmal schnell korrigieren könntet. Ich gehe mal davon aus,
dass es sich nur um kleine Fehler handeln kann !

Code:
class TestClassApp{

        Object o;
        Class cl;

        public TestClassApp(String className){

                try{
                        cl = ClassLoader.getSystemClassLoader().loadClass(className);
                }
                catch(ClassNotFoundException e){ 
                        System.out.println("Class not found :-(");      
                        e.printStackTrace(); 
                }
        }
    
        public void instanceObject(Object[] param){

                try{
                        o = cl.getConstructor().newInstance(param);
Fehler: "createClassByName.java": getConstructor(java.lang.Class[]) in java.lang.Class cannot be applied to () 


                }
                catch(Exception e){  
                        System.out.println("could not instantiate object from class :-(");
                        e.printStackTrace(); 
                }
        }                    
                
        public void executeMethod(String methodName, Object[] param){

                try{
                        o = cl.getMethod(methodName).invoke(o, param);
Fehler: "createClassByName.java": getMethod(java.lang.String,java.lang.Class[]) in java.lang.Class cannot be applied to (java.lang.String)

                }
                catch(Exception e){  
                        System.out.println("could not execute method on object");
                        e.printStackTrace(); 
                }
        }
        
        public static void main(String[] args){ 
        
                TestClassApp test = new TestClassApp("TestClass");
                test.instanceObject((Object[])null);
                test.executeMethod("foo", (Object[])null);
        }
}
 
Und wie lauten die genauen Meldungen der Fehler?

Könntest du das vielleicht noch posten, wäre hilfreich!

Danke

Gruss
Torsten

EDIT: Argh, okay, stehen ja im Source drin, demnächst der übersichtlichkeit einfach, nicht im Code reinhängen. ;)
 
Hi erster fehler:

getClassConstructor() existiert so nicht, ein blick in die API Docs ergibt folgendes:


Constructor getConstructor(Class[] parameterTypes)
Returns a Constructor object that reflects the specified public constructor of the
class represented by this Class object.


Du versuchst eine Funktion aufzurufen, welche es gar nicht gibt.


zweitens:

selber fehler, die korrekte syntax ist:

Method getMethod(String name, Class[] parameterTypes)
Returns a Method object that reflects the specified public member method of the
class or interface represented by this Class object.



wobei das Array parameterTypes von klassen folgendes bedeutet: <zitat>:
The parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order. If parameterTypes is null, it is treated as if it were an empty array.
<zitatende>

Sprich du kannst, wenn du keine Parameter übergeben brauchst nur null als param mitzugeben. Ansonsten, die Parameter in benötigter Reihenfolge.

Kurzer Tipp: Entweder eine geeignete IDE wie z.B.:Eclipse benutzen, welche hilft solche fehler vorzubeugen und/oder die API Docs von Java zu rate ziehen für eine korrekte anwendung der Funktionen ;)

Gruss

Torsten
 
Der Code stammt nicht von mir, sondern wurde als Lösung auf die Frage dieses Threads
gepostet !

Daher meine Frage woher diese Fehler rühren. Das da was nicht stimmt wusste ich auch schon.
Ich dachte daher daran, dass man (der poster dieses Codes) vielleicht ne funktionsfähige
Version posten könnte.

MfG

Marius Meuser
 
Axo,

naja, jetzt kannste ja den Code selbst korrigieren, kann schon mal im eifer des gefechtes passieren ;)

Sollte ja auch kein Vorwurf sein, war nur eine kleine Empfehlung zum besseren Arbeiten ;)


Gruss

Torsten.
 
MariusMeuser hat gesagt.:
Der Code stammt nicht von mir, sondern wurde als Lösung auf die Frage dieses Threads
gepostet !

Daher meine Frage woher diese Fehler rühren. Das da was nicht stimmt wusste ich auch schon.
Ich dachte daher daran, dass man (der poster dieses Codes) vielleicht ne funktionsfähige
Version posten könnte.

MfG

Marius Meuser
torsch2711 hat gesagt.:
Axo,

naja, jetzt kannste ja den Code selbst korrigieren, kann schon mal im eifer des gefechtes passieren

Sollte ja auch kein Vorwurf sein, war nur eine kleine Empfehlung zum besseren Arbeiten


Gruss

Torsten.

Mhm bei mir hat das ganze perfekt compiliert.
Allerdings arbeite ich auch unter 1.5 und hab den Code nich abwärtskompatibel
gebaut.
In 1.5 isses mittlerweile möglich einer Funktion beliebige Parameter zu übergeben
die dann als Feld innerhalb der Funktion angesprochen werden können.
Die Funktion Class.getConstrtor() der Java API is so eine.
Da das < 1.5 nicht möglich ist ließ sich der Code bei dir auch nicht kompilieren,
sorry nochmal dafür
Bsp:

Code:
class TestClassApp{

     
        static int add(int... a){

                if(a.length == 2)
                        return a[0] + a[1];
                else if(a.length == 1)
                        return a[0] + 2;
                else
                        return 0;
                
        }
        public static void main(String[] args){ 
        
                System.out.println(add());
                System.out.println(add(1));
                System.out.println(add(1, 2));
        }
}

Gruß

RedWing
 
Sop, habe jetzt den Code entsprechend angepasst.
Allerdings bekomme ich eine Fehlermeldung, die ich nicht zuordnen kann !

Fehlermeldung:

java.lang.ClassNotFoundException: TestPlugin

at java.net.URLClassLoader$1.run(URLClassLoader.java:199)

at java.security.AccessController.doPrivileged(Native Method)

at java.net.URLClassLoader.findClass(URLClassLoader.java:187)

at java.lang.ClassLoader.loadClass(ClassLoader.java:289)

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)

at java.lang.ClassLoader.loadClass(ClassLoader.java:235)

at mconvert.CreateClassByName.<init>(CreateClassByName.java:11)

at mconvert.PluginManager.initiatePlugins(PluginManager.java:56)Class not found :-(



at mconvert.PluginManager.main(PluginManager.java:70)

java.lang.NullPointerException

at mconvert.CreateClassByName.instanceObject(CreateClassByName.java:22)

at mconvert.PluginManager.initiatePlugins(PluginManager.java:57)

at mconvert.PluginManager.main(PluginManager.java:70)

could not instantiate object from class :-(

Die entsprechenden Klassen:

Code:
  public Vector initiatePlugins() {
    this.loadPlugins();
    Vector v = new Vector();
    try {
     for (int i = 0; i < availablePlugins.length; i++) {
        CreateClassByName cl = new CreateClassByName(availablePlugins[i]);
        Object o = cl.instanceObject((Object[])null);
        v.add(o);
      }
    }
    catch (Exception e) {
      System.out.println("Fehler: " + e.getMessage());
    }

    return v;
  }

  public static void main(String[] args) {
    PluginManager pm = new PluginManager();
    pm.initiatePlugins();
   /* for (int i = 0; i < pm.availablePlugins.length; i++) {
      System.out.println(pm.availablePlugins[i]);
      System.out.println(pm.pluginsPathes[i]);
    }*/
  }
}


Code:
class CreateClassByName {

  Object o;
  Class cl;

  public CreateClassByName(String className) {

    try {
      cl = ClassLoader.getSystemClassLoader().loadClass(className);
    }
    catch (ClassNotFoundException e) {
      System.out.println("Class not found :-(");
      e.printStackTrace();
    }
  }

  public Object instanceObject(Object[] param) {

    try {
      o = cl.getConstructor(null).newInstance(param);
    }
    catch (Exception e) {
      System.out.println("could not instantiate object from class :-(");
      e.printStackTrace();
    }
    return o;
  }

  public void executeMethod(String methodName, Object[] param) {
    try {
      o = cl.getMethod(methodName, null).invoke(o, param);
    }
    catch (Exception e) {
      System.out.println("could not execute method on object");
      e.printStackTrace();
    }
  }
}

Das hier ist die CLass die initialisiert werden soll:

Code:
package mconvert;

/**
 * <p>Title: MConvert</p>
 * <p>Description: Multiformat Converter</p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Company: </p>
 * @author Die 2 Lustigen 3
 * @version 1.0
 */

public class TestPlugin
    implements PluginInterface {

  public TestPlugin(){
    System.out.println("Instanz des TestPlugins erfolgreich erzeugt");
  }
  /**
   * convert
   *
   * @param source String
   * @param target String
   * @param form Format
   * @todo Implement this mconvert.PluginInterface method
   */
  public void convert(String source, String target, Format form) {
    System.out.println("Convert Mehtode erfolgreich aufgerufen !");
  }

  /**
   * getName
   *
   * @return String
   * @todo Implement this mconvert.PluginInterface method
   */
  public String getName() {
    return "TestPlugin";
  }

  /**
   * hasStatus
   *
   * @return boolean
   * @todo Implement this mconvert.PluginInterface method
   */
  public boolean hasStatus() {
    System.out.println("hasStatus erfolgreich aufgerufen");
    return false;
  }

  /**
   * getStatus
   *
   * @return String
   * @todo Implement this mconvert.PluginInterface method
   */
  public String getStatus() {
    return "hier kommt der Status";
  }

  /**
   * hasOptions
   *
   * @return boolean
   * @todo Implement this mconvert.PluginInterface method
   */
  public boolean hasOptions() {
    System.out.println("hasOptions erfolgreich aufgerufen");
    return false;
  }

  /**
   * showOptions
   *
   * @param Format String[]
   * @todo Implement this mconvert.PluginInterface method
   */
  public void showOptions(String[] Format) {
    System.out.println("showOptions erfolgreich aufgerufen");
  }

  /**
   * getConvertableFormats
   *
   * @return FormatList
   * @todo Implement this mconvert.PluginInterface method
   */
  public FormatList getConvertableFormats() {
    System.out.println("getConvertableFormats erfolgreich aufgerufen");
    return null;
  }

  /**
   * stopAll
   *
   * @todo Implement this mconvert.PluginInterface method
   */
  public void stopAll() {
    System.out.println("stopAll erfolgreich aufgerufen");
  }

  /**
   * isBusy
   *
   * @return boolean
   * @todo Implement this mconvert.PluginInterface method
   */
  public boolean isBusy() {
    System.out.println("isBusy erfolgreich aufgerufen");
    return false;
  }
}

Wäre tolle wenn jemandem auffällt, was ich falsch gemacht habe !

Habe bei mir das JDK 1.5 installiert und auch in meiner IDE eingetragen, scheint alledings nicht verwendet zu werden :(

MfG

Marius Meuser
 
Zurück