You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CtConstructor.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2007 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. package javassist;
  16. import javassist.bytecode.*;
  17. import javassist.compiler.Javac;
  18. import javassist.compiler.CompileError;
  19. /**
  20. * An instance of CtConstructor represents a constructor.
  21. * It may represent a static constructor
  22. * (class initializer). To distinguish a constructor and a class
  23. * initializer, call <code>isClassInitializer()</code>.
  24. *
  25. * <p>See the super class <code>CtBehavior</code> as well since
  26. * a number of useful methods are in <code>CtBehavior</code>.
  27. *
  28. * @see CtClass#getDeclaredConstructors()
  29. * @see CtClass#getClassInitializer()
  30. * @see CtNewConstructor
  31. */
  32. public final class CtConstructor extends CtBehavior {
  33. protected CtConstructor(MethodInfo minfo, CtClass declaring) {
  34. super(declaring, minfo);
  35. }
  36. /**
  37. * Creates a constructor with no constructor body.
  38. * The created constructor
  39. * must be added to a class with <code>CtClass.addConstructor()</code>.
  40. *
  41. * <p>The created constructor does not include a constructor body,
  42. * which must be specified with <code>setBody()</code>.
  43. *
  44. * @param declaring the class to which the created method is added.
  45. * @param parameters a list of the parameter types
  46. *
  47. * @see CtClass#addConstructor(CtConstructor)
  48. * @see CtConstructor#setBody(String)
  49. * @see CtConstructor#setBody(CtConstructor,ClassMap)
  50. */
  51. public CtConstructor(CtClass[] parameters, CtClass declaring) {
  52. this((MethodInfo)null, declaring);
  53. ConstPool cp = declaring.getClassFile2().getConstPool();
  54. String desc = Descriptor.ofConstructor(parameters);
  55. methodInfo = new MethodInfo(cp, "<init>", desc);
  56. setModifiers(Modifier.PUBLIC);
  57. }
  58. /**
  59. * Creates a copy of a <code>CtConstructor</code> object.
  60. * The created constructor must be
  61. * added to a class with <code>CtClass.addConstructor()</code>.
  62. *
  63. * <p>All occurrences of class names in the created constructor
  64. * are replaced with names specified by
  65. * <code>map</code> if <code>map</code> is not <code>null</code>.
  66. *
  67. * <p>By default, all the occurrences of the names of the class
  68. * declaring <code>src</code> and the superclass are replaced
  69. * with the name of the class and the superclass that
  70. * the created constructor is added to.
  71. * This is done whichever <code>map</code> is null or not.
  72. * To prevent this replacement, call <code>ClassMap.fix()</code>
  73. * or <code>put()</code> to explicitly specify replacement.
  74. *
  75. * <p><b>Note:</b> if the <code>.class</code> notation (for example,
  76. * <code>String.class</code>) is included in an expression, the
  77. * Javac compiler may produce a helper method.
  78. * Since this constructor never
  79. * copies this helper method, the programmers have the responsiblity of
  80. * copying it. Otherwise, use <code>Class.forName()</code> in the
  81. * expression.
  82. *
  83. * @param src the source method.
  84. * @param declaring the class to which the created method is added.
  85. * @param map the hashtable associating original class names
  86. * with substituted names.
  87. * It can be <code>null</code>.
  88. *
  89. * @see CtClass#addConstructor(CtConstructor)
  90. * @see ClassMap#fix(String)
  91. */
  92. public CtConstructor(CtConstructor src, CtClass declaring, ClassMap map)
  93. throws CannotCompileException
  94. {
  95. this((MethodInfo)null, declaring);
  96. copy(src, true, map);
  97. }
  98. /**
  99. * Returns true if this object represents a constructor.
  100. */
  101. public boolean isConstructor() {
  102. return methodInfo.isConstructor();
  103. }
  104. /**
  105. * Returns true if this object represents a static initializer.
  106. */
  107. public boolean isClassInitializer() {
  108. return methodInfo.isStaticInitializer();
  109. }
  110. /**
  111. * Returns the constructor name followed by parameter types
  112. * such as <code>javassist.CtConstructor(CtClass[],CtClass)</code>.
  113. *
  114. * @since 3.5
  115. */
  116. public String getLongName() {
  117. return getDeclaringClass().getName()
  118. + (isConstructor() ? Descriptor.toString(getSignature())
  119. : ("." + MethodInfo.nameClinit + "()"));
  120. }
  121. /**
  122. * Obtains the name of this constructor.
  123. * It is the same as the simple name of the class declaring this
  124. * constructor. If this object represents a class initializer,
  125. * then this method returns <code>"&lt;clinit&gt;"</code>.
  126. */
  127. public String getName() {
  128. if (methodInfo.isStaticInitializer())
  129. return MethodInfo.nameClinit;
  130. else
  131. return declaringClass.getSimpleName();
  132. }
  133. /**
  134. * Returns true if the constructor (or static initializer)
  135. * is the default one. This method returns true if the constructor
  136. * takes some arguments but it does not perform anything except
  137. * calling <code>super()</code> (the no-argument constructor of
  138. * the super class).
  139. */
  140. public boolean isEmpty() {
  141. CodeAttribute ca = getMethodInfo2().getCodeAttribute();
  142. if (ca == null)
  143. return false; // native or abstract??
  144. // they are not allowed, though.
  145. ConstPool cp = ca.getConstPool();
  146. CodeIterator it = ca.iterator();
  147. try {
  148. int pos, desc;
  149. int op0 = it.byteAt(it.next());
  150. return op0 == Opcode.RETURN // empty static initializer
  151. || (op0 == Opcode.ALOAD_0
  152. && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL
  153. && (desc = cp.isConstructor(getSuperclassName(),
  154. it.u16bitAt(pos + 1))) != 0
  155. && "()V".equals(cp.getUtf8Info(desc))
  156. && it.byteAt(it.next()) == Opcode.RETURN
  157. && !it.hasNext());
  158. }
  159. catch (BadBytecode e) {}
  160. return false;
  161. }
  162. private String getSuperclassName() {
  163. ClassFile cf = declaringClass.getClassFile2();
  164. return cf.getSuperclass();
  165. }
  166. /**
  167. * Returns true if this constructor calls a constructor
  168. * of the super class. This method returns false if it
  169. * calls another constructor of this class by <code>this()</code>.
  170. */
  171. public boolean callsSuper() throws CannotCompileException {
  172. CodeAttribute codeAttr = methodInfo.getCodeAttribute();
  173. if (codeAttr != null) {
  174. CodeIterator it = codeAttr.iterator();
  175. try {
  176. int index = it.skipSuperConstructor();
  177. return index >= 0;
  178. }
  179. catch (BadBytecode e) {
  180. throw new CannotCompileException(e);
  181. }
  182. }
  183. return false;
  184. }
  185. /**
  186. * Sets a constructor body.
  187. *
  188. * @param src the source code representing the constructor body.
  189. * It must be a single statement or block.
  190. * If it is <code>null</code>, the substituted
  191. * constructor body does nothing except calling
  192. * <code>super()</code>.
  193. */
  194. public void setBody(String src) throws CannotCompileException {
  195. if (src == null)
  196. if (isClassInitializer())
  197. src = ";";
  198. else
  199. src = "super();";
  200. super.setBody(src);
  201. }
  202. /**
  203. * Copies a constructor body from another constructor.
  204. *
  205. * <p>All occurrences of the class names in the copied body
  206. * are replaced with the names specified by
  207. * <code>map</code> if <code>map</code> is not <code>null</code>.
  208. *
  209. * @param src the method that the body is copied from.
  210. * @param map the hashtable associating original class names
  211. * with substituted names.
  212. * It can be <code>null</code>.
  213. */
  214. public void setBody(CtConstructor src, ClassMap map)
  215. throws CannotCompileException
  216. {
  217. setBody0(src.declaringClass, src.methodInfo,
  218. declaringClass, methodInfo, map);
  219. }
  220. /**
  221. * Inserts bytecode just after another constructor in the super class
  222. * or this class is called.
  223. * It does not work if this object represents a class initializer.
  224. *
  225. * @param src the source code representing the inserted bytecode.
  226. * It must be a single statement or block.
  227. */
  228. public void insertBeforeBody(String src) throws CannotCompileException {
  229. CtClass cc = declaringClass;
  230. cc.checkModify();
  231. if (isClassInitializer())
  232. throw new CannotCompileException("class initializer");
  233. CodeAttribute ca = methodInfo.getCodeAttribute();
  234. CodeIterator iterator = ca.iterator();
  235. Bytecode b = new Bytecode(methodInfo.getConstPool(),
  236. ca.getMaxStack(), ca.getMaxLocals());
  237. b.setStackDepth(ca.getMaxStack());
  238. Javac jv = new Javac(b, cc);
  239. try {
  240. jv.recordParams(getParameterTypes(), false);
  241. jv.compileStmnt(src);
  242. ca.setMaxStack(b.getMaxStack());
  243. ca.setMaxLocals(b.getMaxLocals());
  244. iterator.skipConstructor();
  245. int pos = iterator.insertEx(b.get());
  246. iterator.insert(b.getExceptionTable(), pos);
  247. methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
  248. }
  249. catch (NotFoundException e) {
  250. throw new CannotCompileException(e);
  251. }
  252. catch (CompileError e) {
  253. throw new CannotCompileException(e);
  254. }
  255. catch (BadBytecode e) {
  256. throw new CannotCompileException(e);
  257. }
  258. }
  259. /* This method is called by addCatch() in CtBehavior.
  260. * super() and this() must not be in a try statement.
  261. */
  262. int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException {
  263. CodeIterator ci = ca.iterator();
  264. try {
  265. ci.skipConstructor();
  266. return ci.next();
  267. }
  268. catch (BadBytecode e) {
  269. throw new CannotCompileException(e);
  270. }
  271. }
  272. /**
  273. * Makes a copy of this constructor and converts it into a method.
  274. * The signature of the mehtod is the same as the that of this constructor.
  275. * The return type is <code>void</code>. The resulting method must be
  276. * appended to the class specified by <code>declaring</code>.
  277. * If this constructor is a static initializer, the resulting method takes
  278. * no parameter.
  279. *
  280. * <p>An occurrence of another constructor call <code>this()</code>
  281. * or a super constructor call <code>super()</code> is
  282. * eliminated from the resulting method.
  283. *
  284. * <p>The immediate super class of the class declaring this constructor
  285. * must be also a super class of the class declaring the resulting method.
  286. * If the constructor accesses a field, the class declaring the resulting method
  287. * must also declare a field with the same name and type.
  288. *
  289. * @param name the name of the resulting method.
  290. * @param declaring the class declaring the resulting method.
  291. */
  292. public CtMethod toMethod(String name, CtClass declaring)
  293. throws CannotCompileException
  294. {
  295. return toMethod(name, declaring, null);
  296. }
  297. /**
  298. * Makes a copy of this constructor and converts it into a method.
  299. * The signature of the method is the same as the that of this constructor.
  300. * The return type is <code>void</code>. The resulting method must be
  301. * appended to the class specified by <code>declaring</code>.
  302. * If this constructor is a static initializer, the resulting method takes
  303. * no parameter.
  304. *
  305. * <p>An occurrence of another constructor call <code>this()</code>
  306. * or a super constructor call <code>super()</code> is
  307. * eliminated from the resulting method.
  308. *
  309. * <p>The immediate super class of the class declaring this constructor
  310. * must be also a super class of the class declaring the resulting method
  311. * (this is obviously true if the second parameter <code>declaring</code> is
  312. * the same as the class declaring this constructor).
  313. * If the constructor accesses a field, the class declaring the resulting method
  314. * must also declare a field with the same name and type.
  315. *
  316. * @param name the name of the resulting method.
  317. * @param declaring the class declaring the resulting method.
  318. * It is normally the same as the class declaring this
  319. * constructor.
  320. * @param map the hash table associating original class names
  321. * with substituted names. The original class names will be
  322. * replaced while making a copy.
  323. * <code>map</code> can be <code>null</code>.
  324. */
  325. public CtMethod toMethod(String name, CtClass declaring, ClassMap map)
  326. throws CannotCompileException
  327. {
  328. CtMethod method = new CtMethod(null, declaring);
  329. method.copy(this, false, map);
  330. if (isConstructor()) {
  331. MethodInfo minfo = method.getMethodInfo2();
  332. CodeAttribute ca = minfo.getCodeAttribute();
  333. if (ca != null) {
  334. removeConsCall(ca);
  335. try {
  336. methodInfo.rebuildStackMapIf6(declaring.getClassPool(),
  337. declaring.getClassFile2());
  338. }
  339. catch (BadBytecode e) {
  340. throw new CannotCompileException(e);
  341. }
  342. }
  343. }
  344. method.setName(name);
  345. return method;
  346. }
  347. private static void removeConsCall(CodeAttribute ca)
  348. throws CannotCompileException
  349. {
  350. CodeIterator iterator = ca.iterator();
  351. try {
  352. int pos = iterator.skipConstructor();
  353. if (pos >= 0) {
  354. int mref = iterator.u16bitAt(pos + 1);
  355. String desc = ca.getConstPool().getMethodrefType(mref);
  356. int num = Descriptor.numOfParameters(desc) + 1;
  357. if (num > 3)
  358. iterator.insertGap(pos, num - 3);
  359. iterator.writeByte(Opcode.POP, pos++); // this
  360. iterator.writeByte(Opcode.NOP, pos);
  361. iterator.writeByte(Opcode.NOP, pos + 1);
  362. Descriptor.Iterator it = new Descriptor.Iterator(desc);
  363. while (true) {
  364. it.next();
  365. if (it.isParameter())
  366. iterator.writeByte(it.is2byte() ? Opcode.POP2 : Opcode.POP,
  367. pos++);
  368. else
  369. break;
  370. }
  371. }
  372. }
  373. catch (BadBytecode e) {
  374. throw new CannotCompileException(e);
  375. }
  376. }
  377. }