1 package sample.vector;
2 
3 import java.io.IOException;
4 import javassist.*;
5 import sample.preproc.Assistant;
6 
7 /**
8  * This is a Javassist program which produce a new class representing
9  * vectors of a given type.  For example,
10  *
11  * <ul>import java.util.Vector by sample.vector.VectorAssistant(int)</ul>
12  *
13  * <p>requests the Javassist preprocessor to substitute the following
14  * lines for the original import declaration:
15  *
16  * <ul><pre>
17  * import java.util.Vector;
18  * import sample.vector.intVector;
19  * </pre></ul>
20  *
21  * <p>The Javassist preprocessor calls <code>VectorAssistant.assist()</code>
22  * and produces class <code>intVector</code> equivalent to:
23  *
24  * <ul><pre>
25  * package sample.vector;
26  *
27  * public class intVector extends Vector {
28  *   pubilc void add(int value) {
29  *     addElement(new Integer(value));
30  *   }
31  *
32  *   public int at(int index) {
33  *     return elementAt(index).intValue();
34  *   }
35  * }
36  * </pre></ul>
37  *
38  * <p><code>VectorAssistant.assist()</code> uses
39  * <code>sample.vector.Sample</code> and <code>sample.vector.Sample2</code>
40  * as a template to produce the methods <code>add()</code> and
41  * <code>at()</code>.
42  */
43 public class VectorAssistant implements Assistant {
44     public final String packageName = "sample.vector.";
45 
46     /**
47      * Calls <code>makeSubclass()</code> and produces a new vector class.
48      * This method is called by a <code>sample.preproc.Compiler</code>.
49      *
50      * @see sample.preproc.Compiler
51      */
assist(ClassPool pool, String vec, String[] args)52     public CtClass[] assist(ClassPool pool, String vec, String[] args)
53 	throws CannotCompileException
54     {
55 	if (args.length != 1)
56 	    throw new CannotCompileException(
57 			"VectorAssistant receives a single argument.");
58 
59 	try {
60 	    CtClass subclass;
61 	    CtClass elementType = pool.get(args[0]);
62 	    if (elementType.isPrimitive())
63 		subclass = makeSubclass2(pool, elementType);
64 	    else
65 		subclass = makeSubclass(pool, elementType);
66 
67 	    CtClass[] results = { subclass, pool.get(vec) };
68 	    return results;
69 	}
70 	catch (NotFoundException e) {
71 	    throw new CannotCompileException(e);
72 	}
73 	catch (IOException e) {
74 	    throw new CannotCompileException(e);
75 	}
76     }
77 
78     /**
79      * Produces a new vector class.  This method does not work if
80      * the element type is a primitive type.
81      *
82      * @param type	the type of elements
83      */
makeSubclass(ClassPool pool, CtClass type)84     public CtClass makeSubclass(ClassPool pool, CtClass type)
85 	throws CannotCompileException, NotFoundException, IOException
86     {
87 	CtClass vec = pool.makeClass(makeClassName(type));
88 	vec.setSuperclass(pool.get("java.util.Vector"));
89 
90 	CtClass c = pool.get("sample.vector.Sample");
91 	CtMethod addmethod = c.getDeclaredMethod("add");
92 	CtMethod atmethod = c.getDeclaredMethod("at");
93 
94 	ClassMap map = new ClassMap();
95 	map.put("sample.vector.X", type.getName());
96 
97 	vec.addMethod(CtNewMethod.copy(addmethod, "add", vec, map));
98 	vec.addMethod(CtNewMethod.copy(atmethod, "at", vec, map));
99 	vec.writeFile();
100 	return vec;
101     }
102 
103     /**
104      * Produces a new vector class.  This uses wrapped methods so that
105      * the element type can be a primitive type.
106      *
107      * @param type	the type of elements
108      */
makeSubclass2(ClassPool pool, CtClass type)109     public CtClass makeSubclass2(ClassPool pool, CtClass type)
110 	throws CannotCompileException, NotFoundException, IOException
111     {
112 	CtClass vec = pool.makeClass(makeClassName(type));
113 	vec.setSuperclass(pool.get("java.util.Vector"));
114 
115 	CtClass c = pool.get("sample.vector.Sample2");
116 	CtMethod addmethod = c.getDeclaredMethod("add");
117 	CtMethod atmethod = c.getDeclaredMethod("at");
118 
119 	CtClass[] args1 = { type };
120 	CtClass[] args2 = { CtClass.intType };
121 	CtMethod m
122 	    = CtNewMethod.wrapped(CtClass.voidType, "add", args1,
123 				  null, addmethod, null, vec);
124 	vec.addMethod(m);
125 	m = CtNewMethod.wrapped(type, "at", args2,
126 				null, atmethod, null, vec);
127 	vec.addMethod(m);
128 	vec.writeFile();
129 	return vec;
130     }
131 
makeClassName(CtClass type)132     private String makeClassName(CtClass type) {
133 	return packageName + type.getSimpleName() + "Vector";
134     }
135 }
136