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 java.io.DataOutputStream;
19import java.io.IOException;
20import javassist.bytecode.ClassFile;
21
22class CtNewClass extends CtClassType {
23    /* true if the class is an interface.
24     */
25    protected boolean hasConstructor;
26
27    CtNewClass(String name, ClassPool cp,
28               boolean isInterface, CtClass superclass) {
29        super(name, cp);
30        wasChanged = true;
31        String superName;
32        if (isInterface || superclass == null)
33            superName = null;
34        else
35            superName = superclass.getName();
36
37        classfile = new ClassFile(isInterface, name, superName);
38        if (isInterface && superclass != null)
39            classfile.setInterfaces(new String[] { superclass.getName() });
40
41        setModifiers(Modifier.setPublic(getModifiers()));
42        hasConstructor = isInterface;
43    }
44
45    protected void extendToString(StringBuffer buffer) {
46        if (hasConstructor)
47            buffer.append("hasConstructor ");
48
49        super.extendToString(buffer);
50    }
51
52    public void addConstructor(CtConstructor c)
53        throws CannotCompileException
54    {
55        hasConstructor = true;
56        super.addConstructor(c);
57    }
58
59    public void toBytecode(DataOutputStream out)
60        throws CannotCompileException, IOException
61    {
62        if (!hasConstructor)
63            try {
64                inheritAllConstructors();
65                hasConstructor = true;
66            }
67            catch (NotFoundException e) {
68                throw new CannotCompileException(e);
69            }
70
71        super.toBytecode(out);
72    }
73
74    /**
75     * Adds constructors inhrited from the super class.
76     *
77     * <p>After this method is called, the class inherits all the
78     * constructors from the super class.  The added constructor
79     * calls the super's constructor with the same signature.
80     */
81    public void inheritAllConstructors()
82        throws CannotCompileException, NotFoundException
83    {
84        CtClass superclazz;
85        CtConstructor[] cs;
86
87        superclazz = getSuperclass();
88        cs = superclazz.getDeclaredConstructors();
89
90        int n = 0;
91        for (int i = 0; i < cs.length; ++i) {
92            CtConstructor c = cs[i];
93            int mod = c.getModifiers();
94            if (isInheritable(mod, superclazz)) {
95                CtConstructor cons
96                    = CtNewConstructor.make(c.getParameterTypes(),
97                                            c.getExceptionTypes(), this);
98                cons.setModifiers(mod & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE));
99                addConstructor(cons);
100                ++n;
101            }
102        }
103
104        if (n < 1)
105            throw new CannotCompileException(
106                        "no inheritable constructor in " + superclazz.getName());
107
108    }
109
110    private boolean isInheritable(int mod, CtClass superclazz) {
111        if (Modifier.isPrivate(mod))
112            return false;
113
114        if (Modifier.isPackage(mod)) {
115            String pname = getPackageName();
116            String pname2 = superclazz.getPackageName();
117            if (pname == null)
118                return pname2 == null;
119            else
120                return pname.equals(pname2);
121        }
122
123        return true;
124    }
125}
126