package sample.vector; import java.io.IOException; import javassist.*; import sample.preproc.Assistant; /** * This is a Javassist program which produce a new class representing * vectors of a given type. For example, * * <ul>import java.util.Vector by sample.vector.VectorAssistant(int)</ul> * * <p>requests the Javassist preprocessor to substitute the following * lines for the original import declaration: * * <ul><pre> * import java.util.Vector; * import sample.vector.intVector; * </pre></ul> * * <p>The Javassist preprocessor calls <code>VectorAssistant.assist()</code> * and produces class <code>intVector</code> equivalent to: * * <ul><pre> * package sample.vector; * * public class intVector extends Vector { * pubilc void add(int value) { * addElement(new Integer(value)); * } * * public int at(int index) { * return elementAt(index).intValue(); * } * } * </pre></ul> * * <p><code>VectorAssistant.assist()</code> uses * <code>sample.vector.Sample</code> and <code>sample.vector.Sample2</code> * as a template to produce the methods <code>add()</code> and * <code>at()</code>. */ public class VectorAssistant implements Assistant { public final String packageName = "sample.vector."; /** * Calls <code>makeSubclass()</code> and produces a new vector class. * This method is called by a <code>sample.preproc.Compiler</code>. * * @see sample.preproc.Compiler */ public CtClass[] assist(ClassPool pool, String vec, String[] args) throws CannotCompileException { if (args.length != 1) throw new CannotCompileException( "VectorAssistant receives a single argument."); try { CtClass subclass; CtClass elementType = pool.get(args[0]); if (elementType.isPrimitive()) subclass = makeSubclass2(pool, elementType); else subclass = makeSubclass(pool, elementType); CtClass[] results = { subclass, pool.get(vec) }; return results; } catch (NotFoundException e) { throw new CannotCompileException(e); } catch (IOException e) { throw new CannotCompileException(e); } } /** * Produces a new vector class. This method does not work if * the element type is a primitive type. * * @param type the type of elements */ public CtClass makeSubclass(ClassPool pool, CtClass type) throws CannotCompileException, NotFoundException, IOException { CtClass vec = pool.makeClass(makeClassName(type)); vec.setSuperclass(pool.get("java.util.Vector")); CtClass c = pool.get("sample.vector.Sample"); CtMethod addmethod = c.getDeclaredMethod("add"); CtMethod atmethod = c.getDeclaredMethod("at"); ClassMap map = new ClassMap(); map.put("sample.vector.X", type.getName()); vec.addMethod(CtNewMethod.copy(addmethod, "add", vec, map)); vec.addMethod(CtNewMethod.copy(atmethod, "at", vec, map)); vec.writeFile(); return vec; } /** * Produces a new vector class. This uses wrapped methods so that * the element type can be a primitive type. * * @param type the type of elements */ public CtClass makeSubclass2(ClassPool pool, CtClass type) throws CannotCompileException, NotFoundException, IOException { CtClass vec = pool.makeClass(makeClassName(type)); vec.setSuperclass(pool.get("java.util.Vector")); CtClass c = pool.get("sample.vector.Sample2"); CtMethod addmethod = c.getDeclaredMethod("add"); CtMethod atmethod = c.getDeclaredMethod("at"); CtClass[] args1 = { type }; CtClass[] args2 = { CtClass.intType }; CtMethod m = CtNewMethod.wrapped(CtClass.voidType, "add", args1, null, addmethod, null, vec); vec.addMethod(m); m = CtNewMethod.wrapped(type, "at", args2, null, atmethod, null, vec); vec.addMethod(m); vec.writeFile(); return vec; } private String makeClassName(CtClass type) { return packageName + type.getSimpleName() + "Vector"; } }