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

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