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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2006 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. next = null;
  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. * 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. *
  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. * Obtains the name of this constructor.
  112. * It is the same as the simple name of the class declaring this
  113. * constructor. If this object represents a class initializer,
  114. * then this method returns <code>"&lt;clinit&gt;"</code>.
  115. */
  116. public String getName() {
  117. if (methodInfo.isStaticInitializer())
  118. return MethodInfo.nameClinit;
  119. else
  120. return declaringClass.getSimpleName();
  121. }
  122. /**
  123. * Returns true if the constructor is the default one.
  124. */
  125. public boolean isEmpty() {
  126. CodeAttribute ca = getMethodInfo2().getCodeAttribute();
  127. if (ca == null)
  128. return false; // native or abstract??
  129. // they are not allowed, though.
  130. ConstPool cp = ca.getConstPool();
  131. CodeIterator it = ca.iterator();
  132. try {
  133. int pos, desc;
  134. return it.byteAt(it.next()) == Opcode.ALOAD_0
  135. && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL
  136. && (desc = cp.isConstructor(CtClass.javaLangObject,
  137. it.u16bitAt(pos + 1))) != 0
  138. && cp.getUtf8Info(desc).equals("()V")
  139. && it.byteAt(it.next()) == Opcode.RETURN
  140. && !it.hasNext();
  141. }
  142. catch (BadBytecode e) {}
  143. return false;
  144. }
  145. /**
  146. * Returns true if this constructor calls a constructor
  147. * of the super class. This method returns false if it
  148. * calls another constructor of this class by <code>this()</code>.
  149. */
  150. public boolean callsSuper() throws CannotCompileException {
  151. CodeAttribute codeAttr = methodInfo.getCodeAttribute();
  152. if (codeAttr != null) {
  153. CodeIterator it = codeAttr.iterator();
  154. try {
  155. int index = it.skipSuperConstructor();
  156. return index >= 0;
  157. }
  158. catch (BadBytecode e) {
  159. throw new CannotCompileException(e);
  160. }
  161. }
  162. return false;
  163. }
  164. /**
  165. * Sets a constructor body.
  166. *
  167. * @param src the source code representing the constructor body.
  168. * It must be a single statement or block.
  169. * If it is <code>null</code>, the substituted
  170. * constructor body does nothing except calling
  171. * <code>super()</code>.
  172. */
  173. public void setBody(String src) throws CannotCompileException {
  174. if (src == null)
  175. if (isClassInitializer())
  176. src = ";";
  177. else
  178. src = "super();";
  179. super.setBody(src);
  180. }
  181. /**
  182. * Copies a constructor body from another constructor.
  183. *
  184. * <p>All occurrences of the class names in the copied body
  185. * are replaced with the names specified by
  186. * <code>map</code> if <code>map</code> is not <code>null</code>.
  187. *
  188. * @param src the method that the body is copied from.
  189. * @param map the hashtable associating original class names
  190. * with substituted names.
  191. * It can be <code>null</code>.
  192. */
  193. public void setBody(CtConstructor src, ClassMap map)
  194. throws CannotCompileException
  195. {
  196. setBody0(src.declaringClass, src.methodInfo,
  197. declaringClass, methodInfo, map);
  198. }
  199. /**
  200. * Inserts bytecode just after another constructor in the super class
  201. * or this class is called.
  202. * It does not work if this object represents a class initializer.
  203. *
  204. * @param src the source code representing the inserted bytecode.
  205. * It must be a single statement or block.
  206. */
  207. public void insertBeforeBody(String src) throws CannotCompileException {
  208. declaringClass.checkModify();
  209. if (isClassInitializer())
  210. throw new CannotCompileException("class initializer");
  211. CodeAttribute ca = methodInfo.getCodeAttribute();
  212. CodeIterator iterator = ca.iterator();
  213. Bytecode b = new Bytecode(methodInfo.getConstPool(),
  214. ca.getMaxStack(), ca.getMaxLocals());
  215. b.setStackDepth(ca.getMaxStack());
  216. Javac jv = new Javac(b, declaringClass);
  217. try {
  218. jv.recordParams(getParameterTypes(), false);
  219. jv.compileStmnt(src);
  220. ca.setMaxStack(b.getMaxStack());
  221. ca.setMaxLocals(b.getMaxLocals());
  222. iterator.skipConstructor();
  223. int pos = iterator.insertEx(b.get());
  224. iterator.insert(b.getExceptionTable(), pos);
  225. }
  226. catch (NotFoundException e) {
  227. throw new CannotCompileException(e);
  228. }
  229. catch (CompileError e) {
  230. throw new CannotCompileException(e);
  231. }
  232. catch (BadBytecode e) {
  233. throw new CannotCompileException(e);
  234. }
  235. }
  236. /* This method is called by addCatch() in CtBehavior.
  237. * super() and this() must not be in a try statement.
  238. */
  239. int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException {
  240. CodeIterator ci = ca.iterator();
  241. try {
  242. ci.skipConstructor();
  243. return ci.next();
  244. }
  245. catch (BadBytecode e) {
  246. throw new CannotCompileException(e);
  247. }
  248. }
  249. /**
  250. * Makes a copy of this constructor and converts it into a method.
  251. * The signature of the mehtod is the same as the that of this constructor.
  252. * The return type is <code>void</code>. The resulting method must be
  253. * appended to the class specified by <code>declaring</code>.
  254. * If this constructor is a static initializer, the resulting method takes
  255. * no parameter.
  256. *
  257. * <p>An occurrence of another constructor call <code>this()</code>
  258. * or a super constructor call <code>super()</code> is
  259. * eliminated from the resulting method.
  260. *
  261. * <p>The immediate super class of the class declaring this constructor
  262. * must be also a super class of the class declaring the resulting method.
  263. * If the constructor accesses a field, the class declaring the resulting method
  264. * must also declare a field with the same name and type.
  265. *
  266. * @param name the name of the resulting method.
  267. * @param declaring the class declaring the resulting method.
  268. */
  269. public CtMethod toMethod(String name, CtClass declaring)
  270. throws CannotCompileException
  271. {
  272. CtMethod method = new CtMethod(null, declaring);
  273. method.copy(this, false, null);
  274. if (isConstructor()) {
  275. MethodInfo minfo = method.getMethodInfo2();
  276. CodeAttribute ca = minfo.getCodeAttribute();
  277. if (ca != null)
  278. removeConsCall(ca);
  279. }
  280. method.setName(name);
  281. return method;
  282. }
  283. private static void removeConsCall(CodeAttribute ca)
  284. throws CannotCompileException
  285. {
  286. CodeIterator iterator = ca.iterator();
  287. try {
  288. int pos = iterator.skipConstructor();
  289. if (pos >= 0) {
  290. int mref = iterator.u16bitAt(pos + 1);
  291. String desc = ca.getConstPool().getMethodrefType(mref);
  292. int num = Descriptor.numOfParameters(desc) + 1;
  293. if (num > 3)
  294. iterator.insertGap(pos, num - 3);
  295. iterator.writeByte(Opcode.POP, pos++); // this
  296. iterator.writeByte(Opcode.NOP, pos);
  297. iterator.writeByte(Opcode.NOP, pos + 1);
  298. Descriptor.Iterator it = new Descriptor.Iterator(desc);
  299. while (true) {
  300. it.next();
  301. if (it.isParameter())
  302. iterator.writeByte(it.is2byte() ? Opcode.POP2 : Opcode.POP,
  303. pos++);
  304. else
  305. break;
  306. }
  307. }
  308. }
  309. catch (BadBytecode e) {
  310. throw new CannotCompileException(e);
  311. }
  312. }
  313. }