Compilar Java en tiempo real

API para compilar y ejecutar código Java en tiempo real

En algunas situaciones nos puede interesar que un usuario dentro de nuestro programa pueda escribir código en Java y este se compile y ejecute en tiempo real, sin que el usuario tenga que realizar todos los pasos (algunos sencillos pero farragosos) para poder ejecutar su código, como guardarlo en un archivo compilar y luego ejecutar manualmente.

Java 6 incorpora una API para realizar este tipo de compilaciones dinámicas en tiempo real. Lo que en inglés se conoce con la expresión "on the fly" (al vuelo).

Janino API

Esta API permite realizar esta tarea, sin embargo con algunos inconvenientes. El principal es que es necesario añadir el archivo tools.jar ya que JRE no viene por defecto con un compilador. Esto añade de golpe 12MB de tamaño más para nuestro proyecto. Además, la API necesita mucho código para lo que en definitiva tendría que ser sencillo para una librería, que es pasarle una String, compilar y ejecutar.

Sin embargo, existe una herramienta llamada Janino que permite hacer esto y mucho más. La API es un jar que actualmente pesa menos de 500kb y además es de código abierto. Esta librería ofrece más ayuda sobre para compilar y ejecutar dinámicamente código Java en tiempo real sin necesidad de implementar más código ni estructuras de datos.

Veamos un ejemplo que nos permite, a partir de un String que contiene una clase, compilarlo y crear una nueva instancia del objeto creado en tiempo real.

public void compilar(String javaSource){
    try {
        SimpleCompiler compiler = new SimpleCompiler();
        compiler.cook(new StringReader(javaSource));
        Class cl = compiler.getClassLoader().loadClass("Nombredelaclase");
        NuestroObjeto objeto = (NuestroObjeto) cl.newInstance();
    } catch (Exception e) {
        System.err.println(e.getMessage());
        e.printStackTrace();
    }

}

Por su puesto, en este ejemplo sería necesario que la clase que cargamos extienda la clase NuestroObjeto. Por ejemplo, el contenido de la variable javaSource que le pasamos por parámetro podría ser:

class Nombredelaclase extends NuestroObjeto{
    ...
}

Sencillo no?, tan sólo 4 líneas. En este caso hemos compilado una clase entera, pero también podríamos usarlo para evaluar expresiones Java. Podemos encontrar más ejemplos en la página principal de Janino.

Desventajas de Janino

Si hasta ahora hemos defendido esta API, también debemos decir que tiene algunos inconvenientes. Actualmente, la versión 2.5.* sólo es compatible con la versión 1.4 de JDK, es decir, que programas que utilizen funcionalidades de Java 5 y Java 6 no se podrán compilar. Aunque esto puede parecer un gran inconveniente, para la mayoría de casos la simplicidad de uso de la API cubrirá este contratiempo.