Compilar en tiempo de ejecución

Hoy hemos decidido salirnos un poco de la programación en Android y marcarnos por la programación básica en java.

Nos surgió poder ejecutar un fichero java sin compilar en tiempo de ejecución y empezamos a investigar. Después de leer la documentación de Oracle vimos como a partir de la java 1.6 existía una herramienta que permitiría compilar un fichero java en cualquier momento y nos pusimos manos a la obra. Esta herramienta es la ToolProvider.

Después de conseguir ejemplos en un ejecutable por  consola fuimos un paso más adelante intentando hacerlo en un servidor, en este caso un Tomcat 6. Para poder compilar, necesitamos tener el classloader para poder salvar los jar de los que vamos a depender a la hora de compilar.


    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();

    List<String> options = new ArrayList<String>();
    options.add("-classpath");
    StringBuffer cp = new StringBuffer();

    String firstRoute = "";
    for (URL url : urlClassLoader.getURLs()){
       String urlFile = url.getFile();
       if(!File.separator.equals("/")){
          urlFile = urlFile.substring(1);
       }
       if(StringUtils.isEmpty(firstRoute)){
          firstRoute = urlFile;
       }
       cp.append(urlFile).append(File.pathSeparator);
    }
    // Construimos las opciones de compilacion
    options.add(cp.toString());
    options.add("-d");
    options.add(firstRoute);

Importante usar la opción “-d” cuando estamos en un servidor para que otro módulo del sistema tenga acceso a la misma. Ese “firstRoute” nos marca el “WEB-INF/classes” de nuestra aplicación web. Una vez que ya tenemos construidas las opciones de compilación ya sólo nos queda coger el fichero y compilarlo.


InputStream fichero = new FileinputStream("C:\Ejemplo.java");

List<JavaFileObject> jsFiles = new ArrayList<JavaFileObject>();

jsFiles.add(new CtrlzAppsJavaFileObject("es.ctrlzapps.Ejemplo", fichero));

DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

// Se realiza la compilacion
if(!compiler.getTask(null, compiler.getStandardFileManager(null, null, null), diagnostics, options, null, jsFiles).call()){
// No hay compilacion
    for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()){
        logger.error("Error en la linea " + diagnostic.getLineNumber() + " "+ diagnostic.getMessage(new Locale("es", "ES"))+ " en el fichero " +diagnostic.getSource().toUri());
    }
}

Si no ha ocurrido ningún error de compilación en la ruta “WEB-INF/classes/es/ctrlzapps/” debe existir un fichero llamado “Ejemplo.class” y ya es accesible en toda nuestra aplicación.


final String code;

public CtrlzAppsJavaFileObject(String name, InputStream imps) {

       super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE);
       BufferedReader buffIn = new BufferedReader(new InputStreamReader(imps));
       StringBuffer code = new StringBuffer();
       String s;
       try {
           while((s = buffIn.readLine())!= null){
               code.append(s).append("\n");
           }
       } catch (IOException e) {
          logger.error("Error procesando el inputstream del fichero");
       }

       this.code = code.toString();
}

Bueno, ahora vamos a ver como se usa esa clase que hemos compilado no?

Class<?> classExecute = Thread.currentThread().getContextClassLoader().loadClass("es.ctrlzapps.Ejemplo");
 classExecute.getDeclaredMethod("execute", String.class)
 .invoke(classExecute.newInstance(), "hola");

También lo podemos sustituir por “Class.forName(“es.ctrlzapps.Ejemplo”);

Espero que este ejemplo os haya sido útil.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: