/Users/lyon/j4p/src/javassist/CtConstructor.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16 package javassist;
17
18 import javassist.bytecode.*;
19 import javassist.compiler.Javac;
20 import javassist.compiler.CompileError;
21 import javassist.expr.ExprEditor;
22
23 /* Some methods do nothing except calling the super's method.
24 * They might seem redundant but they are necessary so that javadoc
25 * includes the description of those methods in the page of this class.
26 */
27
28 /**
29 * An instance of CtConstructor represents a constructor.
30 * It may represent a static constructor
31 * (class initializer). To distinguish a constructor and a class
32 * initializer, call <code>isClassInitializer()</code>.
33 *
34 * @see CtClass#getDeclaredConstructors()
35 * @see CtClass#getClassInitializer()
36 * @see CtNewConstructor
37 */
38 public final class CtConstructor extends CtBehavior {
39 protected CtConstructor next;
40
41 protected CtConstructor(MethodInfo minfo, CtClass declaring) {
42 super(declaring, minfo);
43 next = null;
44 }
45
46 /**
47 * Creates a constructor with no constructor body.
48 * The created constructor
49 * must be added to a class with <code>CtClass.addConstructor()</code>.
50 *
51 * <p>The created constructor does not include a constructor body,
52 * must be specified with <code>setBody()</code>.
53 *
54 * @param declaring the class to which the created method is added.
55 * @param parameters a list of the parameter types
56 *
57 * @see CtClass#addConstructor(CtConstructor)
58 * @see CtConstructor#setBody(String)
59 * @see CtConstructor#setBody(CtConstructor,ClassMap)
60 */
61 public CtConstructor(CtClass[] parameters, CtClass declaring) {
62 this((MethodInfo) null, declaring);
63 ConstPool cp = declaring.getClassFile2().getConstPool();
64 String desc = Descriptor.ofConstructor(parameters);
65 methodInfo = new MethodInfo(cp, "<init>", desc);
66 setModifiers(Modifier.PUBLIC);
67 }
68
69 /**
70 * Creates a copy of a <code>CtConstructor</code> object.
71 * The created constructor must be
72 * added to a class with <code>CtClass.addConstructor()</code>.
73 *
74 * <p>All occurrences of class names in the created constructor
75 * are replaced with names specified by
76 * <code>map</code> if <code>map</code> is not <code>null</code>.
77 *
78 * <p>By default, all the occurrences of the names of the class
79 * declaring <code>src</code> and the superclass are replaced
80 * with the name of the class and the superclass that
81 * the created constructor is added to.
82 * This is done whichever <code>map</code> is null or not.
83 * To prevent this replacement, call <code>ClassMap.fix()</code>.
84 *
85 * <p><b>Note:</b> if the <code>.class</code> notation (for example,
86 * <code>String.class</code>) is included in an expression, the
87 * Javac compiler may produce a helper method.
88 * Since this constructor never
89 * copies this helper method, the programmers have the responsiblity of
90 * copying it. Otherwise, use <code>Class.forName()</code> in the
91 * expression.
92 *
93 * @param src the source method.
94 * @param declaring the class to which the created method is added.
95 * @param map the hashtable associating original class names
96 * with substituted names.
97 * It can be <code>null</code>.
98 *
99 * @see CtClass#addConstructor(CtConstructor)
100 * @see ClassMap#fix(String)
101 */
102 public CtConstructor(CtConstructor src, CtClass declaring, ClassMap map)
103 throws CannotCompileException {
104 this((MethodInfo) null, declaring);
105 MethodInfo srcInfo = src.methodInfo;
106 CtClass srcClass = src.getDeclaringClass();
107 ConstPool cp = declaring.getClassFile2().getConstPool();
108 if (map == null)
109 map = new ClassMap();
110
111 map.put(srcClass.getName(), declaring.getName());
112 try {
113 boolean patch = false;
114 CtClass srcSuper = srcClass.getSuperclass();
115 String destSuperName = declaring.getSuperclass().getName();
116 if (srcSuper != null) {
117 String srcSuperName = srcSuper.getName();
118 if (!srcSuperName.equals(destSuperName))
119 if (srcSuperName.equals(CtClass.javaLangObject))
120 patch = true;
121 else
122 map.put(srcSuperName, destSuperName);
123 }
124
125 methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map);
126 if (patch)
127 methodInfo.setSuperclass(destSuperName);
128 } catch (NotFoundException e) {
129 throw new CannotCompileException(e);
130 } catch (BadBytecode e) {
131 throw new CannotCompileException(e);
132 }
133 }
134
135 static CtConstructor append(CtConstructor list, CtConstructor tail) {
136 tail.next = null;
137 if (list == null)
138 return tail;
139 else {
140 CtConstructor lst = list;
141 while (lst.next != null)
142 lst = lst.next;
143
144 lst.next = tail;
145 return list;
146 }
147 }
148
149 static int count(CtConstructor m) {
150 int n = 0;
151 while (m != null) {
152 ++n;
153 m = m.next;
154 }
155
156 return n;
157 }
158
159 /**
160 * Returns the MethodInfo representing the constructor in the
161 * class file.
162 */
163 public MethodInfo getMethodInfo() {
164 return super.getMethodInfo();
165 }
166
167 /**
168 * Returns true if this object represents a constructor.
169 */
170 public boolean isConstructor() {
171 return methodInfo.isConstructor();
172 }
173
174 /**
175 * Returns true if this object represents a static initializer.
176 */
177 public boolean isClassInitializer() {
178 return methodInfo.isStaticInitializer();
179 }
180
181 /**
182 * Obtains the encoded modifiers of the constructor.
183 *
184 * @return modifiers encoded with
185 * <code>javassist.Modifier</code>.
186 * @see Modifier
187 */
188 public int getModifiers() {
189 return super.getModifiers();
190 }
191
192 /**
193 * Sets the encoded modifiers of the constructor.
194 *
195 * @see Modifier
196 */
197 public void setModifiers(int mod) {
198 super.setModifiers(mod);
199 }
200
201 /**
202 * Obtains the name of this constructor.
203 * It is the same as the simple name of the class declaring this
204 * constructor. If this object represents a class initializer,
205 * then this method returns <code>"<clinit>"</code>.
206 */
207 public String getName() {
208 if (methodInfo.isStaticInitializer())
209 return MethodInfo.nameClinit;
210 else
211 return declaringClass.getName();
212 }
213
214 /**
215 * Returns the class that declares this constructor.
216 */
217 public CtClass getDeclaringClass() {
218 return super.getDeclaringClass();
219 }
220
221 /**
222 * Obtains parameter types of this constructor.
223 */
224 public CtClass[] getParameterTypes() throws NotFoundException {
225 return super.getParameterTypes();
226 }
227
228 /**
229 * Returns the character string representing the parameter types.
230 * If two constructors have the same parameter types,
231 * <code>getSignature()</code> returns the same string.
232 */
233 public String getSignature() {
234 return super.getSignature();
235 }
236
237 /**
238 * Obtains exceptions that this constructor may throw.
239 */
240 public CtClass[] getExceptionTypes() throws NotFoundException {
241 return super.getExceptionTypes();
242 }
243
244 /**
245 * Sets exceptions that this constructor may throw.
246 */
247 public void setExceptionTypes(CtClass[] types)
248 throws NotFoundException {
249 super.setExceptionTypes(types);
250 }
251
252 /**
253 * Returns true if the constructor is the default one.
254 */
255 public boolean isEmpty() {
256 CodeAttribute ca = getMethodInfo2().getCodeAttribute();
257 if (ca == null)
258 return false; // native or abstract??
259 // they are not allowed, though.
260
261 ConstPool cp = ca.getConstPool();
262 CodeIterator it = ca.iterator();
263 try {
264 int pos, desc;
265 return it.byteAt(it.next()) == Opcode.ALOAD_0
266 && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL
267 && (desc = cp.isConstructor(CtClass.javaLangObject,
268 it.u16bitAt(pos + 1))) != 0
269 && cp.getUtf8Info(desc).equals("()V")
270 && it.byteAt(it.next()) == Opcode.RETURN
271 && !it.hasNext();
272 } catch (BadBytecode e) {
273 }
274 return false;
275 }
276
277 /**
278 * Sets a constructor body.
279 *
280 * @param src the source code representing the constructor body.
281 * It must be a single statement or block.
282 * If it is <code>null</code>, the substituted
283 * constructor body does nothing except calling
284 * <code>super()</code>.
285 */
286 public void setBody(String src) throws CannotCompileException {
287 if (src == null)
288 if (isClassInitializer())
289 src = ";";
290 else
291 src = "super();";
292
293 super.setBody(src);
294 }
295
296 /**
297 * Copies a constructor body from another constructor.
298 *
299 * <p>All occurrences of the class names in the copied body
300 * are replaced with the names specified by
301 * <code>map</code> if <code>map</code> is not <code>null</code>.
302 *
303 * @param src the method that the body is copied from.
304 * @param map the hashtable associating original class names
305 * with substituted names.
306 * It can be <code>null</code>.
307 */
308 public void setBody(CtConstructor src, ClassMap map)
309 throws CannotCompileException {
310 setBody0(src.declaringClass, src.methodInfo,
311 declaringClass, methodInfo, map);
312 }
313
314 /**
315 * Obtains an attribute with the given name.
316 * If that attribute is not found in the class file, this
317 * method returns null.
318 *
319 * @param name attribute name
320 */
321 public byte[] getAttribute(String name) {
322 return super.getAttribute(name);
323 }
324
325 /**
326 * Adds an attribute. The attribute is saved in the class file.
327 *
328 * @param name attribute name
329 * @param data attribute value
330 */
331 public void setAttribute(String name, byte[] data) {
332 super.setAttribute(name, data);
333 }
334
335 /**
336 * Declares to use <code>$cflow</code> for this constructor.
337 * If <code>$cflow</code> is used, the class files modified
338 * with Javassist requires a support class
339 * <code>javassist.runtime.Cflow</code> at runtime
340 * (other Javassist classes are not required at runtime).
341 *
342 * <p>Every <code>$cflow</code> variable is given a unique name.
343 * For example, if the given name is <code>"Point.paint"</code>,
344 * then the variable is indicated by <code>$cflow(Point.paint)</code>.
345 *
346 * @param name <code>$cflow</code> name. It can include
347 * alphabets, numbers, <code>_</code>,
348 * <code>$</code>, and <code>.</code> (dot).
349 *
350 * @see javassist.runtime.Cflow
351 */
352 public void useCflow(String name) throws CannotCompileException {
353 super.useCflow(name);
354 }
355
356 /**
357 * Modifies the constructor body.
358 *
359 * @param converter specifies how to modify.
360 */
361 public void instrument(CodeConverter converter)
362 throws CannotCompileException {
363 super.instrument(converter);
364 }
365
366 /**
367 * Modifies the constructor body.
368 *
369 * @param editor specifies how to modify.
370 */
371 public void instrument(ExprEditor editor)
372 throws CannotCompileException {
373 super.instrument(editor);
374 }
375
376 /**
377 * Inserts bytecode at the beginning of the constructor body.
378 * Since the bytecode is inserted before a constructor in the super
379 * class or this class is called, the bytecode is subject
380 * to constraints described
381 * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed).
382 * For example, it cannot access instance members although it can access
383 * static members.
384 *
385 * @param src the source code representing the inserted bytecode.
386 * It must be a single statement or block.
387 */
388 public void insertBefore(String src) throws CannotCompileException {
389 super.insertBefore(src);
390 }
391
392 /**
393 * Inserts bytecode just after another constructor in the super class
394 * or this class is called.
395 * It does not work if this object represents a class initializer.
396 *
397 * @param src the source code representing the inserted bytecode.
398 * It must be a single statement or block.
399 */
400 public void insertBeforeBody(String src) throws CannotCompileException {
401 declaringClass.checkModify();
402 if (isClassInitializer())
403 throw new CannotCompileException("class initializer");
404
405 CodeAttribute ca = methodInfo.getCodeAttribute();
406 CodeIterator iterator = ca.iterator();
407 Bytecode b = new Bytecode(methodInfo.getConstPool(),
408 ca.getMaxStack(), ca.getMaxLocals());
409 b.setStackDepth(ca.getMaxStack());
410 Javac jv = new Javac(b, declaringClass);
411 try {
412 jv.recordParams(getParameterTypes(), false);
413 jv.compileStmnt(src);
414 ca.setMaxStack(b.getMaxStack());
415 ca.setMaxLocals(b.getMaxLocals());
416 iterator.skipConstructor();
417 int pos = iterator.insertEx(b.get());
418 iterator.insert(b.getExceptionTable(), pos);
419 } catch (NotFoundException e) {
420 throw new CannotCompileException(e);
421 } catch (CompileError e) {
422 throw new CannotCompileException(e);
423 } catch (BadBytecode e) {
424 throw new CannotCompileException(e);
425 }
426 }
427
428 /**
429 * Inserts bytecode at the end of the constructor body.
430 * The bytecode is inserted just before every return insturction.
431 * It is not executed when an exception is thrown.
432 *
433 * @param src the source code representing the inserted bytecode.
434 * It must be a single statement or block.
435 */
436 public void insertAfter(String src)
437 throws CannotCompileException {
438 super.insertAfter(src);
439 }
440
441 /**
442 * Inserts bytecode at the end of the constructor body.
443 * The bytecode is inserted just before every return insturction.
444 *
445 * @param src the source code representing the inserted bytecode.
446 * It must be a single statement or block.
447 * @param asFinally true if the inserted bytecode is executed
448 * not only when the transfer normally returns
449 * but also when an exception is thrown.
450 */
451 public void insertAfter(String src, boolean asFinally)
452 throws CannotCompileException {
453 super.insertAfter(src, asFinally);
454 }
455
456 /**
457 * Adds a catch clause that handles an exception thrown in the
458 * constructor body.
459 * The catch clause must end with a return or throw statement.
460 *
461 * @param src the source code representing the catch clause.
462 * It must be a single statement or block.
463 * @param exceptionType the type of the exception handled by the
464 * catch clause.
465 */
466 public void addCatch(String src, CtClass exceptionType)
467 throws CannotCompileException {
468 super.addCatch(src, exceptionType);
469 }
470 }
471