2010-11-17 5 views
2

Dans le code ci-dessous, je génère une classe dynamiquement en utilisant sun.tools.javac.Main. Je vais créer une nouvelle instance de cette classe en utilisant Reflection. Le problème est, je veux éviter d'utiliser Reflection pour invoquer la méthode que j'ai définie pour cette classe, donc j'ai créé un ProxyInvoker qui référence une interface que j'ai définie dans mon projet. Pour que le chargeur de classe puisse le voir, j'ajoute le classpath à l'interface Executable à mon chargeur de classe. Je reçois toujours une erreur lors de l'étape de compilation qui indique que mon interface n'a pas été trouvée.Pourquoi le chargeur de classe Java ne trouve-t-il pas mon interface?

import java.io.ByteArrayOutputStream; 
import java.io.File; 
import java.io.FileWriter; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLClassLoader; 

public class MyClassGenerator { 

    static final String generatedClassName = "TestHello_" + System.currentTimeMillis(); 
    static final String javaFileName = generatedClassName + ".java"; 

    static URLClassLoader classLoader; 

    public static void main(final String args[]) 
      throws MalformedURLException { 
     final ProxyInvoker proxy = new ProxyInvoker(); 
     generateClass(); 
     loadExecutableInterface(); 
     if (compileClass()) { 
      System.out.println("Running " + generatedClassName + ":\n\n"); 
      final Executable ex = createExecutable(); 
      ex.execute(); 
     } 
     else { 
      System.out.println(javaFileName + " is bad."); 
     } 
    } 

    public static void loadExecutableInterface() 
      throws MalformedURLException { 

     final File file = new File("."); // <-- the directory where the generated java class is defined 
     final File file2 = new File("src"); // <-- the directory where interface Executable is defined 

     try { 
      classLoader = URLClassLoader.newInstance(new URL[] { file.toURI().toURL(), file2.toURI().toURL() }); 
      try { 
       classLoader.loadClass("Executable"); 
      } 
      catch (final ClassNotFoundException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     catch (final MalformedURLException e) { 
      e.printStackTrace(); 
     } 
     System.out.println(file.toURI().toURL()); 
     System.out.println(file2.toURI().toURL()); 

    } 

    public static void generateClass() { 
     try { 
      final FileWriter aWriter = new FileWriter(javaFileName, true); 
      aWriter.write("public class " + generatedClassName + " implements Executable {"); 
      aWriter.write("\n"); 
      aWriter.write("\n"); 
      aWriter.write(" public void invoke() {"); 
      aWriter.write("  System.out.println(\"Hello World!\");"); 
      aWriter.write(" }"); 
      aWriter.write("\n"); 
      aWriter.write("}"); 
      aWriter.flush(); 
      aWriter.close(); 
     } 
     catch (final Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static boolean compileClass() { 
     final String[] source = { new String(javaFileName) }; 
     final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     new sun.tools.javac.Main(baos, source[0]).compile(source); 
     System.out.print(baos.toString()); 
     return (baos.toString().indexOf("error") == -1); 
    } 

    public static Executable createExecutable() { 

     Executable instance = null; 

     try { 
      final Class<?> genClass = Class.forName(generatedClassName, true, classLoader); 
      instance = (Executable) genClass.newInstance(); 
     } 
     catch (final Exception e) { 
      e.printStackTrace(); 
     } 

     return instance; 

    } 
} 

class ProxyInvoker { 

    Executable myExecutable; 

    public void runIt() { 

     final Executable myExecutable; 

    } 

} 

Répondre

6

Voici une version de travail de votre code:

import java.io.ByteArrayOutputStream; 
import java.io.File; 
import java.io.FileWriter; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLClassLoader; 

public class MyClassGenerator { 

    static final String generatedClassName = "TestHello_" + System.currentTimeMillis(); 
    static final String javaFileName = generatedClassName + ".java"; 

    static URLClassLoader classLoader; 

    public static void main(final String args[]) 
      throws MalformedURLException { 
     generateClass(); 
     loadExecutableInterface(); 
     if (compileClass()) { 
      System.out.println("Running " + generatedClassName + ":\n\n"); 
      final Executable ex = createExecutable(); 
      ex.execute(); 
     } 
     else { 
      System.out.println(javaFileName + " is bad."); 
     } 
    } 

    public static void loadExecutableInterface() 
      throws MalformedURLException { 

     final File file = new File("."); // <-- the directory where the generated java class is defined 

     try { 
      classLoader = URLClassLoader.newInstance(new URL[] { file.toURI().toURL() }, Executable.class.getClassLoader()); 
      try { 
       classLoader.loadClass("Executable"); 
      } 
      catch (final ClassNotFoundException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     catch (final MalformedURLException e) { 
      e.printStackTrace(); 
     } 
     System.out.println(file.toURI().toURL()); 

    } 

    public static void generateClass() { 
     try { 
      final FileWriter aWriter = new FileWriter(javaFileName, true); 
      aWriter.write("public class " + generatedClassName + " implements Executable {"); 
      aWriter.write("\n"); 
      aWriter.write("\n"); 
      aWriter.write(" public void execute() {"); 
      aWriter.write("  System.out.println(\"Hello World!\");"); 
      aWriter.write(" }"); 
      aWriter.write("\n"); 
      aWriter.write("}"); 
      aWriter.flush(); 
      aWriter.close(); 
     } 
     catch (final Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static boolean compileClass() { 
     final String[] source = { "-classpath", "target/classes", javaFileName }; 
     final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     new sun.tools.javac.Main(baos, source[0]).compile(source); 
     System.out.print(baos.toString()); 
     return (baos.toString().indexOf("error") == -1); 
    } 

    public static Executable createExecutable() { 

     Executable instance = null; 

     try { 
      final Class<?> genClass = Class.forName(generatedClassName, true, classLoader); 
      instance = (Executable) genClass.newInstance(); 
     } 
     catch (final Exception e) { 
      e.printStackTrace(); 
     } 

     return instance; 

    } 

} 

Les principaux changements : pièces classloader et de compilation ont eu tort.

+0

La version du compilateur que vous utilisez est obsolète, mais le reste fonctionne. –

+1

Ce n'est pas moi qui utilise ce compilateur, c'est vous :-P J'ai seulement changé les parties du code qui étaient nécessaires pour le faire fonctionner (et maintenant mis à jour le code pour minimiser le nombre de changements inutiles). –