style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Nano ejemplo de Javassist

Complementando esta entrada de Rodrigo y estas otras de Enrique, aquí va mi nano ejemplo para modificar una clase con javassist.

Me estaba preguntando si sería posible modificar el bytecode de una clase, pero además salvarlo para que ya no exista dependencia con la biblioteca durante la ejecución.

A menos que haya leído mal en los ejemplos de Rodrigo y Enrique, se modificaba la clase en Runtime, en este ejemplo se modificará en "build-time" que es como se llama cuando se modificar el .class

Primero vemos que hay en el directorio:

C:\Users\oreyes\langs\java\javassistdemo>dir

29/02/2009  23:55 p.m.                57 Code.java
03/07/2009  12:03 a.m.           614,203 javassist.jar
29/02/2009  23:53 p.m.               432 ModifyIt.java
29/02/2009  23:51 p.m.                76 UseIt.java

Tenemos tres archivos java y la biblioteca javassist.

Este es el código a modificar:

C:\Users\oreyes\langs\java\javassistdemo>type Code.java
package test;
class Rectangle {
}
class Point {
}

Son dos clases que no están relacionadas.

Las compilamos y vemos que se genere los .class

C:\Users\oreyes\langs\java\javassistdemo>javac -d . Code.java

C:\Users\oreyes\langs\java\javassistdemo>dir test
29/02/2009  23:55 p.m.               188 Point.class
29/02/2009  23:55 p.m.               192 Rectangle.class

Listo. Ahora vemos la clase que los intentará usar:

C:\Users\oreyes\langs\java\javassistdemo>type UseIt.java
package test;
class UseIt {
    test.Point r = new test.Rectangle();
}

C:\Users\oreyes\langs\java\javassistdemo>javac -cp . -d . UseIt.java
UseIt.java:3: incompatible types
found   : test.Rectangle
required: test.Point
    test.Point r = new test.Rectangle();
                   ^
1 error

El compilador dice que los tipos son incompatibles. Es correcto porque test.Rectangle no es una subclase de test.Point

Vamos a modificar esto usando javassist. Vamos a hacer que Rectangle sea una subclase de Point.

Este es el código ( que por cierto es el primero del tutorial ) :

C:\Users\oreyes\langs\java\javassistdemo>type ModifyIt
package test;
import javassist.*;
class ModifyIt {
    public static void main( String ... args )
        throws javassist.NotFoundException,
               javassist.CannotCompileException,
               java.io.IOException {

        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("test.Rectangle");
        cc.setSuperclass(pool.get("test.Point"));
        cc.writeFile();
    }
}

C:\Users\oreyes\langs\java\javassistdemo>java -cp javassist.jar;. test.ModifyIt

Despues de compilar vemos el .class modificado:

C:\Users\oreyes\langs\java\javassistdemo>dir test
29/02/2009  23:56 p.m.               694 ModifyIt.class
29/02/2009  23:55 p.m.               188 Point.class
29/02/2009  23:57 p.m.               213 Rectangle.class

Vemos que el .class de Rectangle se modificó. Si intentamos compilar ahora no debería de haber errores:

C:\Users\oreyes\langs\java\javassistdemo>javac -cp . -d . UseIt.java

C:\Users\oreyes\langs\java\javassistdemo>

Sin errores.

Bueno despues de todo no fue tan nano, espero que a alguien le sirva.

p.d. ¿Alguién sabe que implicación hay para re-distribuir una biblioteca liberada con Mozilla Public License?

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de rodrigo salado anaya

#Ryz Ya decía yo :P

YA decía yo Oscar que tenia que ver con Ryz, no he encontrado donde estas usando Javassist, pero luego comentas que planes tienes para usarlo en Ryz vale.

Saludos y suerte a todos :D.

http://code.google.com/p/ryz/source/detail?r=c67fbfff89789b56225ccf7f48d...

:) :) Así es mi buen Rodrigo

:) :) Así es mi buen Rodrigo

El código Ryz de prueba que esta en tu link es el siguiente:

classes.UseCheckedException { // Declara una clase : UseCheckedExcepcions en el paquete classes
    import( java.io.File )    // importa java.io.File

    test() {                   // declara el metodo test(), sin parametros, que no regresa nada
        file = File("sample")  // crear un nuevo archivo llamado "sample"
        file.createNewFile()  // invocar el método createNewFile que tira IOException      
    }
}

Es decir, se está usando el métdo createNewFile() que como se puede ver en la doc, tira la excepción chequeada: java.io.IOException

Instrumentando con Javassist el mensaje:

unreported exception java.io.IOException; must be caught or declared to be thrown

Será cosa del pasado ( aysi, aysi )

Lo bonito es que es tán facil, como un truco de monedas del mago del WingsFactory; sorprende cuando no se sabe como se hace, pero cuando sabes el truco, está de Dohhhh!!...

La respuesta está en el código ( y es algo bochornosa por cierto ).

Imagen de ezamudio

Tapestry

Tapestry usa Javassist, aunque es para transformación de clases en tiempo de ejecución, y Howard Lewis Ship creo que ya está harto de las broncas que le ha causado y están buscando la manera de reemplazarlo, incluso implementado por cuenta propia lo que necesitan de javassist...

Imagen de benek

Re: Tapestry

De hecho comentó iberck por acá que para la versión 5.2 Final javassist ya no exista en Tapestry, y que probablemente sería reemplazado por asm.

Yeap, vi esos posts,

Yeap, vi esos posts, interesantes por cierto. El problema que entiendo que tienen con él es cuando lo usan en runtime. Acá espero que no tenga problemas pues lo estoy usando en buildtime ( no hay dependencias en los .class generados ).

Habrá que leer detenidamente cuales son los problemas que les dió.

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">