Criando e Rodando Classes em tempo de runtime

Isso é umas das ferramentas mais poderosas na minha opinião, pois é muito mais rápido do que reflection e uma vez compilada a class está na memória e vai ser muito mais rápido na segunda vez.
Não pensem que eu condeno o uso de reflection, não é isso, acho bom e que é uma ferramenta poderosa, mas essa é muito poderosa também.
Vou mostrar como fazer isso com o framework javassist do Jboss, mas existem outros tantos por ai no mercado como por exemplo o ASM do ObjectWeb e o BCEL da Apache, mas o ponto importante do javassist é que ele é bem alto nível e fácil de programar.



Segue um pequeno exemplo:


public interface ToStringAble {
public int toStrInt();
}



import java.io.IOException;
import java.security.SecureClassLoader;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.NotFoundException;

public class UseJavassistTest {

/** Simple-minded loader for constructed classes. */
protected static class DirectLoader extends SecureClassLoader
{
protected DirectLoader() {
super(UseJavassistTest.class.getClassLoader());
}

protected Class load(String name, byte[] data) {
return super.defineClass(name, data, 0, data.length);
}
}

public static final String PACKAGE_JAVA = "org.diegopacheco.javassist.tst";

private static final CtClass[] NO_ARGS = {};

private static DirectLoader s_classLoader = new DirectLoader();


public static void main(String[] args) throws NotFoundException, CannotCompileException, NoSuchMethodException, IOException {

/* gera o nome da class */
String cname = generateClassName();

/* gera a class */
CtClass clas = generateNewClass(cname);

/* Adiciona o construtor default */
addDefaultConstructor(clas);

// add public toStrInt method
createAMethod(clas);

/* Adiciona a interface e gera a class em memoria. */
clas.addInterface(getClassPool().get(PACKAGE_JAVA + ".ToStringAble"));
byte[] bytes = clas.toBytecode();

/* Carrega a class via class loader */
ToStringAble access = loadClassByInterface(cname, bytes,ToStringAble.class);

System.out.println("Rodando a class gerada... ");
System.out.println("Class>: " + access + "ToStrInt: " + access.toStrInt());

}

private static void createAMethod(CtClass clas) throws CannotCompileException {
CtMethod meth = new CtMethod(CtClass.intType, "toStrInt",NO_ARGS,clas);

String methodBody = "{";
methodBody += " System.out.println(\">>> Inicio da execução metodo: \" + System.currentTimeMillis() ); ";
methodBody += " System.out.println(\">>> Fim da execução metodo: \" + System.currentTimeMillis() ); ";
methodBody += " return (int)(java.lang.Math.random() * 100); ";
methodBody += "}";

meth.setBody(methodBody);
clas.addMethod(meth);
}

/* Carrega a classes pela interface */
@SuppressWarnings("unchecked")
private static T loadClassByInterface(String cname, byte[] bytes,Class interfacei) {

// load and construct an instance of the class
Class clasLoad = s_classLoader.load(cname, bytes);
T access = null;
try {
access = (T)clasLoad.newInstance();
} catch (IllegalAccessException ex) {
ex.printStackTrace(System.err);
System.exit(1);
} catch (InstantiationException ex) {
ex.printStackTrace(System.err);
System.exit(1);
}
return access;
}

/* adiciona o construtor default. */
private static void addDefaultConstructor(CtClass clas) throws CannotCompileException {
// add public default constructor method to class
CtConstructor cons = new CtConstructor(NO_ARGS, clas);
cons.setBody(";");
clas.addConstructor(cons);
}

/* Retorna o pool de classes. */
private static ClassPool getClassPool(){
return ClassPool.getDefault();
}

/* Coloca a classe no pool e pega de la. */
private static CtClass generateNewClass(String cname) {

// build generator for the new class
ClassPool pool = ClassPool.getDefault();
CtClass clas = pool.makeClass(cname);
return clas;

}

/* Gera o nome da classe. */
private static String generateClassName() throws NoSuchMethodException {
String cname = "ToStringAble_GeneratedRuntime_";
return cname;
}

}


Mais material sobre Javassist pode ser encontrado no Link: javassist

Rodem, testem e divirtam-se :)

Popular posts from this blog

Telemetry and Microservices part2

Installing and Running ntop 2 on Amazon Linux OS

Fun with Apache Kafka