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:
Mais material sobre Javassist pode ser encontrado no Link: javassist
Rodem, testem e divirtam-se :)
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 publictoStrInt
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 staticT 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 :)