/* * 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. * * MODIFIED BY James Nelson of We The Internet, 2013. * Repackaged to avoid conflicts with different versions of Javassist, * and modified Javassist APIs to make them more accessible to outside code. */ package xapi.bytecode; import xapi.source.X_Modifier; public final class CtMethod extends CtBehavior { protected String cachedStringRep; /** * @see #make(MethodInfo minfo, CtClass declaring) */ CtMethod(MethodInfo minfo, CtClass declaring) { super(declaring, minfo); cachedStringRep = null; } /** * Creates a public abstract method. The created method must be * added to a class with <code>CtClass.addMethod()</code>. * * @param declaring the class to which the created method is added. * @param returnType the type of the returned value * @param mname the method name * @param parameters a list of the parameter types * * @see CtClass#addMethod(CtMethod) */ public CtMethod(CtClass returnType, String mname, CtClass[] parameters, CtClass declaring) { this(null, declaring); ConstPool cp = declaring.getClassFile2().getConstPool(); String desc = Descriptor.ofMethod(returnType, parameters); methodInfo = new MethodInfo(cp, mname, desc); setModifiers(X_Modifier.PUBLIC | X_Modifier.ABSTRACT); } // /** // * Creates a copy of a <code>CtMethod</code> object. // * The created method must be // * added to a class with <code>CtClass.addMethod()</code>. // * // * <p>All occurrences of class names in the created method // * are replaced with names specified by // * <code>map</code> if <code>map</code> is not <code>null</code>. // * // * <p>For example, suppose that a method <code>at()</code> is as // * follows: // * // * <ul><pre>public X at(int i) { // * return (X)super.elementAt(i); // * }</pre></ul> // * // * <p>(<code>X</code> is a class name.) If <code>map</code> substitutes // * <code>String</code> for <code>X</code>, then the created method is: // * // * <ul><pre>public String at(int i) { // * return (String)super.elementAt(i); // * }</pre></ul> // * // * <p>By default, all the occurrences of the names of the class // * declaring <code>at()</code> and the superclass are replaced // * with the name of the class and the superclass that the // * created method is added to. // * This is done whichever <code>map</code> is null or not. // * To prevent this replacement, call <code>ClassMap.fix()</code> // * or <code>put()</code> to explicitly specify replacement. // * // * <p><b>Note:</b> if the <code>.class</code> notation (for example, // * <code>String.class</code>) 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 <code>Class.forName()</code> 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 <code>null</code>. // * // * @see CtClass#addMethod(CtMethod) // * @see ClassMap#fix(String) // */ // public CtMethod(CtMethod src, CtClass declaring, ClassMap map) // throws CannotCompileException // { // this(null, declaring); // copy(src, false, map); // } // // /** // * Compiles the given source code and creates a method. // * This method simply delegates to <code>make()</code> in // * <code>CtNewMethod</code>. See it for more details. // * <code>CtNewMethod</code> has a number of useful factory methods. // * // * @param src the source text. // * @param declaring the class to which the created method is added. // * @see CtNewMethod#make(String, CtClass) // */ // public static CtMethod make(String src, CtClass declaring) // throws CannotCompileException // { // return CtNewMethod.make(src, declaring); // } /** * Creates a method from a <code>MethodInfo</code> object. * * @param declaring the class declaring the method. * @throws CannotCompileException if the the <code>MethodInfo</code> * object and the declaring class have different * <code>ConstPool</code> objects * @since 3.6 */ public static CtMethod make(MethodInfo minfo, CtClass declaring) throws CannotCompileException { if (declaring.getClassFile2().getConstPool() != minfo.getConstPool()) { throw new CannotCompileException("bad declaring class"); } return new CtMethod(minfo, declaring); } /** * Returns a hash code value for the method. * If two methods have the same name and signature, then * the hash codes for the two methods are equal. */ @Override public int hashCode() { return getStringRep().hashCode(); } /** * This method is invoked when setName() or replaceClassName() * in CtClass is called. */ @Override void nameReplaced() { cachedStringRep = null; } /* This method is also called by CtClassType.getMethods0(). */ final String getStringRep() { if (cachedStringRep == null) { cachedStringRep = methodInfo.getName() + Descriptor.getParamDescriptor(methodInfo.getDescriptor()); } return cachedStringRep; } /** * Indicates whether <code>obj</code> has the same name and the * same signature as this method. */ @Override public boolean equals(Object obj) { return obj != null && obj instanceof CtMethod && ((CtMethod)obj).getStringRep().equals(getStringRep()); } /** * Returns the method name followed by parameter types * such as <code>javassist.CtMethod.setBody(String)</code>. * * @since 3.5 */ @Override public String getLongName() { return getDeclaringClass().getName() + "." + getName() + Descriptor.toString(getSignature()); } /** * Obtains the name of this method. */ @Override public String getName() { return methodInfo.getName(); } /** * Changes the name of this method. */ public void setName(String newname) { declaringClass.checkModify(); methodInfo.setName(newname); } /** * Obtains the type of the returned value. */ public CtClass getReturnType() throws NotFoundException { return getReturnType0(); } /** * Returns true if the method body is empty, that is, <code>{}</code>. * It also returns true if the method is an abstract method. */ @Override public boolean isEmpty() { return true; } public static class ConstParameter { /** * Makes an integer constant. * * @param i the constant value. */ public static ConstParameter integer(int i) { return new IntConstParameter(i); } /** * Makes a long integer constant. * * @param i the constant value. */ public static ConstParameter integer(long i) { return new LongConstParameter(i); } /** * Makes an <code>String</code> constant. * * @param s the constant value. */ public static ConstParameter string(String s) { return new StringConstParameter(s); } ConstParameter() {} /** * @return the size of the stack consumption. * @throws CannotCompileException */ int compile(Bytecode code) throws CannotCompileException { return 0; } String descriptor() { return defaultDescriptor(); } /** * @see CtNewWrappedMethod */ static String defaultDescriptor() { return "([Ljava/lang/Object;)Ljava/lang/Object;"; } /** * Returns the descriptor for constructors. * * @see CtNewWrappedConstructor */ String constDescriptor() { return defaultConstDescriptor(); } /** * Returns the default descriptor for constructors. */ static String defaultConstDescriptor() { return "([Ljava/lang/Object;)V"; } } static class IntConstParameter extends ConstParameter { int param; IntConstParameter(int i) { param = i; } @Override int compile(Bytecode code) throws CannotCompileException { code.addIconst(param); return 1; } @Override String descriptor() { return "([Ljava/lang/Object;I)Ljava/lang/Object;"; } @Override String constDescriptor() { return "([Ljava/lang/Object;I)V"; } } static class LongConstParameter extends ConstParameter { long param; LongConstParameter(long l) { param = l; } @Override int compile(Bytecode code) throws CannotCompileException { code.addLconst(param); return 2; } @Override String descriptor() { return "([Ljava/lang/Object;J)Ljava/lang/Object;"; } @Override String constDescriptor() { return "([Ljava/lang/Object;J)V"; } } static class StringConstParameter extends ConstParameter { String param; StringConstParameter(String s) { param = s; } @Override int compile(Bytecode code) throws CannotCompileException { code.addLdc(param); return 1; } @Override String descriptor() { return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;"; } @Override String constDescriptor() { return "([Ljava/lang/Object;Ljava/lang/String;)V"; } } }