![JAR search and dependency download from the Maven repository](/logo.png)
com.github.netty.core.util.ParameterNameDiscoverer Maven / Gradle / Ivy
//package com.github.netty.core.util;
//
//import org.objectweb.asm.*;
//
//import java.io.IOException;
//import java.io.InputStream;
//import java.lang.reflect.Constructor;
//import java.lang.reflect.Member;
//import java.lang.reflect.Method;
//import java.lang.reflect.Modifier;
//import java.util.*;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.function.Consumer;
//import java.util.function.Function;
//
///**
// * Based on ASM parameter name resolution
// * @author wangzihao
// */
//public class ParameterNameDiscoverer {
// private LoggerX logger = LoggerFactoryX.getLogger(getClass());
//
// static final int ASM_VERSION = Opcodes.ASM7;
//
// // marker object for classes that do not have any debug info
// private static final Map NO_DEBUG_INFO_MAP = Collections.emptyMap();
// private static final Map, Method[]> DECLARED_METHODS_CACHE = new ConcurrentReferenceHashMap<>(256);
// private static final Method[] NO_METHODS = {};
//
// // the cache uses a nested index (value is a map) to keep the top level cache relatively small in size
// private final Map, Map> parameterNamesCache = new ConcurrentHashMap<>(32);
//
// public String[] getParameterNames(Method method) {
// Method originalMethod = findBridgedMethod(method);
// Class> declaringClass = originalMethod.getDeclaringClass();
// Map map = this.parameterNamesCache.get(declaringClass);
// if (map == null) {
// map = inspectClass(declaringClass);
// this.parameterNamesCache.put(declaringClass, map);
// }
// if (map != NO_DEBUG_INFO_MAP) {
// return map.get(originalMethod);
// }
// return null;
// }
//
// public String[] getParameterNames(Constructor> ctor) {
// Class> declaringClass = ctor.getDeclaringClass();
// Map map = this.parameterNamesCache.get(declaringClass);
// if (map == null) {
// map = inspectClass(declaringClass);
// this.parameterNamesCache.put(declaringClass, map);
// }
// if (map != NO_DEBUG_INFO_MAP) {
// return map.get(ctor);
// }
// return null;
// }
//
//
// /**
// * Inspects the target class. Exceptions will be logged and a maker map returned
// * to indicate the lack of debug information.
// * @param clazz clazz
// * @return parameter name mapping
// */
// public Map inspectClass(Class> clazz) {
// InputStream is = clazz.getResourceAsStream(ReflectUtil.getClassFileName(clazz));
// if (is == null) {
// // We couldn't load the class file, which is not fatal as it
// // simply means this method of discovering parameter names won't work.
// if (logger.isDebugEnabled()) {
// logger.debug("Cannot find '.class' file for class [" + clazz +
// "] - unable to determine constructor/method parameter names");
// }
// return NO_DEBUG_INFO_MAP;
// }
// try {
// ClassReader classReader = new ClassReader(is);
// Map map = new ConcurrentHashMap<>(32);
// classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
// return map;
// }
// catch (IOException ex) {
// if (logger.isDebugEnabled()) {
// logger.debug("Exception thrown while reading '.class' file for class [" + clazz +
// "] - unable to determine constructor/method parameter names", ex);
// }
// }
// catch (IllegalArgumentException ex) {
// if (logger.isDebugEnabled()) {
// logger.debug("ASM ClassReader failed to parse class file [" + clazz +
// "], probably due to a new Java class file version that isn't supported yet " +
// "- unable to determine constructor/method parameter names", ex);
// }
// }
// finally {
// try {
// is.close();
// }
// catch (IOException ex) {
// // ignore
// }
// }
// return NO_DEBUG_INFO_MAP;
// }
//
// /**
// * Helper class that inspects all methods (constructor included) and then
// * attempts to find the parameter names for that member.
// */
// private static class ParameterNameDiscoveringVisitor extends ClassVisitor {
//
// private static final String STATIC_CLASS_INIT = "";
//
// private final Class> clazz;
//
// private final Map memberMap;
//
// public ParameterNameDiscoveringVisitor(Class> clazz, Map memberMap) {
// super(ASM_VERSION);
// this.clazz = clazz;
// this.memberMap = memberMap;
// }
//
// @Override
// public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// // exclude synthetic + bridged && static class initialization
// if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {
// return new LocalVariableTableVisitor(this.clazz, this.memberMap, name, desc, isStatic(access));
// }
// return null;
// }
//
// private static boolean isSyntheticOrBridged(int access) {
// return (((access & Opcodes.ACC_SYNTHETIC) | (access & Opcodes.ACC_BRIDGE)) > 0);
// }
//
// private static boolean isStatic(int access) {
// return ((access & Opcodes.ACC_STATIC) > 0);
// }
// }
//
//
// private static class LocalVariableTableVisitor extends MethodVisitor {
//
// private static final String CONSTRUCTOR = "";
//
// private final Class> clazz;
//
// private final Map memberMap;
//
// private final String name;
//
// private final Type[] args;
//
// private final String[] parameterNames;
//
// private final boolean isStatic;
//
// private boolean hasLvtInfo = false;
//
// /*
// * The nth entry contains the slot index of the LVT table entry holding the
// * argument name for the nth parameter.
// */
// private final int[] lvtSlotIndex;
//
// public LocalVariableTableVisitor(Class> clazz, Map map, String name, String desc, boolean isStatic) {
// super(ASM_VERSION);
// this.clazz = clazz;
// this.memberMap = map;
// this.name = name;
// this.args = Type.getArgumentTypes(desc);
// this.parameterNames = new String[this.args.length];
// this.isStatic = isStatic;
// this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args);
// }
//
// @Override
// public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
// this.hasLvtInfo = true;
// for (int i = 0; i < this.lvtSlotIndex.length; i++) {
// if (this.lvtSlotIndex[i] == index) {
// this.parameterNames[i] = name;
// }
// }
// }
//
// @Override
// public void visitEnd() {
// if (this.hasLvtInfo || (this.isStatic && this.parameterNames.length == 0)) {
// // visitLocalVariable will never be called for static no args methods
// // which doesn't use any local variables.
// // This means that hasLvtInfo could be false for that kind of methods
// // even if the class has local variable info.
// this.memberMap.put(resolveMember(), this.parameterNames);
// }
// }
//
// private Member resolveMember() {
// ClassLoader loader = this.clazz.getClassLoader();
// Class>[] argTypes = new Class>[this.args.length];
// for (int i = 0; i < this.args.length; i++) {
// argTypes[i] = ReflectUtil.resolveClassName(this.args[i].getClassName(), loader);
// }
// try {
// if (CONSTRUCTOR.equals(this.name)) {
// return this.clazz.getDeclaredConstructor(argTypes);
// }
// return this.clazz.getDeclaredMethod(this.name, argTypes);
// }
// catch (NoSuchMethodException ex) {
// throw new IllegalStateException("Method [" + this.name +
// "] was discovered in the .class file but cannot be resolved in the class object", ex);
// }
// }
//
// private static int[] computeLvtSlotIndices(boolean isStatic, Type[] paramTypes) {
// int[] lvtIndex = new int[paramTypes.length];
// int nextIndex = (isStatic ? 0 : 1);
// for (int i = 0; i < paramTypes.length; i++) {
// lvtIndex[i] = nextIndex;
// if (isWideType(paramTypes[i])) {
// nextIndex += 2;
// }
// else {
// nextIndex++;
// }
// }
// return lvtIndex;
// }
//
// private static boolean isWideType(Type aType) {
// // float is not a wide type
// return (aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE);
// }
// }
//
// public static Method[] getAllDeclaredMethods(Class> leafClass) {
// final List methods = new ArrayList<>(32);
// doWithMethods(leafClass, methods::add,null);
// return methods.toArray(new Method[0]);
// }
//
// private static List findConcreteMethodsOnInterfaces(Class> clazz) {
// List result = null;
// for (Class> ifc : clazz.getInterfaces()) {
// for (Method ifcMethod : ifc.getMethods()) {
// if (!Modifier.isAbstract(ifcMethod.getModifiers())) {
// if (result == null) {
// result = new LinkedList<>();
// }
// result.add(ifcMethod);
// }
// }
// }
// return result;
// }
//
// private static Method[] getDeclaredMethods(Class> clazz) {
// Objects.requireNonNull(clazz, "Class must not be null");
// Method[] result = DECLARED_METHODS_CACHE.get(clazz);
// if (result == null) {
// try {
// Method[] declaredMethods = clazz.getDeclaredMethods();
// List defaultMethods = findConcreteMethodsOnInterfaces(clazz);
// if (defaultMethods != null) {
// result = new Method[declaredMethods.length + defaultMethods.size()];
// System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length);
// int index = declaredMethods.length;
// for (Method defaultMethod : defaultMethods) {
// result[index] = defaultMethod;
// index++;
// }
// }
// else {
// result = declaredMethods;
// }
// DECLARED_METHODS_CACHE.put(clazz, (result.length == 0 ? NO_METHODS : result));
// }
// catch (Throwable ex) {
// throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() +
// "] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
// }
// }
// return result;
// }
//
// public static void doWithMethods(Class> clazz, Consumer mc, Function mf) {
// // Keep backing up the inheritance hierarchy.
// Method[] methods = getDeclaredMethods(clazz);
// for (Method method : methods) {
// if (mf != null && !mf.apply(method)) {
// continue;
// }
// try {
// mc.accept(method);
// }
// catch (Exception ex) {
// throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
// }
// }
// if (clazz.getSuperclass() != null) {
// doWithMethods(clazz.getSuperclass(), mc, mf);
// }
// else if (clazz.isInterface()) {
// for (Class> superIfc : clazz.getInterfaces()) {
// doWithMethods(superIfc, mc, mf);
// }
// }
// }
//
// private static boolean isBridgedCandidateFor(Method candidateMethod, Method bridgeMethod) {
// return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod) &&
// candidateMethod.getName().equals(bridgeMethod.getName()) &&
// candidateMethod.getParameterCount() == bridgeMethod.getParameterCount());
// }
//
// private static Method findBridgedMethod(Method bridgeMethod) {
// if (!bridgeMethod.isBridge()) {
// return bridgeMethod;
// }
//
// // Gather all methods with matching name and parameter size.
// List candidateMethods = new ArrayList<>();
// Method[] methods = getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
// for (Method candidateMethod : methods) {
// if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
// candidateMethods.add(candidateMethod);
// }
// }
//
// // Now perform simple quick check.
// if (candidateMethods.size() == 1) {
// return candidateMethods.get(0);
// }
// return bridgeMethod;
// }
//
// private static Method searchCandidates(List candidateMethods, Method bridgeMethod) {
// if (candidateMethods.isEmpty()) {
// return null;
// }
// Method previousMethod = null;
// boolean sameSig = true;
// for (Method candidateMethod : candidateMethods) {
// if (isBridgeMethodFor(bridgeMethod, candidateMethod, bridgeMethod.getDeclaringClass())) {
// return candidateMethod;
// }
// else if (previousMethod != null) {
// sameSig = sameSig &&
// Arrays.equals(candidateMethod.getGenericParameterTypes(), previousMethod.getGenericParameterTypes());
// }
// previousMethod = candidateMethod;
// }
// return (sameSig ? candidateMethods.get(0) : null);
// }
//
// private static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Class> declaringClass) {
// if (isResolvedTypeMatch(candidateMethod, bridgeMethod, declaringClass)) {
// return true;
// }
// Method method = findGenericDeclaration(bridgeMethod);
// return (method != null && isResolvedTypeMatch(method, candidateMethod, declaringClass));
// }
//
// private static Method findGenericDeclaration(Method bridgeMethod) {
// // Search parent types for method that has same signature as bridge.
// Class> superclass = bridgeMethod.getDeclaringClass().getSuperclass();
// while (superclass != null && Object.class != superclass) {
// Method method = searchForMatch(superclass, bridgeMethod);
// if (method != null && !method.isBridge()) {
// return method;
// }
// superclass = superclass.getSuperclass();
// }
//
// Class>[] interfaces = ReflectUtil.getInterfaces(bridgeMethod.getDeclaringClass());
// return searchInterfaces(interfaces, bridgeMethod);
// }
//
// private static Method searchInterfaces(Class>[] interfaces, Method bridgeMethod) {
// for (Class> ifc : interfaces) {
// Method method = searchForMatch(ifc, bridgeMethod);
// if (method != null && !method.isBridge()) {
// return method;
// }
// else {
// method = searchInterfaces(ifc.getInterfaces(), bridgeMethod);
// if (method != null) {
// return method;
// }
// }
// }
// return null;
// }
//
// private static Method searchForMatch(Class> type, Method bridgeMethod) {
// try {
// return type.getDeclaredMethod(bridgeMethod.getName(), bridgeMethod.getParameterTypes());
// }
// catch (NoSuchMethodException ex) {
// return null;
// }
// }
//
// private static boolean isResolvedTypeMatch(Method genericMethod, Method candidateMethod, Class> declaringClass) {
// java.lang.reflect.Type[] genericParameters = genericMethod.getGenericParameterTypes();
// Class>[] candidateParameters = candidateMethod.getParameterTypes();
// if (genericParameters.length != candidateParameters.length) {
// return false;
// }
// return true;
// }
//
// public static void main(String[] args) {
// ParameterNameDiscoverer parameterNameDiscoverer = new ParameterNameDiscoverer();
// Map memberMap = parameterNameDiscoverer.inspectClass(ClassFileMethodToParameterNamesFunction.class);
// System.out.println("memberMap = " + memberMap);
// }
//}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy