aboutsummaryrefslogtreecommitdiffstats
path: root/sample/vector/VectorAssistant.java
blob: 44fdd41cd8b12437355a23072b524ba8895ad3c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package sample.vector;

import java.io.IOException;
import javassist.*;
import javassist.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>javassist.preproc.Compiler</code>.
     *
     * @see javassist.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));
	pool.writeFile(vec.getName());
	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);
	pool.writeFile(vec.getName());
	return vec;
    }

    private String makeClassName(CtClass type) {
	return packageName + type.getSimpleName() + "Vector";
    }
}