Simplify LocalVariableTableParameterNameDiscoverer implementation

This commit refactors the internals of
LocalVariableTableParameterNameDiscoverer to use
java.lang.reflect.Executable in order to simplify the implementation.
This commit is contained in:
Sam Brannen 2019-07-12 12:02:49 +02:00
parent 309b328719
commit 699d3f15e8
1 changed files with 30 additions and 31 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,7 @@ package org.springframework.core;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Member; import java.lang.reflect.Executable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -51,6 +51,7 @@ import org.springframework.util.ClassUtils;
* @author Costin Leau * @author Costin Leau
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Chris Beams * @author Chris Beams
* @author Sam Brannen
* @since 2.0 * @since 2.0
*/ */
public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer { public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
@ -58,40 +59,38 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
private static final Log logger = LogFactory.getLog(LocalVariableTableParameterNameDiscoverer.class); private static final Log logger = LogFactory.getLog(LocalVariableTableParameterNameDiscoverer.class);
// marker object for classes that do not have any debug info // marker object for classes that do not have any debug info
private static final Map<Member, String[]> NO_DEBUG_INFO_MAP = Collections.emptyMap(); private static final Map<Executable, String[]> NO_DEBUG_INFO_MAP = Collections.emptyMap();
// the cache uses a nested index (value is a map) to keep the top level cache relatively small in size // the cache uses a nested index (value is a map) to keep the top level cache relatively small in size
private final Map<Class<?>, Map<Member, String[]>> parameterNamesCache = new ConcurrentHashMap<>(32); private final Map<Class<?>, Map<Executable, String[]>> parameterNamesCache = new ConcurrentHashMap<>(32);
@Override @Override
@Nullable @Nullable
public String[] getParameterNames(Method method) { public String[] getParameterNames(Method method) {
Method originalMethod = BridgeMethodResolver.findBridgedMethod(method); Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
Class<?> declaringClass = originalMethod.getDeclaringClass(); return doGetParameterNames(originalMethod);
Map<Member, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass);
if (map != NO_DEBUG_INFO_MAP) {
return map.get(originalMethod);
}
return null;
} }
@Override @Override
@Nullable @Nullable
public String[] getParameterNames(Constructor<?> ctor) { public String[] getParameterNames(Constructor<?> ctor) {
Class<?> declaringClass = ctor.getDeclaringClass(); return doGetParameterNames(ctor);
Map<Member, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass); }
if (map != NO_DEBUG_INFO_MAP) {
return map.get(ctor); @Nullable
} private String[] doGetParameterNames(Executable executable) {
return null; Class<?> declaringClass = executable.getDeclaringClass();
Map<Executable, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass);
return (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null);
} }
/** /**
* Inspects the target class. Exceptions will be logged and a maker map returned * Inspects the target class.
* to indicate the lack of debug information. * <p>Exceptions will be logged, and a marker map returned to indicate the
* lack of debug information.
*/ */
private Map<Member, String[]> inspectClass(Class<?> clazz) { private Map<Executable, String[]> inspectClass(Class<?> clazz) {
InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz)); InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));
if (is == null) { if (is == null) {
// We couldn't load the class file, which is not fatal as it // We couldn't load the class file, which is not fatal as it
@ -104,7 +103,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
} }
try { try {
ClassReader classReader = new ClassReader(is); ClassReader classReader = new ClassReader(is);
Map<Member, String[]> map = new ConcurrentHashMap<>(32); Map<Executable, String[]> map = new ConcurrentHashMap<>(32);
classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0); classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
return map; return map;
} }
@ -134,8 +133,8 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
/** /**
* Helper class that inspects all methods (constructor included) and then * Helper class that inspects all methods and constructors and then
* attempts to find the parameter names for that member. * attempts to find the parameter names for the given {@link Executable}.
*/ */
private static class ParameterNameDiscoveringVisitor extends ClassVisitor { private static class ParameterNameDiscoveringVisitor extends ClassVisitor {
@ -143,12 +142,12 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
private final Class<?> clazz; private final Class<?> clazz;
private final Map<Member, String[]> memberMap; private final Map<Executable, String[]> executableMap;
public ParameterNameDiscoveringVisitor(Class<?> clazz, Map<Member, String[]> memberMap) { public ParameterNameDiscoveringVisitor(Class<?> clazz, Map<Executable, String[]> executableMap) {
super(SpringAsmInfo.ASM_VERSION); super(SpringAsmInfo.ASM_VERSION);
this.clazz = clazz; this.clazz = clazz;
this.memberMap = memberMap; this.executableMap = executableMap;
} }
@Override @Override
@ -156,7 +155,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// exclude synthetic + bridged && static class initialization // exclude synthetic + bridged && static class initialization
if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) { if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {
return new LocalVariableTableVisitor(this.clazz, this.memberMap, name, desc, isStatic(access)); return new LocalVariableTableVisitor(this.clazz, this.executableMap, name, desc, isStatic(access));
} }
return null; return null;
} }
@ -177,7 +176,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
private final Class<?> clazz; private final Class<?> clazz;
private final Map<Member, String[]> memberMap; private final Map<Executable, String[]> executableMap;
private final String name; private final String name;
@ -195,10 +194,10 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
*/ */
private final int[] lvtSlotIndex; private final int[] lvtSlotIndex;
public LocalVariableTableVisitor(Class<?> clazz, Map<Member, String[]> map, String name, String desc, boolean isStatic) { public LocalVariableTableVisitor(Class<?> clazz, Map<Executable, String[]> map, String name, String desc, boolean isStatic) {
super(SpringAsmInfo.ASM_VERSION); super(SpringAsmInfo.ASM_VERSION);
this.clazz = clazz; this.clazz = clazz;
this.memberMap = map; this.executableMap = map;
this.name = name; this.name = name;
this.args = Type.getArgumentTypes(desc); this.args = Type.getArgumentTypes(desc);
this.parameterNames = new String[this.args.length]; this.parameterNames = new String[this.args.length];
@ -223,11 +222,11 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
// which doesn't use any local variables. // which doesn't use any local variables.
// This means that hasLvtInfo could be false for that kind of methods // This means that hasLvtInfo could be false for that kind of methods
// even if the class has local variable info. // even if the class has local variable info.
this.memberMap.put(resolveMember(), this.parameterNames); this.executableMap.put(resolveExecutable(), this.parameterNames);
} }
} }
private Member resolveMember() { private Executable resolveExecutable() {
ClassLoader loader = this.clazz.getClassLoader(); ClassLoader loader = this.clazz.getClassLoader();
Class<?>[] argTypes = new Class<?>[this.args.length]; Class<?>[] argTypes = new Class<?>[this.args.length];
for (int i = 0; i < this.args.length; i++) { for (int i = 0; i < this.args.length; i++) {