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