All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.CtConstructor Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.3.0
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist;

import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.Bytecode;
import com.feilong.lib.javassist.bytecode.ClassFile;
import com.feilong.lib.javassist.bytecode.CodeAttribute;
import com.feilong.lib.javassist.bytecode.CodeIterator;
import com.feilong.lib.javassist.bytecode.ConstPool;
import com.feilong.lib.javassist.bytecode.Descriptor;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.Opcode;
import com.feilong.lib.javassist.compiler.CompileError;
import com.feilong.lib.javassist.compiler.Javac;

/**
 * An instance of CtConstructor represents a constructor.
 * It may represent a static constructor
 * (class initializer). To distinguish a constructor and a class
 * initializer, call isClassInitializer().
 *
 * 

* See the super class CtBehavior as well since * a number of useful methods are in CtBehavior. * * @see CtClass#getDeclaredConstructors() * @see CtClass#getClassInitializer() * @see CtNewConstructor */ public final class CtConstructor extends CtBehavior{ protected CtConstructor(MethodInfo minfo, CtClass declaring){ super(declaring, minfo); } /** * Creates a constructor with no constructor body. * The created constructor * must be added to a class with CtClass.addConstructor(). * *

* The created constructor does not include a constructor body, * which must be specified with setBody(). * * @param declaring * the class to which the created method is added. * @param parameters * a list of the parameter types * * @see CtClass#addConstructor(CtConstructor) * @see CtConstructor#setBody(String) * @see CtConstructor#setBody(CtConstructor,ClassMap) */ public CtConstructor(CtClass[] parameters, CtClass declaring){ this((MethodInfo) null, declaring); ConstPool cp = declaring.getClassFile2().getConstPool(); String desc = Descriptor.ofConstructor(parameters); methodInfo = new MethodInfo(cp, "", desc); setModifiers(Modifier.PUBLIC); } /** * Creates a copy of a CtConstructor object. * The created constructor must be * added to a class with CtClass.addConstructor(). * *

* All occurrences of class names in the created constructor * are replaced with names specified by * map if map is not null. * *

* By default, all the occurrences of the names of the class * declaring src and the superclass are replaced * with the name of the class and the superclass that * the created constructor is added to. * This is done whichever map is null or not. * To prevent this replacement, call ClassMap.fix() * or put() to explicitly specify replacement. * *

* Note: if the .class notation (for example, * String.class) is included in an expression, the * Javac compiler may produce a helper method. * Since this constructor never * copies this helper method, the programmers have the responsiblity of * copying it. Otherwise, use Class.forName() in the * expression. * * @param src * the source method. * @param declaring * the class to which the created method is added. * @param map * the hashtable associating original class names * with substituted names. * It can be null. * * @see CtClass#addConstructor(CtConstructor) * @see ClassMap#fix(String) */ public CtConstructor(CtConstructor src, CtClass declaring, ClassMap map) throws CannotCompileException{ this((MethodInfo) null, declaring); copy(src, true, map); } /** * Returns true if this object represents a constructor. */ public boolean isConstructor(){ return methodInfo.isConstructor(); } /** * Returns true if this object represents a static initializer. */ public boolean isClassInitializer(){ return methodInfo.isStaticInitializer(); } /** * Returns the constructor name followed by parameter types * such as javassist.CtConstructor(CtClass[],CtClass). * * @since 3.5 */ @Override public String getLongName(){ return getDeclaringClass().getName() + (isConstructor() ? Descriptor.toString(getSignature()) : ("." + MethodInfo.nameClinit + "()")); } /** * Obtains the name of this constructor. * It is the same as the simple name of the class declaring this * constructor. If this object represents a class initializer, * then this method returns "<clinit>". */ @Override public String getName(){ if (methodInfo.isStaticInitializer()){ return MethodInfo.nameClinit; } return declaringClass.getSimpleName(); } /** * Returns true if the constructor (or static initializer) * is the default one. This method returns true if the constructor * takes some arguments but it does not perform anything except * calling super() (the no-argument constructor of * the super class). */ @Override public boolean isEmpty(){ CodeAttribute ca = getMethodInfo2().getCodeAttribute(); if (ca == null){ return false; // native or abstract?? // they are not allowed, though. } ConstPool cp = ca.getConstPool(); CodeIterator it = ca.iterator(); try{ int pos, desc; int op0 = it.byteAt(it.next()); return op0 == Opcode.RETURN // empty static initializer || (op0 == Opcode.ALOAD_0 && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL && (desc = cp.isConstructor(getSuperclassName(), it.u16bitAt(pos + 1))) != 0 && "()V".equals(cp.getUtf8Info(desc)) && it.byteAt(it.next()) == Opcode.RETURN && !it.hasNext()); }catch (BadBytecode e){} return false; } private String getSuperclassName(){ ClassFile cf = declaringClass.getClassFile2(); return cf.getSuperclass(); } /** * Returns true if this constructor calls a constructor * of the super class. This method returns false if it * calls another constructor of this class by this(). */ public boolean callsSuper() throws CannotCompileException{ CodeAttribute codeAttr = methodInfo.getCodeAttribute(); if (codeAttr != null){ CodeIterator it = codeAttr.iterator(); try{ int index = it.skipSuperConstructor(); return index >= 0; }catch (BadBytecode e){ throw new CannotCompileException(e); } } return false; } /** * Sets a constructor body. * * @param src * the source code representing the constructor body. * It must be a single statement or block. * If it is null, the substituted * constructor body does nothing except calling * super(). */ @Override public void setBody(String src) throws CannotCompileException{ if (src == null){ if (isClassInitializer()){ src = ";"; }else{ src = "super();"; } } super.setBody(src); } /** * Copies a constructor body from another constructor. * *

* All occurrences of the class names in the copied body * are replaced with the names specified by * map if map is not null. * * @param src * the method that the body is copied from. * @param map * the hashtable associating original class names * with substituted names. * It can be null. */ public void setBody(CtConstructor src,ClassMap map) throws CannotCompileException{ setBody0(src.declaringClass, src.methodInfo, declaringClass, methodInfo, map); } /** * Inserts bytecode just after another constructor in the super class * or this class is called. * It does not work if this object represents a class initializer. * * @param src * the source code representing the inserted bytecode. * It must be a single statement or block. */ public void insertBeforeBody(String src) throws CannotCompileException{ CtClass cc = declaringClass; cc.checkModify(); if (isClassInitializer()){ throw new CannotCompileException("class initializer"); } CodeAttribute ca = methodInfo.getCodeAttribute(); CodeIterator iterator = ca.iterator(); Bytecode b = new Bytecode(methodInfo.getConstPool(), ca.getMaxStack(), ca.getMaxLocals()); b.setStackDepth(ca.getMaxStack()); Javac jv = new Javac(b, cc); try{ jv.recordParams(getParameterTypes(), false); jv.compileStmnt(src); ca.setMaxStack(b.getMaxStack()); ca.setMaxLocals(b.getMaxLocals()); iterator.skipConstructor(); int pos = iterator.insertEx(b.get()); iterator.insert(b.getExceptionTable(), pos); methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); }catch (NotFoundException e){ throw new CannotCompileException(e); }catch (CompileError e){ throw new CannotCompileException(e); }catch (BadBytecode e){ throw new CannotCompileException(e); } } /* * This method is called by addCatch() in CtBehavior. * super() and this() must not be in a try statement. */ @Override int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException{ CodeIterator ci = ca.iterator(); try{ ci.skipConstructor(); return ci.next(); }catch (BadBytecode e){ throw new CannotCompileException(e); } } /** * Makes a copy of this constructor and converts it into a method. * The signature of the mehtod is the same as the that of this constructor. * The return type is void. The resulting method must be * appended to the class specified by declaring. * If this constructor is a static initializer, the resulting method takes * no parameter. * *

* An occurrence of another constructor call this() * or a super constructor call super() is * eliminated from the resulting method. * *

* The immediate super class of the class declaring this constructor * must be also a super class of the class declaring the resulting method. * If the constructor accesses a field, the class declaring the resulting method * must also declare a field with the same name and type. * * @param name * the name of the resulting method. * @param declaring * the class declaring the resulting method. */ public CtMethod toMethod(String name,CtClass declaring) throws CannotCompileException{ return toMethod(name, declaring, null); } /** * Makes a copy of this constructor and converts it into a method. * The signature of the method is the same as the that of this constructor. * The return type is void. The resulting method must be * appended to the class specified by declaring. * If this constructor is a static initializer, the resulting method takes * no parameter. * *

* An occurrence of another constructor call this() * or a super constructor call super() is * eliminated from the resulting method. * *

* The immediate super class of the class declaring this constructor * must be also a super class of the class declaring the resulting method * (this is obviously true if the second parameter declaring is * the same as the class declaring this constructor). * If the constructor accesses a field, the class declaring the resulting method * must also declare a field with the same name and type. * * @param name * the name of the resulting method. * @param declaring * the class declaring the resulting method. * It is normally the same as the class declaring this * constructor. * @param map * the hash table associating original class names * with substituted names. The original class names will be * replaced while making a copy. * map can be null. */ public CtMethod toMethod(String name,CtClass declaring,ClassMap map) throws CannotCompileException{ CtMethod method = new CtMethod(null, declaring); method.copy(this, false, map); if (isConstructor()){ MethodInfo minfo = method.getMethodInfo2(); CodeAttribute ca = minfo.getCodeAttribute(); if (ca != null){ removeConsCall(ca); try{ methodInfo.rebuildStackMapIf6(declaring.getClassPool(), declaring.getClassFile2()); }catch (BadBytecode e){ throw new CannotCompileException(e); } } } method.setName(name); return method; } private static void removeConsCall(CodeAttribute ca) throws CannotCompileException{ CodeIterator iterator = ca.iterator(); try{ int pos = iterator.skipConstructor(); if (pos >= 0){ int mref = iterator.u16bitAt(pos + 1); String desc = ca.getConstPool().getMethodrefType(mref); int num = Descriptor.numOfParameters(desc) + 1; if (num > 3){ pos = iterator.insertGapAt(pos, num - 3, false).position; } iterator.writeByte(Opcode.POP, pos++); // this iterator.writeByte(Opcode.NOP, pos); iterator.writeByte(Opcode.NOP, pos + 1); Descriptor.Iterator it = new Descriptor.Iterator(desc); while (true){ it.next(); if (it.isParameter()){ iterator.writeByte(it.is2byte() ? Opcode.POP2 : Opcode.POP, pos++); }else{ break; } } } }catch (BadBytecode e){ throw new CannotCompileException(e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy