Reflection und JAR files



  • Hallo Leute

    Ich beschäftige mich zur Zeit mit einem Problem:
    Ich möchte ein Projekt von mir (Fuzzy Engine) per reflection Plug-In Fähig machen.

    Nun ist das problem das ich hier jetzt nicht einfach hergehen kann und class files in einem folder hineinlegen kann und diese per reflection auslesen

    das ganze ist schon etwas komplizierter:
    Ich will .Jar files in ein directory legen:
    Eine XML datei die enthalten ist soll notwendige konfigurationsparameter beinhalten und die klasse selbst ebenfalls

    die klasse muss natuerlich ein spezielles interface definieren .. damit ich weiss das das ganze hand und fuss hat 🙂

    ich hab mir da jetzt mal kurz was ausgedacht was ca. so aussieht

    try {
       JarInputStream JarInput = new JarInputStream(new FileInputStream(args[0]), true);
       JarEntry entry;
       while ((entry = JarInput.getNextJarEntry()) != null) {
           String classMain = entry.toString();
           //check den klassennamen ... funktioniert das so???
           if((classMain.indexOf("class")) != -1 && classMain.indexOf("$") == -1)
           {
              Class cl = Class.forName(classMain);
              //jetzt kann ich mir dann die methoden holen bzw interface checken
           }
       }
    }
    

    ich hab das problem das mein ding nicht funktioniert
    ich hab schon verschiedene sachen probiert bekomme aber entweder eine
    ClassNotFoundException oder eine violation exception (protected access)

    kann mir irgendjemand helfen und aufzeigen ob ich hier am komplett falschen weg bin um jar files dynamisch zu laden

    danke

    gomberl



  • Hier ist eine Klasse zum Laden von Jar-Archiven. Ich weis die Quelle (URL) leider nicht mehr, aber ich poste den code:

    import java.io.*;
    import java.util.*;
    import java.util.zip.*;
    
    /**
     * JarResources: JarResources maps all resources included in a
     * Zip or Jar file. Additionaly, it provides a method to extract one
     * as a blob.
     */
    
    public final class JarResources {
    
       // external debug flag
       public boolean debugOn=false;
    
       // jar resource mapping tables
       private Hashtable htSizes=new Hashtable();  
       private Hashtable htJarContents=new Hashtable();
    
       // a jar file
       private String jarFileName;
    
       /**
        * creates a JarResources. It extracts all resources from a Jar
        * into an internal hashtable, keyed by resource names.
        * @param jarFileName a jar or zip file
        */
    
       public JarResources(String jarFileName) {
          this.jarFileName=jarFileName;
          init();
       }
    
       /**
        * Extracts a jar resource as a blob.
        * @param name a resource name.
        */
    
       public byte[] getResource(String name) {
          return (byte[])htJarContents.get(name);
       }
    
       /**
        * initializes internal hash tables with Jar file resources.
        */
    
       private void init() {
    
          try {
              // extracts just sizes only. 
              ZipFile zf=new ZipFile(jarFileName);
              Enumeration e=zf.entries();
              while (e.hasMoreElements()) {
                  ZipEntry ze=(ZipEntry)e.nextElement();
                  if (debugOn) {
                     System.out.println(dumpZipEntry(ze));
                  }
                  htSizes.put(ze.getName(),new Integer((int)ze.getSize()));
              }
              zf.close();
              // extract resources and put them into the hashtable.
              FileInputStream fis=new FileInputStream(jarFileName);
              BufferedInputStream bis=new BufferedInputStream(fis);
              ZipInputStream zis=new ZipInputStream(bis);
              ZipEntry ze=null;
              while ((ze=zis.getNextEntry())!=null) {
                 if (ze.isDirectory()) {
                    continue;
                 }
                 if (debugOn) {
                    System.out.println(
                       "ze.getName()="+ze.getName()+","+"getSize()="+ze.getSize()
                       );
                 }
                 int size=(int)ze.getSize();
                 // -1 means unknown size. 
                 if (size==-1) {
                    size=((Integer)htSizes.get(ze.getName())).intValue();
                 }
                 byte[] b=new byte[(int)size];
                 int rb=0;
                 int chunk=0;
                 while (((int)size - rb) > 0) {
                     chunk=zis.read(b,rb,(int)size - rb);
                     if (chunk==-1) {
                        break;
                     }
                     rb+=chunk;
                 }
                 // add to internal resource hashtable
                 htJarContents.put(ze.getName(),b);
                 if (debugOn) {
                    System.out.println(
                       ze.getName()+"  rb="+rb+
                       ",size="+size+
                       ",csize="+ze.getCompressedSize()
                       );
                 }
              }
           } catch (NullPointerException e) {
              System.out.println("done.");
           } catch (FileNotFoundException e) {
              e.printStackTrace();
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
    
       /**
        * Dumps a zip entry into a string.
        * @param ze a ZipEntry
        */
    
       private String dumpZipEntry(ZipEntry ze) {
    
           StringBuffer sb=new StringBuffer();
           if (ze.isDirectory()) {
              sb.append("d "); 
           } else {
              sb.append("f "); 
           }
           if (ze.getMethod()==ZipEntry.STORED) {
              sb.append("stored   "); 
           } else {
              sb.append("defalted ");
           }
           sb.append(ze.getName());
           sb.append("\t");
           sb.append(""+ze.getSize());
           if (ze.getMethod()==ZipEntry.DEFLATED) {
              sb.append("/"+ze.getCompressedSize());
           }
           return (sb.toString());
       }
    
       /**
        * Is a test driver. Given a jar file and a resource name, it trys to
        * extract the resource and then tells us whether it could or not.
        *
        * <strong>Example</strong>
        * Let's say you have a JAR file which jarred up a bunch of gif image
        * files. Now, by using JarResources, you could extract, create, and display
        * those images on-the-fly.
        * <pre>
        *     ...
        *     JarResources JR=new JarResources("GifBundle.jar");
        *     Image image=Toolkit.createImage(JR.getResource("logo.gif");
        *     Image logo=Toolkit.getDefaultToolkit().createImage(
        *                   JR.getResources("logo.gif")
        *                   );
        *     ...
        * </pre>
        */
    
       public static void main(String[] args) throws IOException {
    
           if (args.length!=2) {
              System.err.println(
                 "usage: java JarResources <jar file name> <resource name>"
                 );
              System.exit(1);
           }
           JarResources jr=new JarResources(args[0]);
           byte[] buff=jr.getResource(args[1]);
           if (buff==null) {
              System.out.println("Could not find "+args[1]+".");
           } else {
              System.out.println("Found "+args[1]+ " (length="+buff.length+").");
           }
       }
    }	// End of JarResources class.
    

    Vielleicht hilft dir das weiter?



  • Danke das ist mal ne nette klasse als wrapper um ein .JAR file

    nur hat sich bei mir noch nicht das problem gelöst das ich nicht weiss wie ich jetzt aus diesem BLOB den ich bekomme ein file classe instanzieren kann

    ich schätze dazu werde ich wohl einen eigenen Class Loader brauchen

    danke jedenfallls



  • Also durch diese Klasse kriegt man doch ein Byte-Array einer beliebigen Resource innerhalb des Archivs. Vielleicht kannst du folgender Maßen ein Objekt draus kriegen:

    byte[] b = jr.getResource("Verzeichnis/Klasse.class");
    Object o = (new Object()).getClass().getClassLoader().defineClass("Klasse", b, 0, b.length).newInstance(); // Also defineClass(String, int, int, int) hat Class als Rückgabewert
    

    Es nur ein Vorschlag, vielleicht klappt es ja. Zumindest hast du so nun ein Objekt aus dem byte-array bekommen. Das glaube ich jedenfalls! 😃



  • Ich habs jetzt zusammengebracht (Eigentlich schon freitags)

    hier der code ausschnitt um aus einem jar file zu laden
    es lädt eine klasse aus dem file, schaut nach ob sie ein bestimmtest interface implementiert und checkt dann ob es einen spezifischen konstruktor gibt
    wenn ja lädt sie ein objekt der neuen klasse

    JARClassLoader ist hier nur ein etwas vereinfachter URL Class Loader

    JARClassLoader ClassLoaderObject = new JARClassLoader(CurFile.toURL());
                                            //load class
                                            Class ModuleClass = ClassLoaderObject.loadClass(ClassName);
                                            //check if ObjectClass Implements Interface
                                            Class[] Interfaces = this.getAllInterfaces(ModuleClass);//ModuleClass.getInterfaces();
    
                                            boolean isModule = false;
                                            for(int j=0; (j < Interfaces.length) && (isModule == false); i++){
                                                //System.out.println("\n\nCurrentInterface: " + Interfaces[i].getName() + " comparing to " + InterfaceClass.getName());
                                                if(InterfaceClass.isAssignableFrom(Interfaces[i])){
                                                    //this is a correct class object
                                                    isModule = true;
                                                }
                                            }
                                            if(isModule){
                                                //load class object new instance
                                                System.out.println("Loading Module: " + ModuleClass.getName());
                                                try{
                                                    //instantiate object with constructor
                                                    Constructor ModuleConstructor = ModuleClass.getConstructor(ConstructorParams);
                                                    Object[] ConsParameter = new Object[2];
                                                    ConsParameter[0] = id;
                                                    ConsParameter[1] = config;
                                                    ret = (AbstractModule) ModuleConstructor.newInstance(ConsParameter);
                                                    System.out.println("Created Object");
                                                    //save object into hash
                                                    cacheObject(ret,type,id);
                                                    //ret = (AbstractModule) ModuleClass.newInstance();
                                                }
                                                catch(Exception ex){
                                                    ex.printStackTrace();
                                                    throw new ClassNotFoundException("Constructor could not be instantiated. Class might not have correct PortalNode Constructor");
                                                }
    

    im endeffekt macht der URLClassLoader alles das man braucht


Anmelden zum Antworten