quarta-feira, dezembro 15, 2004

Carregamento dinâmico de classes em Java

Tá aqui um truque java que vale a pena. Basicamente, tenho o source code vindo do limbo e quero criar uma classe "on the fly". A dureza é que o java não é nada amistoso pra fazer isso, mas dá pra fazer. ;) Peguei do seguinte fórum
package com.sun.tools.javac.v8;
 
import com.sun.tools.javac.v8.JavaCompiler;
import com.sun.tools.javac.v8.util.List;
import com.sun.tools.javac.v8.util.Context;
import com.sun.tools.javac.v8.comp.Gen;
import com.sun.tools.javac.v8.comp.Env;
import com.sun.tools.javac.v8.tree.Tree;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
 
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Iterator;
 
public class Derik1
{
	static class Compiler
	{
		private ByteArrayOutputStream os;
 
		public byte[] compile(String name, final String source)
			throws Throwable
		{
			os= new ByteArrayOutputStream(1024);
 
			final Context context= new Context();
 
			JavaCompiler compiler= new JavaCompiler(context) {
				public InputStream openSource(String filename) {
					return new ByteArrayInputStream(source.getBytes());
				}
				void genCode(Env env, Tree.ClassDef classdef) 
					throws IOException
				{
					Gen.instance(context).genClass(env, classdef);
					writer.writeClassFile(os, classdef.sym);
				}
			};
	
			List list= new List();
			list= list.append(name +".java");
			compiler.compile(list);
 
			byte[] bytes= os.toByteArray();
			os.close();
			return bytes;
		}
	}
 
	static class Loader
		extends ClassLoader
	{
		private Hashtable mClasses= new Hashtable();
 
		public void add(String name, byte[] bytes) { mClasses.put(name, bytes); }
 
		public Class findClass(String name)
			throws ClassNotFoundException 
		{
			byte[] bytes= (byte[]) mClasses.get(name);
			if (bytes == null) 
				return super.findClass(name);
			return defineClass(name, bytes, 0, bytes.length);
		}
	}
 
	static class Attribute
	{
		public String name;
		public String type;
 
		public Attribute(String name, String type)
		{
			this.name= name.substring(0,1).toUpperCase() +
				name.substring(1).toLowerCase();
			this.type= type;
		}
 
		public String declaration() {
			return "private " +type +" m" +name +";";
		}
 
		public String getter() {
			return "public " +type +" get" +name +"() { return m" +name +"; }";
		}
 
		public String setter() {
			return "public void set" +name +
				"(" +type +" " +name.toLowerCase() +") { m" +
				name +"= " +name.toLowerCase() +"; }";
		}
	}
 
	public static void main(String[] argv)
		throws Throwable
	{
		BufferedReader reader= new BufferedReader(
			new InputStreamReader(System.in));
 
		System.out.print("Class: ");
		String cname= reader.readLine();
 
		ArrayList attributes= new ArrayList();
 
		while (true) {
			System.out.print("Attribute (return to finish): ");
			String name= reader.readLine();
			if (name.length() < 1) 
				break;
			System.out.print("Type for " +name +": ");
			String type= reader.readLine();
			attributes.add(new Attribute(name, type));
		}
 
		String src= "public class " +cname +" {";
 
		Iterator iter= attributes.iterator();
		while (iter.hasNext()) 
			src += "\n\t" + ((Attribute) iter.next()).declaration();
 
		iter= attributes.iterator();
		while (iter.hasNext()) {
			Attribute a= (Attribute) iter.next();
			src += "\n\t" + a.setter();
			src += "\n\t" + a.getter();
		}
 
		src += "\n\tpublic String toString() {";
		src += "\n\t\treturn \"";
		iter= attributes.iterator();
		boolean first= true;
		while (iter.hasNext()) {
			Attribute a= (Attribute) iter.next();
			if (!first) 
				src += "+\",\" +\n\t\t\t\"";
			src += a.name +"=\" +get" +a.name +"()";
			first= false;
		}
		src +=  ";\n\t}\n}";
 
		System.err.println("##### Source Code");
		System.err.println(src);
 
		System.err.println("##### Compiling...");
		byte[] bytes= new Compiler().compile(cname, src);
    
		System.err.println("##### Class Loading...");
		Loader loader= new Loader();
		loader.add(cname, bytes);
		Class clazz= loader.findClass(cname);
 
		System.err.println("##### Class: " +clazz.getName());
    
		Object instance= clazz.newInstance();
		System.err.println("##### Instance: " +instance);
	}
}

Nenhum comentário:

Postar um comentário