169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist; 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.*; 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.Javac; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.CompileError; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * An instance of CtConstructor represents a constructor. 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It may represent a static constructor 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * (class initializer). To distinguish a constructor and a class 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * initializer, call <code>isClassInitializer()</code>. 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>See the super class <code>CtBehavior</code> as well since 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a number of useful methods are in <code>CtBehavior</code>. 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtClass#getDeclaredConstructors() 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtClass#getClassInitializer() 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtNewConstructor 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic final class CtConstructor extends CtBehavior { 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected CtConstructor(MethodInfo minfo, CtClass declaring) { 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal super(declaring, minfo); 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Creates a constructor with no constructor body. 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The created constructor 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * must be added to a class with <code>CtClass.addConstructor()</code>. 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The created constructor does not include a constructor body, 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * which must be specified with <code>setBody()</code>. 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param declaring the class to which the created method is added. 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param parameters a list of the parameter types 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtClass#addConstructor(CtConstructor) 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtConstructor#setBody(String) 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtConstructor#setBody(CtConstructor,ClassMap) 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public CtConstructor(CtClass[] parameters, CtClass declaring) { 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this((MethodInfo)null, declaring); 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ConstPool cp = declaring.getClassFile2().getConstPool(); 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String desc = Descriptor.ofConstructor(parameters); 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methodInfo = new MethodInfo(cp, "<init>", desc); 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal setModifiers(Modifier.PUBLIC); 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Creates a copy of a <code>CtConstructor</code> object. 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The created constructor must be 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * added to a class with <code>CtClass.addConstructor()</code>. 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>All occurrences of class names in the created constructor 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * are replaced with names specified by 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>map</code> if <code>map</code> is not <code>null</code>. 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>By default, all the occurrences of the names of the class 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * declaring <code>src</code> and the superclass are replaced 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with the name of the class and the superclass that 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the created constructor is added to. 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This is done whichever <code>map</code> is null or not. 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * To prevent this replacement, call <code>ClassMap.fix()</code> 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or <code>put()</code> to explicitly specify replacement. 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p><b>Note:</b> if the <code>.class</code> notation (for example, 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>String.class</code>) is included in an expression, the 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javac compiler may produce a helper method. 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Since this constructor never 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * copies this helper method, the programmers have the responsiblity of 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * copying it. Otherwise, use <code>Class.forName()</code> in the 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * expression. 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param src the source method. 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param declaring the class to which the created method is added. 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param map the hashtable associating original class names 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with substituted names. 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It can be <code>null</code>. 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtClass#addConstructor(CtConstructor) 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see ClassMap#fix(String) 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public CtConstructor(CtConstructor src, CtClass declaring, ClassMap map) 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this((MethodInfo)null, declaring); 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal copy(src, true, map); 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns true if this object represents a constructor. 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isConstructor() { 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return methodInfo.isConstructor(); 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns true if this object represents a static initializer. 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isClassInitializer() { 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return methodInfo.isStaticInitializer(); 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the constructor name followed by parameter types 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * such as <code>javassist.CtConstructor(CtClass[],CtClass)</code>. 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @since 3.5 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public String getLongName() { 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return getDeclaringClass().getName() 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + (isConstructor() ? Descriptor.toString(getSignature()) 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal : ("." + MethodInfo.nameClinit + "()")); 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Obtains the name of this constructor. 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It is the same as the simple name of the class declaring this 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * constructor. If this object represents a class initializer, 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * then this method returns <code>"<clinit>"</code>. 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public String getName() { 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (methodInfo.isStaticInitializer()) 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return MethodInfo.nameClinit; 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return declaringClass.getSimpleName(); 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns true if the constructor (or static initializer) 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is the default one. This method returns true if the constructor 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * takes some arguments but it does not perform anything except 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * calling <code>super()</code> (the no-argument constructor of 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the super class). 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isEmpty() { 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeAttribute ca = getMethodInfo2().getCodeAttribute(); 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (ca == null) 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return false; // native or abstract?? 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // they are not allowed, though. 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ConstPool cp = ca.getConstPool(); 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator it = ca.iterator(); 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos, desc; 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int op0 = it.byteAt(it.next()); 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return op0 == Opcode.RETURN // empty static initializer 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal || (op0 == Opcode.ALOAD_0 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal && (desc = cp.isConstructor(getSuperclassName(), 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal it.u16bitAt(pos + 1))) != 0 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal && "()V".equals(cp.getUtf8Info(desc)) 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal && it.byteAt(it.next()) == Opcode.RETURN 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal && !it.hasNext()); 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) {} 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return false; 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private String getSuperclassName() { 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ClassFile cf = declaringClass.getClassFile2(); 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return cf.getSuperclass(); 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns true if this constructor calls a constructor 18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * of the super class. This method returns false if it 18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * calls another constructor of this class by <code>this()</code>. 18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean callsSuper() throws CannotCompileException { 18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeAttribute codeAttr = methodInfo.getCodeAttribute(); 18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (codeAttr != null) { 18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator it = codeAttr.iterator(); 18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int index = it.skipSuperConstructor(); 19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return index >= 0; 19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) { 19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return false; 19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Sets a constructor body. 20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param src the source code representing the constructor body. 20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It must be a single statement or block. 20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If it is <code>null</code>, the substituted 20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * constructor body does nothing except calling 20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>super()</code>. 20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void setBody(String src) throws CannotCompileException { 21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (src == null) 21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (isClassInitializer()) 21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal src = ";"; 21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal src = "super();"; 21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal super.setBody(src); 21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copies a constructor body from another constructor. 22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>All occurrences of the class names in the copied body 22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * are replaced with the names specified by 22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>map</code> if <code>map</code> is not <code>null</code>. 22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param src the method that the body is copied from. 22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param map the hashtable associating original class names 22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with substituted names. 22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It can be <code>null</code>. 23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void setBody(CtConstructor src, ClassMap map) 23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal setBody0(src.declaringClass, src.methodInfo, 23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal declaringClass, methodInfo, map); 23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Inserts bytecode just after another constructor in the super class 24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or this class is called. 24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It does not work if this object represents a class initializer. 24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param src the source code representing the inserted bytecode. 24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It must be a single statement or block. 24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void insertBeforeBody(String src) throws CannotCompileException { 24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass cc = declaringClass; 24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal cc.checkModify(); 24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (isClassInitializer()) 25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException("class initializer"); 25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeAttribute ca = methodInfo.getCodeAttribute(); 25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator iterator = ca.iterator(); 25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Bytecode b = new Bytecode(methodInfo.getConstPool(), 25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ca.getMaxStack(), ca.getMaxLocals()); 25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal b.setStackDepth(ca.getMaxStack()); 25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Javac jv = new Javac(b, cc); 25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal jv.recordParams(getParameterTypes(), false); 26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal jv.compileStmnt(src); 26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ca.setMaxStack(b.getMaxStack()); 26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ca.setMaxLocals(b.getMaxLocals()); 26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iterator.skipConstructor(); 26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos = iterator.insertEx(b.get()); 26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iterator.insert(b.getExceptionTable(), pos); 26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); 26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (NotFoundException e) { 26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (CompileError e) { 27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) { 27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* This method is called by addCatch() in CtBehavior. 28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * super() and this() must not be in a try statement. 28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException { 28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator ci = ca.iterator(); 28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ci.skipConstructor(); 28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return ci.next(); 28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) { 28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Makes a copy of this constructor and converts it into a method. 29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The signature of the mehtod is the same as the that of this constructor. 29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The return type is <code>void</code>. The resulting method must be 29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * appended to the class specified by <code>declaring</code>. 29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If this constructor is a static initializer, the resulting method takes 29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * no parameter. 30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>An occurrence of another constructor call <code>this()</code> 30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or a super constructor call <code>super()</code> is 30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * eliminated from the resulting method. 30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The immediate super class of the class declaring this constructor 30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * must be also a super class of the class declaring the resulting method. 30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the constructor accesses a field, the class declaring the resulting method 30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * must also declare a field with the same name and type. 30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param name the name of the resulting method. 31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param declaring the class declaring the resulting method. 31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public CtMethod toMethod(String name, CtClass declaring) 31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return toMethod(name, declaring, null); 31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Makes a copy of this constructor and converts it into a method. 32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The signature of the method is the same as the that of this constructor. 32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The return type is <code>void</code>. The resulting method must be 32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * appended to the class specified by <code>declaring</code>. 32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If this constructor is a static initializer, the resulting method takes 32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * no parameter. 32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>An occurrence of another constructor call <code>this()</code> 32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or a super constructor call <code>super()</code> is 32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * eliminated from the resulting method. 33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The immediate super class of the class declaring this constructor 33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * must be also a super class of the class declaring the resulting method 33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * (this is obviously true if the second parameter <code>declaring</code> is 33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the same as the class declaring this constructor). 33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the constructor accesses a field, the class declaring the resulting method 33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * must also declare a field with the same name and type. 33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param name the name of the resulting method. 33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param declaring the class declaring the resulting method. 34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It is normally the same as the class declaring this 34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * constructor. 34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param map the hash table associating original class names 34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with substituted names. The original class names will be 34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * replaced while making a copy. 34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>map</code> can be <code>null</code>. 34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public CtMethod toMethod(String name, CtClass declaring, ClassMap map) 34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod method = new CtMethod(null, declaring); 35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal method.copy(this, false, map); 35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (isConstructor()) { 35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal MethodInfo minfo = method.getMethodInfo2(); 35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeAttribute ca = minfo.getCodeAttribute(); 35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (ca != null) { 35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal removeConsCall(ca); 35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methodInfo.rebuildStackMapIf6(declaring.getClassPool(), 35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal declaring.getClassFile2()); 36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) { 36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal method.setName(name); 36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return method; 36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static void removeConsCall(CodeAttribute ca) 37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws CannotCompileException 37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator iterator = ca.iterator(); 37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos = iterator.skipConstructor(); 37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (pos >= 0) { 37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int mref = iterator.u16bitAt(pos + 1); 37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String desc = ca.getConstPool().getMethodrefType(mref); 38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int num = Descriptor.numOfParameters(desc) + 1; 38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (num > 3) 38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal pos = iterator.insertGapAt(pos, num - 3, false).position; 38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iterator.writeByte(Opcode.POP, pos++); // this 38569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iterator.writeByte(Opcode.NOP, pos); 38669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iterator.writeByte(Opcode.NOP, pos + 1); 38769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Descriptor.Iterator it = new Descriptor.Iterator(desc); 38869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (true) { 38969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal it.next(); 39069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (it.isParameter()) 39169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal iterator.writeByte(it.is2byte() ? Opcode.POP2 : Opcode.POP, 39269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal pos++); 39369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 39469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal break; 39569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (BadBytecode e) { 39969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotCompileException(e); 40069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 40169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 40269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 403