Dynamischer Klassenaufruf ->Class.forName().newInstance()

raphk

Mitglied
Hallo

Ich habe ein Problem bei einem Programm das einen dynamischen Klassenaufruf erzeugen soll. Im Endeffekt gehts darum eine XML Datei auszulesen. Dann bestimmt man via DropDown Liste im Programm welche Klasse die XML bearbeitet und diese führt dann je nach Klasse bestimmte Funktionen mit den XML Tags aus.

Also ganz banal gesagt:
Code:
 if(vendor.equals("reservation_simple"))
        {
            commandesXML rs = new reservation_simple(aa);
            
            return rs;
        }
        else if(vendor.equals("reservation_advance"))
        {
            commandesXML rs = new reservation_advance(aa);
            
            return rs;
        }
... wobei vendor die Klasse ist, die aufgerufen wird und commandesXML die Überklasse. So wies hier steht funktionniert das Programm auch wunderbar.

Jetzt will ich aber das ganze dynamisch machen sprich anstatt mit den if(vendor == X) else .... nur noch eine Funktione die sich via Class.forName() ihre Klasse selber sucht und diese dann aufruft. Also quasi so in etwa:
Code:
Class clazz = Class.forName(vendor);
Object o = clazz.newInstance();
Problem ist nur das das bei mir immer zu nem Error führt. Ausserdem besitzen die Klassen in ihrem Konstruktor eine Variable die man mitgibt. Und ein newINstance(VARIABLE) funktionniert auch nicht.

Naja ich hoffe mal ihr habt plus minus verstanden worum es mir geht und noch mehr hoffe ich das mir einer weiter helfen kann!
 
Hallo du musst dir erst einen Konstruktor holen bevor du dir ein Objekt holen kannst.

Ungefähr so:

Code:
import java.lang.Class;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

class Foo{
    
    public Foo(int para1, int para2){
        System.out.println("Creating an object for class Foo with para1=" + para1 + " and para2=" + para2);
    }   
    
    public int add(int a, int b){
        return a+b;
    }   
}   
class ReflectionExample{
    
    public static void main(String[] args) throws Exception{
        Class cl = Class.forName("Foo");
        Object o = cl.getConstructor(Integer.TYPE, Integer.TYPE).newInstance(1,2);
        Method m = cl.getMethod("add", Integer.TYPE, Integer.TYPE);
        System.out.println(m.invoke(o, 5,10));
    }
}

Gruß

RedWing
 
Hallo ralphK
ich weiß nicht genau ob ich mit dem was du haben willst richtig liege....
Verstehe ich Dich richtig, dass Du gerne so eine Art PlugIn bauen möchtest? Also Deine Dropdownliste soll durch Programm initialisierung zur Laufzeit mit den möglichen Optionen, sprich Klassen versorgt werden, gelle?

Für solche Zwecke hatte ich mal durch Zufall einige Zeilen Code irgendwo entdeckt, die ich dann für meine Zwecke angepasst hatte. Dabei wird davon ausgegangen, dass eine Beispielklasse (Oberklasse, oder Interface) angegeben wirde und vielleicht noch einen letzten Qualifire für das darunterliegende Paket in dem diese Beispielklasse drinne liegt.
Anhand des angegebenen Typs werden dann im Zielpaket alle Klassen herausgefuselt und zur Verfügung gestellt.

Code:
package de.cmk.util;

import java.util.*;

import java.util.zip.*;
import java.util.jar.*;
import java.net.*;
import java.io.*;

import javax.swing.JProgressBar;

/**
* ClassCollector sammelt Klassen einer Gegebenen unter Vorgabe eines
* Unterverzeichnises, welches direkt unter dem Package der gegebenen Klasse
* liegt.
* Diese Klasse ist zum dynamischen Zuladen von Klassen geeignet. Auf diese Weise
* können z.B. Unterdialoge zur Laufzeit einem Übergeordneten Panel zugeordnet werden
*/

public class ClassCollector
{
    Vector m_classNames = new Vector();
    String m_path;
    String m_packageName;
    String m_subPackageName;
    String m_lastQual;
    Class  m_class;



    public ClassCollector(Class klasse, String lastQualifier)
    {
        m_class          = klasse;
        m_path           = m_class.getResource("").getFile();
        m_lastQual       = lastQualifier;
        m_packageName    = m_class.getName().substring(0, m_class.getName().lastIndexOf('.'));
        if (m_lastQual!=null && m_lastQual.length()>0)
        {
            m_subPackageName = m_packageName + '.' + m_lastQual;
        }
        else
        {
            m_subPackageName = m_packageName;
        }

        try
        {
            collectClassNames();
        }
        catch (Exception e)
        {
            MExceptionHandler.handleException(e);
        }
    } // end of ClassCollector(Class, String)

    protected void collectClassNames() throws Exception
    {
        Vector classFileNames = new Vector();

        if (m_class.getResource("").getProtocol().equalsIgnoreCase("jar"))
        {
            URLConnection urlConn = m_class.getResource("").openConnection();
            if (!(urlConn instanceof JarURLConnection))
            {
                throw new Exception("Is jar file but has no JarURLConnection");
            }
            JarURLConnection jarConn = (JarURLConnection)urlConn;
            JarFile jarFile = jarConn.getJarFile();
            for (Enumeration e = jarFile.entries(); e.hasMoreElements(); )
            {
                JarEntry currentEntry = (JarEntry)e.nextElement();
                if (currentEntry.getName().startsWith(m_path)
                    &&!currentEntry.isDirectory())
                {
                    classFileNames.add(currentEntry.getName());
                } // end of if
            } // end of for e
        } // end of if(Classe in einer .jar Datei)
        else
        {
            URL url;

            url = m_class.getResource("/"+m_subPackageName.replace('.','/'));
//            System.out.println("2. url="+url.toString());
            if (url==null)
            {
                throw new Exception("Kann "+m_lastQual+" Verzeichnis nicht finden"+
                                    "\nres="+m_class.getResource(""));
            }
            File demosDir = new File(url.getFile());

            if (demosDir==null)
            {
                throw new Exception("Kann "+m_lastQual+" Verzeichnis nicht finden"+
                                    "\n url="+url);
            }

            if (!demosDir.isDirectory())
            {
                throw new Exception(m_lastQual+" ist kein Verzeichnis"+
                                    "\n url="+url+
                                    "\n file="+demosDir);
            }
            String[] list = demosDir.list();

            for (int i = 0; i<list.length; i++)
            {
                String fullName = m_subPackageName+"."+list[i];
                classFileNames.add(fullName);
            }
        } // end of if else (Classe in einer .jar Datei)

        for (int i = 0; i<classFileNames.size(); i++)
        {
            String currentName = (String)classFileNames.get(i);
            if (currentName.indexOf("$")==-1 && currentName.endsWith(".class"))
            {
                // remove trailing ".class"
                currentName = currentName.substring(0, currentName.length()-6);
                StringBuffer tmp = new StringBuffer(currentName);
                for (int j = 0; j<tmp.length(); j++)
                {
                    if (tmp.charAt(j)=='/'||tmp.charAt(j)=='\\')
                        tmp.setCharAt(j, '.');
                }
                m_classNames.add(tmp.toString());
            }
        }

    } // end of collectClassNames()

    public List loadClasses(JProgressBar progressBar)
    {
        List loadedClasses = new ArrayList();
        int count = progressBar.getValue();

        for (int i = 0; i<m_classNames.size(); i++)
        {
            String className = (String)m_classNames.get(i);
            String progressName = className.substring(m_subPackageName.length()+1,
                className.length());
            progressBar.setValue(count++);
            progressBar.setString("Lade "+progressName);
            try
            {
                Class currentClass = Class.forName(className);
                Object obj = currentClass.newInstance();

                if (m_class.isInstance(obj))
                {
                    loadedClasses.add(obj);
                }

            }
            catch (Exception e)
            {
                MExceptionHandler.handleException(e);
            }
        }
        return loadedClasses;
    } // end of loadClasses(JProgressBar)

    public List loadClasses()
    {
        List loadedClasses = new ArrayList();

        for (int i = 0; i<m_classNames.size(); i++)
        {
            try
            {
                Class currentClass = Class.forName((String)m_classNames.get(i));
                if (!currentClass.isInterface())
                {
                    Object obj = currentClass.newInstance();
                    if(m_class.isInstance(obj))
                    {
                        loadedClasses.add(obj);
                    }
                }
            }
            catch (Exception e)
            {
                MExceptionHandler.handleException(e);
            }
        }
        return loadedClasses;
    } // end of loadClasses()

    public String[] getClassNames()
    {
        return (String[])m_classNames.toArray((Object[])new String[0]);
    }

    public String getClassName(int i)
    {
        return (String)m_classNames.get(i);
    }

} // end of ClassCollector

hier noch kurz der Code bezüglich meines (schon fast legendären) MExceptionhandlers
Natürlich kannst das auch weglassen und nach Deinem Gutdünken ändern.
Hier erstmal ein Interface
Code:
package de.cmk.util;

public interface ExceptionHandlerLike
{
    public void handleException(Exception e);
}

und hier der Dekorierer mit defaultimplementierung

Code:
package de.cmk.util;

import javax.swing.*;

//import loggings.VersionController;

/**
* Statische Klasse, die als zentraler Exceptionhandler verwendet
* wird. Kann, wenn Bedarf besteht, mit einem anderen Verhalten
* (z.B: in der Hauptklasse) mittels setHandler() konfiguriert
* werden.
*/
public class MExceptionHandler
{
    static private ExceptionHandlerLike eHandle = new DefaultEHandler();
  
    static public void setHandler(ExceptionHandlerLike eHandler)
    {
    	eHandle = eHandler;
    }

    static public void handleException(Exception e)
    {
    	eHandle.handleException(e);
    }

}// end of class MExceptionHandler


class DefaultEHandler implements ExceptionHandlerLike
{
    public void handleException(Exception e)
    {
        e.printStackTrace();
        JOptionPane.showMessageDialog(null, e);
    }
}// end of class DefaultEHandler

Also in der Hoffnung das das alles follständig ist :)
Also ich habe diese Klasse schon mindestens 2 mal erfolgreich verwendet. Es muss dann nur festgelegt sein in welchem Packet sie die speziellen anderen Klassen befinden sollen und nach welchem Typ zu suchen ist, dann werden die bibliotheken durch sucht, so ich das richtig interpretiere :)

viel Spaß damit

Takidoso
 
Danke euch beiden. Also im Moment ist RedWings Lösung das was ich zur Zeit am Probieren bin. Takidosos Vorschlag wird wahrscheinlich später noch eingebaut! :suspekt:

Ich hab allerdings immer noch ein Problem.

Code:
Object o = cl.getConstructor(Integer.TYPE, Integer.TYPE).newInstance(1,2);
So klappt das für Integer. Aber wie schreib ich das denn wenn ich ein Klassenobjekt mitgeb. Also mein Konstruktor sieht folgendermaßen aus:
Code:
 public reservation_simple(RESERVATION res) 
    {
        objRes = res;
    }
Und wenn ich einfach getConstructor(RESERVATION).newInstance(res) oder auch getConstructor(Package.RESERVATION) mach kommt ein Fehler und anders wüsst ich nicht was ich da reinschreiben sollte.
 
Hallo!

Schau mal hier:
Code:
 /**
  * 
  */
 package de.tutorials;
 
 /**
  * @author Tom
  * 
  */
 public class DynamicInstantiationExample {
 
 	/**
 	 * @param args
 	 */
 	public static void main(String[] args) throws Exception {
 		Object[] values = { "Hallo", new int[] { 1, 2, 3 },
 			    Double.valueOf(10.0D),new Reservation("Thomas") };
 		for (int i = 0; i < values.length; i++) {
 			Foo.class.getDeclaredConstructor(
 				    new Class[] { values[i].getClass() }).newInstance(
 				    new Object[] { values[i] });
 		}
 	}
 
 	static class Foo {
 		public Foo(String value) {
 			System.out.println("Constructor Foo(String) invoked");
 		}
 
 		public Foo(int[] value) {
 			System.out.println("Constructor Foo(int[]) invoked");
 		}
 
 		public Foo(Double value) {
 			System.out.println("Constructor Foo(Double) invoked");
 		}
 		
 		public Foo(Reservation reservation) {
 			System.out.println("Constructor Foo(Reservation) invoked");
 		}
 	}
 	
 	static class Reservation{
 		String data;
 		public Reservation(String data){
 			this.data = data;
 		}
 	}
 }

Gruß Tom
 
hmm also ich hab inzwischen ein neues Problem. Wenn ich die Methode Class.forName("x") mach sagt der mir das die Klasse nicht gefunden wird obschon diese vorhanden ist und auch alles richtig geschrieben ist.
Weiss evtl einer woran das liegen könnte?
 
Code:
Object[] values = { "Hallo", new int[] { 1, 2, 3 }, Double.valueOf(10.0D),new Reservation("Thomas") };
In derLinie gibst du ja aber die Klasse an (new Reservation("Thomas")). Ich hab deren aber 4 die unterschiedliche Funktionen ausführen und die der User im Programm via Drop Down selber auswählt. Also weiss ich ja im Vorraus nie welche Klasse aufgerufen wird. Dehalb kann ich das so nicht schreiben weils ja dann an dynamität verlieren würde. Nur anders fällt mir im Moment auch nüscht ein! :confused:
 
Hallo!

Wenn du noch 2 Zeilen untendrunter schauen würdest, könntest du auch die Verwendung von getClass() sehen: ;-)
Code:
 Foo.class.getDeclaredConstructor(
 			 		new Class[] { values[i].getClass() }).newInstance(
 			 		new Object[] { values[i] });

Gruß Tom
 
Zurück