/* * Copyright 2016, Stuart Douglas, and individual contributors as indicated * by the @authors tag. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fakereplace.data; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import javassist.bytecode.AccessFlag; import org.fakereplace.util.DescriptorUtils; /** * Class that holds information about a method. * * @author stuart */ public class MethodData { private final String methodName; private final String descriptor; /** * contains the argument portion of the descriptor minus the return type */ private final String argumentDescriptor; /** * the return type of the method * final */ private final String returnTypeDescriptor; private final MemberType type; private final int accessFlags; /** * stores the method no for a fake method. This is only used for constructors */ private final int methodNo; /** * The actual class that the method resides in java not internal format */ private final String className; private final boolean finalMethod; public MethodData(String name, String descriptor, String className, MemberType type, int accessFlags, boolean finalMethod) { this.methodName = name; this.descriptor = descriptor; this.returnTypeDescriptor = DescriptorUtils.getReturnType(descriptor); this.argumentDescriptor = DescriptorUtils.getArgumentString(descriptor); this.className = className; this.type = type; this.accessFlags = accessFlags; this.methodNo = 0; this.finalMethod = finalMethod; } public MethodData(String name, String descriptor, String className, MemberType type, int accessFlags, int methodNo) { this.methodName = name; this.descriptor = descriptor; this.returnTypeDescriptor = DescriptorUtils.getReturnType(descriptor); this.argumentDescriptor = DescriptorUtils.getArgumentString(descriptor); this.className = className; this.type = type; this.accessFlags = accessFlags; this.methodNo = methodNo; this.finalMethod = false; } /** * MethodData's are equal if they refer to the same method */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj instanceof MethodData) { MethodData m = (MethodData) obj; if (m.className.equals(className)) { if (m.methodName.equals(methodName)) { if (m.descriptor.equals(descriptor)) { return true; } } } } return false; } @Override public int hashCode() { return (className + methodName + descriptor).hashCode(); } public String getClassName() { return className; } public int getAccessFlags() { return accessFlags; } public String getMethodName() { return methodName; } public String getDescriptor() { return descriptor; } public MemberType getType() { return type; } public boolean isStatic() { return (accessFlags & AccessFlag.STATIC) != 0; } public String getArgumentDescriptor() { return argumentDescriptor; } public Method getMethod(Class<?> actualClass) throws ClassNotFoundException, SecurityException, NoSuchMethodException { Class<?>[] methodDesc = DescriptorUtils.argumentStringToClassArray(descriptor, actualClass); Method method = actualClass.getDeclaredMethod(methodName, methodDesc); return method; } public Method getMethodToInvoke(Class<?> actualClass) throws ClassNotFoundException, SecurityException, NoSuchMethodException { Class<?>[] methodDesc; if (type == MemberType.FAKE && !isStatic()) { methodDesc = DescriptorUtils.argumentStringToClassArray(descriptor, actualClass); Class<?>[] ret = new Class<?>[methodDesc.length + 1]; ret[0] = ClassDataStore.instance().getRealClassFromProxyName(actualClass.getName()); for (int i = 0; i < methodDesc.length; ++i) { ret[i + 1] = methodDesc[i]; } methodDesc = ret; } else { methodDesc = DescriptorUtils.argumentStringToClassArray(descriptor, actualClass); } Method method = actualClass.getDeclaredMethod(methodName, methodDesc); return method; } /** * If this method is actually a constructor get the construtor object */ public Constructor<?> getConstructor(Class<?> actualClass) throws ClassNotFoundException, SecurityException, NoSuchMethodException { Class<?>[] methodDesc = DescriptorUtils.argumentStringToClassArray(descriptor, actualClass); Constructor<?> method = actualClass.getDeclaredConstructor(methodDesc); return method; } public int getMethodNo() { return methodNo; } public String getReturnTypeDescriptor() { return returnTypeDescriptor; } public boolean isFinalMethod() { return finalMethod; } public boolean isConstructor() { return methodName.equals("<init>"); } }