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 16KB

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