Inconsistency in Constructor.getGenericParameterTypes()

Joe Darcy joe.darcy at oracle.com
Tue Mar 2 02:17:35 UTC 2021


Hi Remi,

As package level statement would be helpful as long as it was linked to 
from specific types and methods (as java.lang.Class and 
java.lang.Package are part of core reflection but not the 
java.lang.reflect package).

As you state, core reflection is *mostly* a view of what is represented 
in the class file. However, the class file in general does not present 
sufficient information in all cases to recover a source-file view of the 
world even as an option. For example, as a compiler-internal contract 
javac had added two additional parameters to the private constructors of 
enums. Other Java compilers are required to do this and javac could, in 
principle, change this implementation detail at any time. There is no 
MANDATED or SYNTHETIC bit (see javax.lang.model.util.Elements.Origin) 
that can be used to reliably tease apart what is going on. The 
package-level specs of javax.lang.model.element discuss analogous issue 
for the language model API.

In any case, I've filed

     JDK-8262807: Note assumptions of core reflection modeling and 
parameter handling

for core reflection.

Thanks,

-Joe

On 3/1/2021 2:16 PM, Remi Forax wrote:
> Hi Joe,
> i think the overview of the package java.lang.reflect should discuss the fact that the reflection view is what is stored in the classfile, not exactly a reflection of the java code.
>
> So depending on what you are requesting, you can see synthetic parameters generated by javac or only the Java view because the Java view is directly stored in an attributes like with generics
>
> Rémi
>
> ----- Mail original -----
>> De: "joe darcy" <joe.darcy at oracle.com>
>> À: "Oliver Drotbohm" <odrotbohm at vmware.com>
>> Cc: "core-libs-dev" <core-libs-dev at openjdk.java.net>
>> Envoyé: Lundi 1 Mars 2021 22:35:59
>> Objet: Re: Inconsistency in Constructor.getGenericParameterTypes()
>> Hi Oliver,
>>
>> Perhaps the time has come to make a run at discussing this situation in
>> the javadoc. One challenge in writing this material up is to phrase and
>> structure the text so it offers a net-clarification of the situation. In
>> other words, to not distract or confuse most readers on what is usually
>> a tricky detail.
>>
>> The @apiNote javadoc tag offers a mechanism to separate such discussion.
>>
>> Thanks,
>>
>> -Joe
>>
>> On 2/26/2021 2:20 PM, Oliver Drotbohm wrote:
>>> Hi Joe,
>>>
>>> thanks for the explanation. We switched to rather iterating over
>>> ….getParameters() and take it from there. Do you think it makes sense to leave
>>> a note about this in the Javadoc?
>>>
>>> Cheers,
>>> Ollie
>>>
>>>> Am 26.02.2021 um 22:38 schrieb Joe Darcy <joe.darcy at oracle.com>:
>>>>
>>>> Hello Oliver,
>>>>
>>>> This is long-standing if surprising and under-documented behavior.
>>>>
>>>> The getGenericFoo methods, when generic type information is present, give a
>>>> source-level view of the element. At a source level, the implicit outer this
>>>> parameter is not present and thus omitted by
>>>> constructor.getGenericParameterTypes for the constructor in question.
>>>>
>>>> HTH,
>>>>
>>>> -Joe
>>>>
>>>> On 2/26/2021 5:41 AM, Oliver Drotbohm wrote:
>>>>> Previously sent to the wrong list. Sorry for the double post.
>>>>>
>>>>> Von: Oliver Drotbohm <odrotbohm at vmware.com>
>>>>> Betreff: Inconsistency in Constructor.getGenericParameterTypes()
>>>>> Datum: 25. Februar 2021 um 10:03:12 MEZ
>>>>> An: jdk-dev at openjdk.java.net
>>>>>
>>>>> Hi all,
>>>>>
>>>>> we've just ran into the following issue: for a non-static, generic inner class
>>>>> with a constructor declaring a generic parameter, a call to
>>>>> constructor.getGenericParameterTypes() does not return the enclosing class
>>>>> parameter type. Is that by intention? If so, what's the reasoning behind that?
>>>>>
>>>>> Here's a the output of a reproducer (below):
>>>>>
>>>>> static class StaticGeneric<T> - names: value, string
>>>>> static class StaticGeneric<T> - parameters: [class java.lang.Object, class
>>>>> java.lang.String]
>>>>> static class StaticGeneric<T> - generic parameters: [T, class java.lang.String]
>>>>>
>>>>> class NonStaticGeneric<T> - names: this$0, value, String
>>>>> class NonStaticGeneric<T> - parameters: [class Sample, class java.lang.Object,
>>>>> class java.lang.String]
>>>>> class NonStaticGeneric<T> - generic parameters: [T, class java.lang.String]
>>>>>
>>>>> class NonStaticNonGeneric - names: this$0, String
>>>>> class NonStaticNonGeneric - parameters: [class Sample, class java.lang.String]
>>>>> class NonStaticNonGeneric - generic parameters: [class Sample, class
>>>>> java.lang.String]
>>>>>
>>>>> Note how the constructor of the NonStaticGeneric<T> type exposes three parameter
>>>>> names, three parameter types but omits the enclosing class parameter in the
>>>>> list of generic parameter types.
>>>>>
>>>>> Tested on JDK 8 to 15. Same behavior.
>>>>>
>>>>> Cheers,
>>>>> Ollie
>>>>>
>>>>>
>>>>> class Sample {
>>>>>
>>>>> 	public static void main(String[] args) {
>>>>>
>>>>> 		Constructor<?> first = StaticGeneric.class.getDeclaredConstructors()[0];
>>>>>
>>>>> 		System.out.println("static class StaticGeneric<T> - names: "
>>>>> 				+
>>>>> 				Arrays.stream(first.getParameters()).map(Parameter::getName).collect(Collectors.joining(",
>>>>> 				")));
>>>>> 		System.out.println("static class StaticGeneric<T> - parameters: " +
>>>>> 		Arrays.toString(first.getParameterTypes()));
>>>>> 		System.out.println(
>>>>> 				"static class StaticGeneric<T> - generic parameters: " +
>>>>> 				Arrays.toString(first.getGenericParameterTypes()));
>>>>>
>>>>> 		System.out.println();
>>>>>
>>>>> 		Constructor<?> second = NonStaticGeneric.class.getDeclaredConstructors()[0];
>>>>> 		System.out.println("class NonStaticGeneric<T> - names: "
>>>>> 				+
>>>>> 				Arrays.stream(second.getParameters()).map(Parameter::getName).collect(Collectors.joining(",
>>>>> 				")));
>>>>> 		System.out.println("class NonStaticGeneric<T> - parameters: " +
>>>>> 		Arrays.toString(second.getParameterTypes()));
>>>>> 		System.out
>>>>> 				.println(
>>>>> 						"class NonStaticGeneric<T> - generic parameters: " +
>>>>> 						Arrays.toString(second.getGenericParameterTypes()));
>>>>>
>>>>> 		System.out.println();
>>>>>
>>>>> 		Constructor<?> third = NonStaticNonGeneric.class.getDeclaredConstructors()[0];
>>>>> 		System.out.println("class NonStaticNonGeneric - names: "
>>>>> 				+
>>>>> 				Arrays.stream(third.getParameters()).map(Parameter::getName).collect(Collectors.joining(",
>>>>> 				")));
>>>>> 		System.out.println("class NonStaticNonGeneric - parameters: " +
>>>>> 		Arrays.toString(third.getParameterTypes()));
>>>>> 		System.out
>>>>> 				.println(
>>>>> 						"class NonStaticNonGeneric - generic parameters: " +
>>>>> 						Arrays.toString(third.getGenericParameterTypes()));
>>>>> 	}
>>>>>
>>>>> 	static class StaticGeneric<T> {
>>>>> 		StaticGeneric(T value, String string) {}
>>>>> 	}
>>>>>
>>>>> 	class NonStaticGeneric<T> {
>>>>> 		NonStaticGeneric(T value, String String) {}
>>>>> 	}
>>>>>
>>>>> 	class NonStaticNonGeneric {
>>>>> 		NonStaticNonGeneric(String String) {}
>>>>> 	}
>>>>> }


More information about the core-libs-dev mailing list