Remove LocalVariableTableParameterNameDiscoverer
Closes gh-29559
This commit is contained in:
parent
9342317291
commit
4d15b58ca4
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -18,8 +18,7 @@ package org.springframework.core;
|
|||
|
||||
/**
|
||||
* Default implementation of the {@link ParameterNameDiscoverer} strategy interface,
|
||||
* delegating to the Java 8 standard reflection mechanism, with a deprecated fallback
|
||||
* to {@link LocalVariableTableParameterNameDiscoverer}.
|
||||
* delegating to the Java 8 standard reflection mechanism.
|
||||
*
|
||||
* <p>If a Kotlin reflection implementation is present,
|
||||
* {@link KotlinReflectionParameterNameDiscoverer} is added first in the list and
|
||||
|
|
@ -36,7 +35,6 @@ package org.springframework.core;
|
|||
*/
|
||||
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
public DefaultParameterNameDiscoverer() {
|
||||
if (KotlinDetector.isKotlinReflectPresent()) {
|
||||
addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
|
||||
|
|
@ -44,12 +42,6 @@ public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDisc
|
|||
|
||||
// Recommended approach on Java 8+: compilation with -parameters.
|
||||
addDiscoverer(new StandardReflectionParameterNameDiscoverer());
|
||||
|
||||
// Deprecated fallback to class file parsing for -debug symbols.
|
||||
// Does not work on native images without class file resources.
|
||||
if (!NativeDetector.inNativeImage()) {
|
||||
addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.SpringAsmInfo;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ParameterNameDiscoverer} that uses the LocalVariableTable
|
||||
* information in the method attributes to discover parameter names. Returns
|
||||
* {@code null} if the class file was compiled without debug information.
|
||||
*
|
||||
* <p>Uses ObjectWeb's ASM library for analyzing class files. Each discoverer instance
|
||||
* caches the ASM discovered information for each introspected Class, in a thread-safe
|
||||
* manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
|
||||
*
|
||||
* <p>This class is deprecated in the 6.0 generation and scheduled for removal in 6.1
|
||||
* since it is effectively superseded by {@link StandardReflectionParameterNameDiscoverer}.
|
||||
* For the time being, this discoverer logs a warning every time it actually inspects a
|
||||
* class file which is particularly useful for identifying remaining gaps in usage of
|
||||
* the standard "-parameters" compiler flag, and also unintended over-inspection of
|
||||
* e.g. JDK core library classes (which are not compiled with the "-parameters" flag).
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
* @see StandardReflectionParameterNameDiscoverer
|
||||
* @see DefaultParameterNameDiscoverer
|
||||
* @deprecated as of 6.0.1, in favor of {@link StandardReflectionParameterNameDiscoverer}
|
||||
* (with the "-parameters" compiler flag)
|
||||
*/
|
||||
@Deprecated(since = "6.0.1", forRemoval = true)
|
||||
public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(LocalVariableTableParameterNameDiscoverer.class);
|
||||
|
||||
// marker object for classes that do not have any debug info
|
||||
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
|
||||
private final Map<Class<?>, Map<Executable, String[]>> parameterNamesCache = new ConcurrentHashMap<>(32);
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames(Method method) {
|
||||
Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
return doGetParameterNames(originalMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames(Constructor<?> ctor) {
|
||||
return doGetParameterNames(ctor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String[] doGetParameterNames(Executable executable) {
|
||||
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.
|
||||
* <p>Exceptions will be logged, and a marker map returned to indicate the
|
||||
* lack of debug information.
|
||||
*/
|
||||
private Map<Executable, String[]> inspectClass(Class<?> clazz) {
|
||||
InputStream is = clazz.getResourceAsStream(ClassUtils.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;
|
||||
}
|
||||
// We cannot use try-with-resources here for the InputStream, since we have
|
||||
// custom handling of the close() method in a finally-block.
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(is);
|
||||
Map<Executable, String[]> map = new ConcurrentHashMap<>(32);
|
||||
classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Using deprecated '-debug' fallback for parameter name resolution. Compile the " +
|
||||
"affected code with '-parameters' instead or avoid its introspection: " + clazz.getName());
|
||||
}
|
||||
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 and constructors and then
|
||||
* attempts to find the parameter names for the given {@link Executable}.
|
||||
*/
|
||||
private static class ParameterNameDiscoveringVisitor extends ClassVisitor {
|
||||
|
||||
private static final String STATIC_CLASS_INIT = "<clinit>";
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Map<Executable, String[]> executableMap;
|
||||
|
||||
public ParameterNameDiscoveringVisitor(Class<?> clazz, Map<Executable, String[]> executableMap) {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
this.clazz = clazz;
|
||||
this.executableMap = executableMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
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.executableMap, 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 = "<init>";
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
private final Map<Executable, String[]> executableMap;
|
||||
|
||||
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<Executable, String[]> map, String name, String desc, boolean isStatic) {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
this.clazz = clazz;
|
||||
this.executableMap = 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.executableMap.put(resolveExecutable(), this.parameterNames);
|
||||
}
|
||||
}
|
||||
|
||||
private Executable resolveExecutable() {
|
||||
ClassLoader loader = this.clazz.getClassLoader();
|
||||
Class<?>[] argTypes = new Class<?>[this.args.length];
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
argTypes[i] = ClassUtils.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,326 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.core;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.tests.sample.objects.TestObject;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Adrian Colyer
|
||||
*/
|
||||
class LocalVariableTableParameterNameDiscovererTests {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private final ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
|
||||
@Test
|
||||
void methodParameterNameDiscoveryNoArgs() throws NoSuchMethodException {
|
||||
Method getName = TestObject.class.getMethod("getName");
|
||||
String[] names = discoverer.getParameterNames(getName);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("no argument names").isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void methodParameterNameDiscoveryWithArgs() throws NoSuchMethodException {
|
||||
Method setName = TestObject.class.getMethod("setName", String.class);
|
||||
String[] names = discoverer.getParameterNames(setName);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("one argument").hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void consParameterNameDiscoveryNoArgs() throws NoSuchMethodException {
|
||||
Constructor<TestObject> noArgsCons = TestObject.class.getConstructor();
|
||||
String[] names = discoverer.getParameterNames(noArgsCons);
|
||||
assertThat(names).as("should find cons info").isNotNull();
|
||||
assertThat(names).as("no argument names").isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void consParameterNameDiscoveryArgs() throws NoSuchMethodException {
|
||||
Constructor<TestObject> twoArgCons = TestObject.class.getConstructor(String.class, int.class);
|
||||
String[] names = discoverer.getParameterNames(twoArgCons);
|
||||
assertThat(names).as("should find cons info").isNotNull();
|
||||
assertThat(names).as("one argument").hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("name");
|
||||
assertThat(names[1]).isEqualTo("age");
|
||||
}
|
||||
|
||||
@Test
|
||||
void staticMethodParameterNameDiscoveryNoArgs() throws NoSuchMethodException {
|
||||
Method m = getClass().getMethod("staticMethodNoLocalVars");
|
||||
String[] names = discoverer.getParameterNames(m);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("no argument names").isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void overloadedStaticMethod() throws Exception {
|
||||
Class<? extends LocalVariableTableParameterNameDiscovererTests> clazz = this.getClass();
|
||||
|
||||
Method m1 = clazz.getMethod("staticMethod", Long.TYPE, Long.TYPE);
|
||||
String[] names = discoverer.getParameterNames(m1);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("two arguments").hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("x");
|
||||
assertThat(names[1]).isEqualTo("y");
|
||||
|
||||
Method m2 = clazz.getMethod("staticMethod", Long.TYPE, Long.TYPE, Long.TYPE);
|
||||
names = discoverer.getParameterNames(m2);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("three arguments").hasSize(3);
|
||||
assertThat(names[0]).isEqualTo("x");
|
||||
assertThat(names[1]).isEqualTo("y");
|
||||
assertThat(names[2]).isEqualTo("z");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overloadedStaticMethodInInnerClass() throws Exception {
|
||||
Class<InnerClass> clazz = InnerClass.class;
|
||||
|
||||
Method m1 = clazz.getMethod("staticMethod", Long.TYPE);
|
||||
String[] names = discoverer.getParameterNames(m1);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("one argument").hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("x");
|
||||
|
||||
Method m2 = clazz.getMethod("staticMethod", Long.TYPE, Long.TYPE);
|
||||
names = discoverer.getParameterNames(m2);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("two arguments").hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("x");
|
||||
assertThat(names[1]).isEqualTo("y");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overloadedMethod() throws Exception {
|
||||
Class<? extends LocalVariableTableParameterNameDiscovererTests> clazz = this.getClass();
|
||||
|
||||
Method m1 = clazz.getMethod("instanceMethod", Double.TYPE, Double.TYPE);
|
||||
String[] names = discoverer.getParameterNames(m1);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("two arguments").hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("x");
|
||||
assertThat(names[1]).isEqualTo("y");
|
||||
|
||||
Method m2 = clazz.getMethod("instanceMethod", Double.TYPE, Double.TYPE, Double.TYPE);
|
||||
names = discoverer.getParameterNames(m2);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("three arguments").hasSize(3);
|
||||
assertThat(names[0]).isEqualTo("x");
|
||||
assertThat(names[1]).isEqualTo("y");
|
||||
assertThat(names[2]).isEqualTo("z");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overloadedMethodInInnerClass() throws Exception {
|
||||
Class<InnerClass> clazz = InnerClass.class;
|
||||
|
||||
Method m1 = clazz.getMethod("instanceMethod", String.class);
|
||||
String[] names = discoverer.getParameterNames(m1);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("one argument").hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("aa");
|
||||
|
||||
Method m2 = clazz.getMethod("instanceMethod", String.class, String.class);
|
||||
names = discoverer.getParameterNames(m2);
|
||||
assertThat(names).as("should find method info").isNotNull();
|
||||
assertThat(names).as("two arguments").hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("aa");
|
||||
assertThat(names[1]).isEqualTo("bb");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generifiedClass() throws Exception {
|
||||
Class<?> clazz = GenerifiedClass.class;
|
||||
|
||||
Constructor<?> ctor = clazz.getDeclaredConstructor(Object.class);
|
||||
String[] names = discoverer.getParameterNames(ctor);
|
||||
assertThat(names).hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("key");
|
||||
|
||||
ctor = clazz.getDeclaredConstructor(Object.class, Object.class);
|
||||
names = discoverer.getParameterNames(ctor);
|
||||
assertThat(names).hasSize(2);
|
||||
assertThat(names[0]).isEqualTo("key");
|
||||
assertThat(names[1]).isEqualTo("value");
|
||||
|
||||
Method m = clazz.getMethod("generifiedStaticMethod", Object.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).hasSize(1);
|
||||
assertThat(names[0]).isEqualTo("param");
|
||||
|
||||
m = clazz.getMethod("generifiedMethod", Object.class, long.class, Object.class, Object.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).hasSize(4);
|
||||
assertThat(names[0]).isEqualTo("param");
|
||||
assertThat(names[1]).isEqualTo("x");
|
||||
assertThat(names[2]).isEqualTo("key");
|
||||
assertThat(names[3]).isEqualTo("value");
|
||||
|
||||
m = clazz.getMethod("voidStaticMethod", Object.class, long.class, int.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).hasSize(3);
|
||||
assertThat(names[0]).isEqualTo("obj");
|
||||
assertThat(names[1]).isEqualTo("x");
|
||||
assertThat(names[2]).isEqualTo("i");
|
||||
|
||||
m = clazz.getMethod("nonVoidStaticMethod", Object.class, long.class, int.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).hasSize(3);
|
||||
assertThat(names[0]).isEqualTo("obj");
|
||||
assertThat(names[1]).isEqualTo("x");
|
||||
assertThat(names[2]).isEqualTo("i");
|
||||
|
||||
m = clazz.getMethod("getDate");
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).isEmpty();
|
||||
}
|
||||
|
||||
@Disabled("Ignored because Ubuntu packages OpenJDK with debug symbols enabled. See SPR-8078.")
|
||||
@Test
|
||||
void classesWithoutDebugSymbols() throws Exception {
|
||||
// JDK classes don't have debug information (usually)
|
||||
Class<Component> clazz = Component.class;
|
||||
String methodName = "list";
|
||||
|
||||
Method m = clazz.getMethod(methodName);
|
||||
String[] names = discoverer.getParameterNames(m);
|
||||
assertThat(names).isNull();
|
||||
|
||||
m = clazz.getMethod(methodName, PrintStream.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).isNull();
|
||||
|
||||
m = clazz.getMethod(methodName, PrintStream.class, int.class);
|
||||
names = discoverer.getParameterNames(m);
|
||||
assertThat(names).isNull();
|
||||
}
|
||||
|
||||
|
||||
public static void staticMethodNoLocalVars() {
|
||||
}
|
||||
|
||||
public static long staticMethod(long x, long y) {
|
||||
long u = x * y;
|
||||
return u;
|
||||
}
|
||||
|
||||
public static long staticMethod(long x, long y, long z) {
|
||||
long u = x * y * z;
|
||||
return u;
|
||||
}
|
||||
|
||||
public double instanceMethod(double x, double y) {
|
||||
double u = x * y;
|
||||
return u;
|
||||
}
|
||||
|
||||
public double instanceMethod(double x, double y, double z) {
|
||||
double u = x * y * z;
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
public static class InnerClass {
|
||||
|
||||
public int waz = 0;
|
||||
|
||||
public InnerClass() {
|
||||
}
|
||||
|
||||
public InnerClass(String firstArg, long secondArg, Object thirdArg) {
|
||||
long foo = 0;
|
||||
short bar = 10;
|
||||
this.waz = (int) (foo + bar);
|
||||
}
|
||||
|
||||
public String instanceMethod(String aa) {
|
||||
return aa;
|
||||
}
|
||||
|
||||
public String instanceMethod(String aa, String bb) {
|
||||
return aa + bb;
|
||||
}
|
||||
|
||||
public static long staticMethod(long x) {
|
||||
long u = x;
|
||||
return u;
|
||||
}
|
||||
|
||||
public static long staticMethod(long x, long y) {
|
||||
long u = x * y;
|
||||
return u;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class GenerifiedClass<K, V> {
|
||||
|
||||
private static long date;
|
||||
|
||||
static {
|
||||
// some custom static bloc or <clinit>
|
||||
date = new Date().getTime();
|
||||
}
|
||||
|
||||
public GenerifiedClass() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public GenerifiedClass(K key) {
|
||||
this(key, null);
|
||||
}
|
||||
|
||||
public GenerifiedClass(K key, V value) {
|
||||
}
|
||||
|
||||
public static <P> long generifiedStaticMethod(P param) {
|
||||
return date;
|
||||
}
|
||||
|
||||
public <P> void generifiedMethod(P param, long x, K key, V value) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public static void voidStaticMethod(Object obj, long x, int i) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public static long nonVoidStaticMethod(Object obj, long x, int i) {
|
||||
return date;
|
||||
}
|
||||
|
||||
public static long getDate() {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue