JavassistHelper xref

View Javadoc

    1   /**
    2    * Copyright (c) 2004-2011 QOS.ch
    3    * All rights reserved.
    4    *
    5    * Permission is hereby granted, free  of charge, to any person obtaining
    6    * a  copy  of this  software  and  associated  documentation files  (the
    7    * "Software"), to  deal in  the Software without  restriction, including
    8    * without limitation  the rights to  use, copy, modify,  merge, publish,
    9    * distribute,  sublicense, and/or sell  copies of  the Software,  and to
    10   * permit persons to whom the Software  is furnished to do so, subject to
    11   * the following conditions:
    12   *
    13   * The  above  copyright  notice  and  this permission  notice  shall  be
    14   * included in all copies or substantial portions of the Software.
    15   *
    16   * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
    17   * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
    18   * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
    19   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    20   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    21   * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
    22   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    23   *
    24   */
    25  package org.slf4j.instrumentation;
    26
    27  import javassist.CtBehavior;
    28  import javassist.CtClass;
    29  import javassist.CtMethod;
    30  import javassist.Modifier;
    31  import javassist.NotFoundException;
    32  import javassist.bytecode.AttributeInfo;
    33  import javassist.bytecode.CodeAttribute;
    34  import javassist.bytecode.LocalVariableAttribute;
    35
    36  /**
    37   * Helper methods for Javassist functionality.
    38   *
    39   */
    40  public class JavassistHelper {
    41
    42  	/**
    43  	 * Create a javaassist source snippet which either is empty (for anything
    44  	 * which does not return a value) or a explanatory text around the $_
    45  	 * javaassist return value variable.
    46  	 *
    47  	 * @param method
    48  	 *            descriptor of method
    49  	 * @return source snippet
    50  	 * @throws NotFoundException
    51  	 */
    52  	public static String returnValue(CtBehavior method)
    53  			throws NotFoundException {
    54
    55  		String returnValue = "";
    56  		if (methodReturnsValue(method)) {
    57  			returnValue = " returns: \" + $_ + \".";
    58  		}
    59  		return returnValue;
    60  	}
    61
    62  	/**
    63  	 * determine if the given method returns a value, and return true if so.
    64  	 * false otherwise.
    65  	 *
    66  	 * @param method
    67  	 * @return
    68  	 * @throws NotFoundException
    69  	 */
    70  	private static boolean methodReturnsValue(CtBehavior method)
    71  			throws NotFoundException {
    72
    73  		if (method instanceof CtMethod == false) {
    74  			return false;
    75  		}
    76
    77  		CtClass returnType = ((CtMethod) method).getReturnType();
    78  		String returnTypeName = returnType.getName();
    79
    80  		boolean isVoidMethod = "void".equals(returnTypeName);
    81
    82  		boolean methodReturnsValue = isVoidMethod == false;
    83  		return methodReturnsValue;
    84  	}
    85
    86  	/**
    87  	 * Return javaassist source snippet which lists all the parameters and their
    88  	 * values. If available the source names are extracted from the debug
    89  	 * information and used, otherwise just a number is shown.
    90  	 *
    91  	 * @param method
    92  	 * @return
    93  	 * @throws NotFoundException
    94  	 */
    95  	public static String getSignature(CtBehavior method)
    96  			throws NotFoundException {
    97
    98  		CtClass parameterTypes[] = method.getParameterTypes();
    99
    100 		CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute();
    101
    102 		LocalVariableAttribute locals = null;
    103
    104 		if (codeAttribute != null) {
    105 			AttributeInfo attribute;
    106 			attribute = codeAttribute.getAttribute("LocalVariableTable");
    107 			locals = (LocalVariableAttribute) attribute;
    108 		}
    109
    110 		String methodName = method.getName();
    111
    112 		StringBuffer sb = new StringBuffer(methodName + "(\" ");
    113 		for (int i = 0; i < parameterTypes.length; i++) {
    114 			if (i > 0) {
    115 				// add a comma and a space between printed values
    116 				sb.append(" + \", \" ");
    117 			}
    118
    119 			CtClass parameterType = parameterTypes[i];
    120 			boolean isArray = parameterType.isArray();
    121 			CtClass arrayType = parameterType.getComponentType();
    122 			if (isArray) {
    123 				while (arrayType.isArray()) {
    124 					arrayType = arrayType.getComponentType();
    125 				}
    126 			}
    127
    128 			sb.append(" + \"");
    129 			try {
    130 				sb.append(parameterNameFor(method, locals, i));
    131 			} catch (Exception e) {
    132 				sb.append("" + (i + 1));
    133 			}
    134 			sb.append("\" + \"=");
    135
    136 			if (parameterType.isPrimitive()) {
    137 				// let the compiler handle primitive -> string
    138 				sb.append("\"+ $" + (i + 1));
    139 			} else {
    140 				String s = "org.slf4j.instrumentation.ToStringHelper.render";
    141 				sb.append("\"+ " + s + "($" + (i + 1) + ")");
    142 			}
    143 		}
    144 		sb.append("+\")");
    145
    146 		String signature = sb.toString();
    147 		return signature;
    148 	}
    149
    150 	/**
    151 	 * Determine the name of parameter with index i in the given method. Use the
    152 	 * locals attributes about local variables from the classfile. Note: This is
    153 	 * still work in progress.
    154 	 *
    155 	 * @param method
    156 	 * @param locals
    157 	 * @param i
    158 	 * @return the name of the parameter if available or a number if not.
    159 	 */
    160 	static String parameterNameFor(CtBehavior method,
    161 			LocalVariableAttribute locals, int i) {
    162
    163 		if (locals == null) {
    164 			return Integer.toString(i + 1);
    165 		}
    166
    167 		int modifiers = method.getModifiers();
    168
    169 		int j = i;
    170
    171 		if (Modifier.isSynchronized(modifiers)) {
    172 			// skip object to synchronize upon.
    173 			j++;
    174 			// System.err.println("Synchronized");
    175 		}
    176 		if (Modifier.isStatic(modifiers) == false) {
    177 			// skip "this"
    178 			j++;
    179 			// System.err.println("Instance");
    180 		}
    181 		String variableName = locals.variableName(j);
    182 		// if (variableName.equals("this")) {
    183 		// System.err.println("'this' returned as a parameter name for "
    184 		// + method.getName() + " index " + j
    185 		// +
    186 		// ", names are probably shifted. Please submit source for class in slf4j bugreport");
    187 		// }
    188 		return variableName;
    189 	}
    190 }