17ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu/** 27ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * Copyright (c) 2004-2011 QOS.ch 37ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * All rights reserved. 47ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * 57ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * Permission is hereby granted, free of charge, to any person obtaining 67ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * a copy of this software and associated documentation files (the 77ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * "Software"), to deal in the Software without restriction, including 87ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * without limitation the rights to use, copy, modify, merge, publish, 97ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * distribute, sublicense, and/or sell copies of the Software, and to 107ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * permit persons to whom the Software is furnished to do so, subject to 117ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * the following conditions: 127ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * 137ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * The above copyright notice and this permission notice shall be 147ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * included in all copies or substantial portions of the Software. 157ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * 167ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 177ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 187ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 197ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 207ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 217ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 227ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 237ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * 247ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu */ 2516764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenpackage org.slf4j.instrumentation; 2616764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersen 2716764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.CtBehavior; 2816764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.CtClass; 2916764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.CtMethod; 3016764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.Modifier; 3116764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.NotFoundException; 32231046d8abf52f4b7f7a69d037bbc0a58dbe07cbThorbjorn Ravn Andersenimport javassist.bytecode.AttributeInfo; 3316764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.bytecode.CodeAttribute; 3416764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenimport javassist.bytecode.LocalVariableAttribute; 3516764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersen 366d8325a0c52b9f04a76085c748beddc306027d18Thorbjorn Ravn Andersen/** 376d8325a0c52b9f04a76085c748beddc306027d18Thorbjorn Ravn Andersen * Helper methods for Javassist functionality. 3842d254db97a8103ede6461d8d16303cbd037ccd5Thorbjorn Ravn Andersen * 396d8325a0c52b9f04a76085c748beddc306027d18Thorbjorn Ravn Andersen */ 4016764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersenpublic class JavassistHelper { 4116764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersen 4231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu /** 4331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * Create a javaassist source snippet which either is empty (for anything 4431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * which does not return a value) or a explanatory text around the $_ 4531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * javaassist return value variable. 4631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * 4731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @param method 4831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * descriptor of method 4931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @return source snippet 5031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @throws NotFoundException 5131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu */ 5231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu public static String returnValue(CtBehavior method) throws NotFoundException { 5331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 5431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu String returnValue = ""; 5531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (methodReturnsValue(method)) { 5631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu returnValue = " returns: \" + $_ + \"."; 5731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 5831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu return returnValue; 5931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 6031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 6131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu /** 6231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * determine if the given method returns a value, and return true if so. 6331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * false otherwise. 6431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * 6531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @param method 6631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @return 6731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @throws NotFoundException 6831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu */ 6931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu private static boolean methodReturnsValue(CtBehavior method) throws NotFoundException { 7031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 7131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (method instanceof CtMethod == false) { 7231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu return false; 7331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 7431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 7531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu CtClass returnType = ((CtMethod) method).getReturnType(); 7631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu String returnTypeName = returnType.getName(); 7731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 7831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu boolean isVoidMethod = "void".equals(returnTypeName); 7931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 8031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu boolean methodReturnsValue = isVoidMethod == false; 8131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu return methodReturnsValue; 8231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 8331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 8431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu /** 8531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * Return javaassist source snippet which lists all the parameters and their 8631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * values. If available the source names are extracted from the debug 8731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * information and used, otherwise just a number is shown. 8831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * 8931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @param method 9031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @return 9131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @throws NotFoundException 9231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu */ 9331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu public static String getSignature(CtBehavior method) throws NotFoundException { 9431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 9531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu CtClass parameterTypes[] = method.getParameterTypes(); 9631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 9731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute(); 9831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 9931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu LocalVariableAttribute locals = null; 10031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 10131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (codeAttribute != null) { 10231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu AttributeInfo attribute; 10331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu attribute = codeAttribute.getAttribute("LocalVariableTable"); 10431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu locals = (LocalVariableAttribute) attribute; 10531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 10631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 10731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu String methodName = method.getName(); 10831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 10931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu StringBuilder sb = new StringBuilder(methodName).append("(\" "); 11031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu for (int i = 0; i < parameterTypes.length; i++) { 11131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (i > 0) { 11231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // add a comma and a space between printed values 11331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append(" + \", \" "); 11431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 11531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 11631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu CtClass parameterType = parameterTypes[i]; 11731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu boolean isArray = parameterType.isArray(); 11831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu CtClass arrayType = parameterType.getComponentType(); 11931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (isArray) { 12031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu while (arrayType.isArray()) { 12131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu arrayType = arrayType.getComponentType(); 12231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 12331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 12431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 12531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append(" + \""); 12631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu try { 12731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append(parameterNameFor(method, locals, i)); 12831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } catch (Exception e) { 12931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append(i + 1); 13031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 13131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append("\" + \"="); 13231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 13331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (parameterType.isPrimitive()) { 13431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // let the compiler handle primitive -> string 13531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append("\"+ $").append(i + 1); 13631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } else { 13731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu String s = "org.slf4j.instrumentation.ToStringHelper.render"; 13831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append("\"+ ").append(s).append("($").append(i + 1).append(')'); 13931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 14031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 14131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu sb.append("+\")"); 14231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 14331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu String signature = sb.toString(); 14431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu return signature; 14531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 14631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 14731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu /** 14831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * Determine the name of parameter with index i in the given method. Use the 14931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * locals attributes about local variables from the classfile. Note: This is 15031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * still work in progress. 15131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * 15231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @param method 15331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @param locals 15431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @param i 15531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu * @return the name of the parameter if available or a number if not. 15631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu */ 15731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu static String parameterNameFor(CtBehavior method, LocalVariableAttribute locals, int i) { 15831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 15931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (locals == null) { 16031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu return Integer.toString(i + 1); 16131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 16231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 16331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu int modifiers = method.getModifiers(); 16431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 16531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu int j = i; 16631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu 16731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (Modifier.isSynchronized(modifiers)) { 16831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // skip object to synchronize upon. 16931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu j++; 17031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // System.err.println("Synchronized"); 17131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 17231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu if (Modifier.isStatic(modifiers) == false) { 17331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // skip "this" 17431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu j++; 17531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // System.err.println("Instance"); 17631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 17731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu String variableName = locals.variableName(j); 17831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // if (variableName.equals("this")) { 17931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // System.err.println("'this' returned as a parameter name for " 18031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // + method.getName() + " index " + j 18131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // + 18231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // ", names are probably shifted. Please submit source for class in slf4j bugreport"); 18331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu // } 18431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu return variableName; 18531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu } 18616764e712db81772de71ba3f7932b01fbbe2eec3Thorbjorn Ravn Andersen} 187