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

jodd.proxetta.asm.MethodSignatureVisitor Maven / Gradle / Ivy

Go to download

Jodd Proxetta is the fastest proxy creator with unique approach for defying pointcuts and advices.

The newest version!
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package jodd.proxetta.asm;

import jodd.asm.AsmUtil;
import jodd.asm.TraceSignatureVisitor;
import jodd.asm9.Opcodes;
import jodd.asm9.signature.SignatureVisitor;
import jodd.proxetta.AnnotationInfo;
import jodd.proxetta.ClassInfo;
import jodd.proxetta.GenericsReader;
import jodd.proxetta.MethodInfo;
import jodd.proxetta.ProxettaException;
import jodd.proxetta.TypeInfo;
import jodd.util.StringPool;
import jodd.util.StringUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static jodd.proxetta.asm.AnnotationReader.NO_ANNOTATIONS;

/**
 * Resolves method signature and holds all information. Uses {@link jodd.asm.TraceSignatureVisitor} from ASM library.
 * 
 * MethodSignature = ( visitFormalTypeParameter visitClassBound? visitInterfaceBound* )* ( visitParameterType* visitReturnType visitExceptionType* )
 * 
*/ public class MethodSignatureVisitor extends TraceSignatureVisitor implements MethodInfo { protected final String classname; protected final String methodName; protected final String[] exceptionsArray; protected final boolean isStatic; protected final boolean isFinal; protected final ClassInfo targetClassInfo; protected final List argumentsOffset; protected final List arguments; protected final int access; protected final String description; protected TypeInfo returnType; protected String signature; protected int argumentsCount; protected int argumentsWords; protected String asmMethodSignature; protected AnnotationInfo[] annotations; protected String declaredClassName; protected final Map generics; protected final Map declaredTypeGeneric; // ---------------------------------------------------------------- ctors public MethodSignatureVisitor( final String methodName, final int access, final String classname, String description, final String[] exceptions, String signature, final Map declaredTypeGenerics, final ClassInfo targetClassInfo) { super(new StringBuilder(), (access & Opcodes.ACC_INTERFACE) != 0); if (signature != null && signature.startsWith("(") && !declaredTypeGenerics.isEmpty()) { // special case when we can replace the signature // as generic types are defined in declaration in superclass // e.g.: Foo extends Bar String newSignature = signature; for (Map.Entry entry : declaredTypeGenerics.entrySet()) { newSignature = StringUtil.replace(newSignature, "T" + entry.getKey() + ";", entry.getValue()); } description = AsmUtil.removeGenericsFromSignature(newSignature); signature = null; } // this.isInterface = (access & Opcodes.ACC_INTERFACE) != 0; this.isStatic = (access & Opcodes.ACC_STATIC) != 0; this.isFinal = (access & Opcodes.ACC_FINAL) != 0; this.methodName = methodName; this.access = access; this.classname = classname; this.description = description; this.targetClassInfo = targetClassInfo; this.asmMethodSignature = signature; this.generics = new GenericsReader().parseSignatureForGenerics(signature, isInterface); this.exceptionsArray = exceptions; this.declaredTypeGeneric = declaredTypeGenerics; this.arguments = new ArrayList<>(); this.arguments.add(new TypeInfoImpl('L', null, null, null)); this.argumentsOffset = new ArrayList<>(); this.argumentsOffset.add(0); this.annotations = NO_ANNOTATIONS; } // ---------------------------------------------------------------- method-info signature @Override public String getSignature() { if (signature == null) { String decl = getDeclaration(); int ndx = decl.indexOf(')'); ndx++; String retType = decl.substring(ndx); StringBuilder methodDeclaration = new StringBuilder(50); methodDeclaration.append(retType).append(' ').append(methodName).append(decl, 0, ndx); String exceptionsAsString = getExceptionsAsString(); if (exceptionsAsString != null) { methodDeclaration.append(" throws ").append(exceptionsAsString); } signature = methodDeclaration.toString(); } return signature; } @Override public String getCleanSignature() { return methodName + '#' + getDescription(); } public String getAsmMethodSignature() { return asmMethodSignature; } @Override public String getMethodName() { return methodName; } @Override public int getArgumentsCount() { return argumentsCount; } @Override public TypeInfoImpl getArgument(final int ndx) { return arguments.get(ndx); } @Override public int getArgumentOffset(final int index) { return argumentsOffset.get(index); } @Override public int getAllArgumentsSize() { return argumentsWords; } @Override public TypeInfo getReturnType() { return returnType; } @Override public int getAccessFlags() { return access; } @Override public String getClassname() { return classname; } @Override public String getDescription() { return description; } @Override public AnnotationInfo[] getAnnotations() { return annotations; } @Override public String getDeclaredClassName() { if (declaredClassName == null) { return classname; } return declaredClassName; } public void setDeclaredClassName(final String declaredClassName) { this.declaredClassName = declaredClassName; } @Override public boolean isTopLevelMethod() { return declaredClassName == null; } @Override public ClassInfo getClassInfo() { return targetClassInfo; } @Override public String[] getExceptions() { return exceptionsArray; } // ---------------------------------------------------------------- type private boolean visitingArgument; private boolean visitingReturnType; private boolean visitingArray; private int declarationTypeOffset; @Override public SignatureVisitor visitParameterType() { super.visitParameterType(); visitingArgument = true; return this; } @Override public SignatureVisitor visitReturnType() { super.visitReturnType(); visitingReturnType = true; return this; } @Override public SignatureVisitor visitArrayType() { visitingArray = true; return super.visitArrayType(); } @Override public void visitBaseType(final char descriptor) { if (isTopLevelType()) { // mark type start declarationTypeOffset = declaration.length(); } super.visitBaseType(descriptor); } @Override public void visitClassType(final String name) { if (isTopLevelType()) { // mark type start declarationTypeOffset = declaration.length(); } super.visitClassType(name); } @Override protected void startType() { super.startType(); if (isTopLevelType()) { // mark type start declarationTypeOffset = declaration.length(); } } @Override protected void endType() { super.endType(); String type = declaration.subSequence(declarationTypeOffset, declaration.length()).toString(); maybeUseType(type); } private void maybeUseType(final String typeInput) { if (!isTopLevelType()) { return; } final String typeName = AsmUtil.removeGenericsFromSignature(typeInput); if (visitingArray) { // since generics are removed, review the array situation int arrayCount = StringUtil.count(typeName, '['); if (arrayCount == 0) { // there were only generic arrays visitingArray = false; } } char type; String bytecodeName; if (visitingArray) { type = '['; int arrayCount = StringUtil.count(typeName, '['); String arrayDepth = StringUtil.repeat('[', arrayCount); int ndx = typeName.indexOf('['); bytecodeName = typeName.substring(0, ndx); char arrayType = AsmUtil.typeNameToOpcode(bytecodeName); if (arrayType != 'L') { bytecodeName = String.valueOf(arrayType); } else { bytecodeName = resolveBytecodeName(bytecodeName); } bytecodeName = arrayDepth + bytecodeName; } else { type = AsmUtil.typeNameToOpcode(typeName); if (type != 'L') { bytecodeName = String.valueOf(type); } else { bytecodeName = resolveBytecodeName(typeName); } } final TypeInfoImpl typeInfo = new TypeInfoImpl( type, typeInput, bytecodeName, resolveRawTypeName(bytecodeName)); if (visitingArgument) { if (type == 'V') { throw new ProxettaException("Method argument can't be void"); } arguments.add(typeInfo); argumentsCount++; argumentsOffset.add(argumentsWords + 1); if ((type == 'D') || (type == 'J')) { argumentsWords += 2; } else { argumentsWords++; } } else if (visitingReturnType) { returnType = typeInfo; } visitingReturnType = false; visitingArgument = false; visitingArray = false; } /** * Returns {@code true} if we are scanning the top-level type and not * the inner ones, like generics. */ private boolean isTopLevelType() { return argumentStack == 0; } private String resolveBytecodeName(String typeName) { int ndx = 0; int genericsStartNdx = -1; int bracketCount = 0; while (ndx < typeName.length()) { final char c = typeName.charAt(ndx); if (c == '<') { if (bracketCount == 0) { genericsStartNdx = ndx; } bracketCount++; ndx++; continue; } if (c == '>') { bracketCount--; if (bracketCount == 0) { break; } } ndx++; } if (genericsStartNdx != -1) { typeName = typeName.substring(0, genericsStartNdx) + typeName.substring(ndx + 1); } if (isGenericType(typeName)) { return typeName; } return 'L' + typeName.replace('.', '/') + ';'; } /** * Resolves raw type name using the generics information from the class * or method information. */ private String resolveRawTypeName(String typeName) { if (typeName == null) { return null; } boolean isArray = typeName.startsWith(StringPool.LEFT_SQ_BRACKET); if (isArray) { typeName = typeName.substring(1); } String rawTypeName; if (generics.containsKey(typeName)) { rawTypeName = generics.get(typeName); } else { rawTypeName = declaredTypeGeneric.getOrDefault(typeName, typeName); } if (isArray) { rawTypeName = '[' + rawTypeName; } return rawTypeName; } private boolean isGenericType(final String typeName) { if (generics.containsKey(typeName)) { return true; } return declaredTypeGeneric.containsKey(typeName); } // ---------------------------------------------------------------- toString @Override public String toString() { return getDeclaredClassName() + '#' + getMethodName() + getDescription(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy