1
2
3
4
5
6
7
8
9
10 package nl.tudelft.simulation.dsol.interpreter.classfile;
11
12 import java.io.DataInput;
13 import java.io.DataInputStream;
14 import java.io.IOException;
15 import java.lang.reflect.AccessibleObject;
16 import java.util.HashMap;
17 import java.util.Map;
18
19 /***
20 * A ClassDescriptor <br>
21 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
22 * University of Technology </a>, the Netherlands. <br>
23 * See for project information <a
24 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
25 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
26 * License (GPL) </a>, no warranty <br>
27 *
28 * @version 1.0 Jan 10, 2004 <br>
29 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
30 * Jacobs </a>
31 */
32 public class ClassDescriptor
33 {
34 /*** the repository which caches descriptors */
35 private static final Map REPOSITORY = new HashMap();
36
37 /*** the constantPool */
38 private Constant[] constantPool = null;
39
40 /*** the localVariables */
41 private Map methods = new HashMap();
42
43 /*** the javaClass we are reading */
44 private Class javaClass = null;
45
46 /***
47 * returns the classDescriptor of this class
48 *
49 * @param clazz the class the clazz to parse
50 * @return ClassDescriptor the descriptor
51 * @throws IOException on IO exception
52 * @throws ClassNotFoundException if clazz cannot be found
53 */
54 public static ClassDescriptor get(final Class clazz) throws IOException,
55 ClassNotFoundException
56 {
57 synchronized (REPOSITORY)
58 {
59 if (REPOSITORY.containsKey(clazz))
60 {
61 return (ClassDescriptor) REPOSITORY.get(clazz);
62 }
63 ClassDescriptor classDescriptor = new ClassDescriptor(clazz);
64 REPOSITORY.put(clazz, classDescriptor);
65 return classDescriptor;
66 }
67 }
68
69 /***
70 *
71 * constructs a new ClassDescriptor
72 *
73 * @param javaClass the class to read
74 * @throws IOException on IO - failure
75 * @throws ClassNotFoundException on incomplete classPath
76 */
77 private ClassDescriptor(final Class javaClass) throws IOException,
78 ClassNotFoundException
79 {
80 super();
81 this.javaClass = javaClass;
82 ClassLoader classLoader = javaClass.getClassLoader();
83 if (classLoader == null)
84 {
85 classLoader = ClassLoader.getSystemClassLoader();
86 }
87 this.readClass(new DataInputStream(classLoader
88 .getResourceAsStream(javaClass.getName().replace('.', '/')
89 + ".class")));
90 }
91
92 /***
93 * returns the methodDescriptor of the method.
94 *
95 * @param method the method to resolve.
96 * @return its descriptor.
97 */
98 public MethodDescriptor getMethod(final AccessibleObject method)
99 {
100 return (MethodDescriptor) this.methods.get(method);
101 }
102
103 /***
104 * returns the constantpool of a classfile
105 *
106 * @return Constant[] the constantpool
107 */
108 public Constant[] getConstantPool()
109 {
110 return this.constantPool;
111 }
112
113 /***
114 * returns the methods of this class
115 *
116 * @return MethodDescriptor[]
117 */
118 public MethodDescriptor[] getMethods()
119 {
120 return (MethodDescriptor[]) this.methods.values().toArray(
121 new MethodDescriptor[this.methods.size()]);
122 }
123
124 /*** ** PRIVATE PARSING METHODS *** */
125
126 /***
127 * reads the class
128 *
129 * @param dataInput the dataInput
130 * @throws IOException on failure
131 * @throws ClassNotFoundException on incomplete classPath
132 */
133 private void readClass(final DataInput dataInput) throws IOException,
134 ClassNotFoundException
135 {
136
137 dataInput.skipBytes(8);
138
139
140 this.readConstantPool(dataInput);
141
142
143 dataInput.skipBytes(6);
144
145
146 int interfacesCount = dataInput.readUnsignedShort();
147 dataInput.skipBytes(2 * interfacesCount);
148
149
150
151 int fieldCount = dataInput.readUnsignedShort();
152 for (int i = 0; i < fieldCount; i++)
153 {
154
155 dataInput.skipBytes(6);
156 int attributeCount = dataInput.readUnsignedShort();
157 for (int j = 0; j < attributeCount; j++)
158 {
159
160 dataInput.skipBytes(2);
161 dataInput.skipBytes(dataInput.readInt());
162 }
163 }
164
165
166 int methodCount = dataInput.readUnsignedShort();
167 for (int i = 0; i < methodCount; i++)
168 {
169 MethodDescriptor methodDescriptor = new MethodDescriptor(dataInput,
170 this.constantPool);
171 AccessibleObject method = this.parseMethod(methodDescriptor
172 .getName(), methodDescriptor.getMethodSignature()
173 .getParameterTypes());
174 methodDescriptor.setMethod(method);
175 this.methods.put(method, methodDescriptor);
176 }
177 }
178
179 /***
180 * reads the constantpool from file
181 *
182 * @param dataInput the stream
183 * @throws IOException on failure
184 */
185 private void readConstantPool(final DataInput dataInput) throws IOException
186 {
187 this.constantPool = new Constant[dataInput.readUnsignedShort()];
188
189
190
191
192
193 for (int i = 1; i < this.constantPool.length; i++)
194 {
195 this.constantPool[i] = Constant.readConstant(this.constantPool,
196 dataInput);
197
198 if (this.constantPool[i] instanceof ConstantDouble
199 || this.constantPool[i] instanceof ConstantLong)
200 {
201
202
203
204
205
206
207
208
209 i++;
210 }
211 }
212 }
213
214 /***
215 * parses a methodName and descriptor to an accessibleObject
216 *
217 * @param methodName the name of the method
218 * @param argumentClasses the argumentClasses
219 * @return the AccessibleObject
220 */
221 private AccessibleObject parseMethod(final String methodName,
222 final Class[] argumentClasses)
223 {
224 try
225 {
226 if (methodName.equals("<clinit>"))
227 {
228 return null;
229 }
230 if (!methodName.equals("<init>"))
231 {
232 return this.javaClass.getDeclaredMethod(methodName,
233 argumentClasses);
234 }
235 return this.javaClass.getDeclaredConstructor(argumentClasses);
236 } catch (Exception exception)
237 {
238 return null;
239 }
240 }
241 }