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 17 package javassist; 18 19 import javassist.CtMethod.ConstParameter; 20 import javassist.bytecode.Bytecode; 21 import javassist.bytecode.ConstPool; 22 import javassist.compiler.CompileError; 23 import javassist.compiler.Javac; 24 25 /** 26 * A collection of static methods for creating a <code>CtConstructor</code>. 27 * An instance of this class does not make any sense. 28 * 29 * <p>A class initializer (static constructor) cannot be created by the 30 * methods in this class. Call <code>makeClassInitializer()</code> in 31 * <code>CtClass</code> and append code snippet to the body of the class 32 * initializer obtained by <code>makeClassInitializer()</code>. 33 * 34 * @see CtClass#addConstructor(CtConstructor) 35 * @see CtClass#makeClassInitializer() 36 */ 37 public class CtNewConstructor { 38 /** 39 * Specifies that no parameters are passed to a super-class' 40 * constructor. That is, the default constructor is invoked. 41 */ 42 public static final int PASS_NONE = 0; // call super() 43 44 /** 45 * Specifies that parameters are converted into an array of 46 * <code>Object</code> and passed to a super-class' 47 * constructor. 48 */ 49 public static final int PASS_ARRAY = 1; // an array of parameters 50 51 /** 52 * Specifies that parameters are passed <i>as is</i> 53 * to a super-class' constructor. The signature of that 54 * constructor must be the same as that of the created constructor. 55 */ 56 public static final int PASS_PARAMS = 2; 57 58 /** 59 * Compiles the given source code and creates a constructor. 60 * The source code must include not only the constructor body 61 * but the whole declaration. 62 * 63 * @param src the source text. 64 * @param declaring the class to which the created constructor is added. 65 */ make(String src, CtClass declaring)66 public static CtConstructor make(String src, CtClass declaring) 67 throws CannotCompileException 68 { 69 Javac compiler = new Javac(declaring); 70 try { 71 CtMember obj = compiler.compile(src); 72 if (obj instanceof CtConstructor) { 73 // a stack map table has been already created. 74 return (CtConstructor)obj; 75 } 76 } 77 catch (CompileError e) { 78 throw new CannotCompileException(e); 79 } 80 81 throw new CannotCompileException("not a constructor"); 82 } 83 84 /** 85 * Creates a public constructor. 86 * 87 * @param parameters a list of the parameter types. 88 * @param exceptions a list of the exception types. 89 * @param body the source text of the constructor body. 90 * It must be a block surrounded by <code>{}</code>. 91 * If it is <code>null</code>, the substituted 92 * constructor body does nothing except calling 93 * <code>super()</code>. 94 * @param declaring the class to which the created method is added. 95 */ make(CtClass[] parameters, CtClass[] exceptions, String body, CtClass declaring)96 public static CtConstructor make(CtClass[] parameters, 97 CtClass[] exceptions, 98 String body, CtClass declaring) 99 throws CannotCompileException 100 { 101 try { 102 CtConstructor cc = new CtConstructor(parameters, declaring); 103 cc.setExceptionTypes(exceptions); 104 cc.setBody(body); 105 return cc; 106 } 107 catch (NotFoundException e) { 108 throw new CannotCompileException(e); 109 } 110 } 111 112 /** 113 * Creates a copy of a constructor. 114 * This is a convenience method for calling 115 * {@link CtConstructor#CtConstructor(CtConstructor, CtClass, ClassMap) this constructor}. 116 * See the description of the constructor for particular behavior of the copying. 117 * 118 * @param c the copied constructor. 119 * @param declaring the class to which the created method is added. 120 * @param map the hash table associating original class names 121 * with substituted names. 122 * It can be <code>null</code>. 123 * 124 * @see CtConstructor#CtConstructor(CtConstructor,CtClass,ClassMap) 125 */ copy(CtConstructor c, CtClass declaring, ClassMap map)126 public static CtConstructor copy(CtConstructor c, CtClass declaring, 127 ClassMap map) throws CannotCompileException { 128 return new CtConstructor(c, declaring, map); 129 } 130 131 /** 132 * Creates a default (public) constructor. 133 * 134 * <p>The created constructor takes no parameter. It calls 135 * <code>super()</code>. 136 */ defaultConstructor(CtClass declaring)137 public static CtConstructor defaultConstructor(CtClass declaring) 138 throws CannotCompileException 139 { 140 CtConstructor cons = new CtConstructor((CtClass[])null, declaring); 141 142 ConstPool cp = declaring.getClassFile2().getConstPool(); 143 Bytecode code = new Bytecode(cp, 1, 1); 144 code.addAload(0); 145 try { 146 code.addInvokespecial(declaring.getSuperclass(), 147 "<init>", "()V"); 148 } 149 catch (NotFoundException e) { 150 throw new CannotCompileException(e); 151 } 152 153 code.add(Bytecode.RETURN); 154 155 // no need to construct a stack map table. 156 cons.getMethodInfo2().setCodeAttribute(code.toCodeAttribute()); 157 return cons; 158 } 159 160 /** 161 * Creates a public constructor that only calls a constructor 162 * in the super class. The created constructor receives parameters 163 * specified by <code>parameters</code> but calls the super's 164 * constructor without those parameters (that is, it calls the default 165 * constructor). 166 * 167 * <p>The parameters passed to the created constructor should be 168 * used for field initialization. <code>CtField.Initializer</code> 169 * objects implicitly insert initialization code in constructor 170 * bodies. 171 * 172 * @param parameters parameter types 173 * @param exceptions exception types 174 * @param declaring the class to which the created constructor 175 * is added. 176 * @see CtField.Initializer#byParameter(int) 177 */ skeleton(CtClass[] parameters, CtClass[] exceptions, CtClass declaring)178 public static CtConstructor skeleton(CtClass[] parameters, 179 CtClass[] exceptions, CtClass declaring) 180 throws CannotCompileException 181 { 182 return make(parameters, exceptions, PASS_NONE, 183 null, null, declaring); 184 } 185 186 /** 187 * Creates a public constructor that only calls a constructor 188 * in the super class. The created constructor receives parameters 189 * specified by <code>parameters</code> and calls the super's 190 * constructor with those parameters. 191 * 192 * @param parameters parameter types 193 * @param exceptions exception types 194 * @param declaring the class to which the created constructor 195 * is added. 196 */ make(CtClass[] parameters, CtClass[] exceptions, CtClass declaring)197 public static CtConstructor make(CtClass[] parameters, 198 CtClass[] exceptions, CtClass declaring) 199 throws CannotCompileException 200 { 201 return make(parameters, exceptions, PASS_PARAMS, 202 null, null, declaring); 203 } 204 205 /** 206 * Creates a public constructor. 207 * 208 * <p>If <code>howto</code> is <code>PASS_PARAMS</code>, 209 * the created constructor calls the super's constructor with the 210 * same signature. The superclass must contain 211 * a constructor taking the same set of parameters as the created one. 212 * 213 * <p>If <code>howto</code> is <code>PASS_NONE</code>, 214 * the created constructor calls the super's default constructor. 215 * The superclass must contain a constructor taking no parameters. 216 * 217 * <p>If <code>howto</code> is <code>PASS_ARRAY</code>, 218 * the created constructor calls the super's constructor 219 * with the given parameters in the form of an array of 220 * <code>Object</code>. The signature of the super's constructor 221 * must be: 222 * 223 * <pre>constructor(Object[] params, <type> cvalue) 224 * </pre> 225 * 226 * <p>Here, <code>cvalue</code> is the constant value specified 227 * by <code>cparam</code>. 228 * 229 * <p>If <code>cparam</code> is <code>null</code>, the signature 230 * must be: 231 * 232 * <pre>constructor(Object[] params)</pre> 233 * 234 * <p>If <code>body</code> is not null, a copy of that method is 235 * embedded in the body of the created constructor. 236 * The embedded method is executed after 237 * the super's constructor is called and the values of fields are 238 * initialized. Note that <code>body</code> must not 239 * be a constructor but a method. 240 * 241 * <p>Since the embedded method is wrapped 242 * in parameter-conversion code 243 * as in <code>CtNewMethod.wrapped()</code>, 244 * the constructor parameters are 245 * passed in the form of an array of <code>Object</code>. 246 * The method specified by <code>body</code> must have the 247 * signature shown below: 248 * 249 * <pre>Object method(Object[] params, <type> cvalue)</pre> 250 * 251 * <p>If <code>cparam</code> is <code>null</code>, the signature 252 * must be: 253 * 254 * <pre>Object method(Object[] params)</pre> 255 * 256 * <p>Although the type of the returned value is <code>Object</code>, 257 * the value must be always <code>null</code>. 258 * 259 * <p><i>Example:</i> 260 * 261 * <pre> 262 * ClassPool pool = ... ; 263 * CtClass xclass = pool.makeClass("X"); 264 * CtMethod method = pool.getMethod("Sample", "m"); 265 * xclass.setSuperclass(pool.get("Y")); 266 * CtClass[] argTypes = { CtClass.intType }; 267 * ConstParameter cparam = ConstParameter.string("test"); 268 * CtConstructor c = CtNewConstructor.make(argTypes, null, 269 * PASS_PARAMS, method, cparam, xclass); 270 * xclass.addConstructor(c);</pre> 271 * 272 * <p>where the class <code>Sample</code> is as follows: 273 * 274 * <pre> 275 * public class Sample { 276 * public Object m(Object[] args, String msg) { 277 * System.out.println(msg); 278 * return null; 279 * } 280 * }</pre> 281 * 282 * <p>This program produces the following class: 283 * 284 * <pre> 285 * public class X extends Y { 286 * public X(int p0) { 287 * super(p0); 288 * String msg = "test"; 289 * Object[] args = new Object[] { p0 }; 290 * // begin of copied body 291 * System.out.println(msg); 292 * Object result = null; 293 * // end 294 * } 295 * }</pre> 296 * 297 * @param parameters a list of the parameter types 298 * @param exceptions a list of the exceptions 299 * @param howto how to pass parameters to the super-class' 300 * constructor (<code>PASS_NONE</code>, 301 * <code>PASS_ARRAY</code>, 302 * or <code>PASS_PARAMS</code>) 303 * @param body appended body (may be <code>null</code>). 304 * It must be not a constructor but a method. 305 * @param cparam constant parameter (may be <code>null</code>.) 306 * @param declaring the class to which the created constructor 307 * is added. 308 * 309 * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass) 310 */ make(CtClass[] parameters, CtClass[] exceptions, int howto, CtMethod body, ConstParameter cparam, CtClass declaring)311 public static CtConstructor make(CtClass[] parameters, 312 CtClass[] exceptions, int howto, 313 CtMethod body, ConstParameter cparam, 314 CtClass declaring) 315 throws CannotCompileException 316 { 317 return CtNewWrappedConstructor.wrapped(parameters, exceptions, 318 howto, body, cparam, declaring); 319 } 320 } 321