Skip to content

Commit f0afd89

Browse files
committed
8357728: Avoid caching synthesized names in synthesized parameters
Reviewed-by: jvernee
1 parent 0bff5f3 commit f0afd89

File tree

3 files changed

+84
-3
lines changed

3 files changed

+84
-3
lines changed

src/java.base/share/classes/java/lang/reflect/Executable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ private Parameter[] synthesizeAllParams() {
431431
// modifiers? Probably not in the general case, since
432432
// we'd have no way of knowing about them, but there
433433
// may be specific cases.
434-
out[i] = new Parameter("arg" + i, 0, this, i);
434+
out[i] = new Parameter(null, 0, this, i);
435435
return out;
436436
}
437437

src/java.base/share/classes/java/lang/reflect/Parameter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public final class Parameter implements AnnotatedElement {
5555
* absent, however, then {@code Executable} uses this constructor
5656
* to synthesize them.
5757
*
58-
* @param name The name of the parameter.
58+
* @param name The name of the parameter, or {@code null} if absent
5959
* @param modifiers The modifier flags for the parameter.
6060
* @param executable The executable which defines this parameter.
6161
* @param index The index of the parameter.
@@ -104,7 +104,7 @@ public int hashCode() {
104104
* to the class file.
105105
*/
106106
public boolean isNamePresent() {
107-
return executable.hasRealParameterData() && name != null;
107+
return name != null;
108108
}
109109

110110
/**
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.lang.invoke.MethodHandleProxies;
25+
import java.lang.invoke.MethodHandles;
26+
import java.lang.reflect.Constructor;
27+
import java.lang.reflect.Executable;
28+
import java.lang.reflect.Parameter;
29+
import java.util.stream.Stream;
30+
31+
import org.junit.jupiter.params.ParameterizedTest;
32+
import org.junit.jupiter.params.provider.MethodSource;
33+
34+
import static org.junit.jupiter.api.Assertions.*;
35+
36+
/*
37+
* @test
38+
* @bug 8357728
39+
* @summary Synthetic parameter names should not be retained.
40+
* @modules java.base/java.lang.reflect:+open
41+
* @run junit SyntheticNameRetention
42+
*/
43+
public class SyntheticNameRetention {
44+
45+
class Inner {
46+
Inner() {}
47+
}
48+
49+
public interface NameGetter {
50+
String getRawName(Parameter parameter);
51+
}
52+
static final NameGetter GETTER;
53+
54+
static {
55+
try {
56+
var lookup = MethodHandles.privateLookupIn(Parameter.class, MethodHandles.lookup());
57+
GETTER = MethodHandleProxies.asInterfaceInstance(NameGetter.class, lookup.findGetter(Parameter.class, "name", String.class));
58+
} catch (ReflectiveOperationException ex) {
59+
throw new ExceptionInInitializerError(ex);
60+
}
61+
}
62+
63+
static Stream<Executable> methods() throws Throwable {
64+
return Stream.of(Inner.class.getDeclaredConstructor(SyntheticNameRetention.class), // Has MethodParameters with flags
65+
SyntheticNameRetention.class.getDeclaredMethod("test", Executable.class)); // No MethodParameters
66+
}
67+
68+
@ParameterizedTest
69+
@MethodSource("methods")
70+
public void test(Executable exec) {
71+
var params = exec.getParameters();
72+
for (int i = 0; i < params.length; i++) {
73+
var param = params[i];
74+
assertEquals("arg" + i, param.getName(), "name " + i);
75+
assertFalse(param.isNamePresent(), "name present " + i);
76+
assertNull(GETTER.getRawName(param), "raw name " + i);
77+
boolean mandated = exec instanceof Constructor<?> && i == 0;
78+
assertEquals(mandated, param.isImplicit(), "mandated " + i);
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)