Reflection APIs for records
Oliver Drotbohm
odrotbohm at pivotal.io
Mon Jan 20 06:24:08 UTC 2020
> Am 19.01.2020 um 21:09 schrieb Brian Goetz <brian.goetz at oracle.com>:
>
> OK, that makes more sense — if you’re already going through Introspector for ordinary classes, it would not be very difficult to make Introspector understand records. This seems a reasonable enhancement. I could imagine getBeanIntrospector on a record invoking the constructor with stopClass=java.lang.Record.class and maybe a flag that says “hey, we’ve got a record here, also mine the components for property descriptions.” This should fit fairly cleanly into the beans model.
>
> Is this something you’d be interested in working on?
I would. Haven't contributed to anything JDK related before though. Wouldn't mind some initial guidance off list if you prefer.
Cheers,
Ollie
>> On Jan 18, 2020, at 12:16 PM, Oliver Drotbohm <odrotbohm at pivotal.io> wrote:
>>
>> Remi, Brian,
>>
>> thanks for your feedback. Obviously I have been imprecise about why I am asking for. I didn't want to ask for new methods on the reflection API but the beans API creating PropertyDescriptor instance produce ones for records that expose record components as effectively read-only properties. Let me try it another way:
>>
>> Given a record "record Point(int x, int y) {}", Introspector.getBeanInfo(Point.class) currently returns a BeanInfo instance that only exposes "class" as PropertyDescriptor. If that BeanInfo exposed PropertyDescriptors for x and y in the way I described in my original email, not a single change to at least Spring Framework would be needed to generally support records for data binding and mapping purposes.
>>
>> From an inspection and property metadata point of view they'd just behave like classes that do not expose setters. I assume that other libraries using the BeanInfo API today would be able to also pick up records at least in general without further changes.
>>
>> What my current POC does is plugging into Spring's PropertyDescriptor detection and adds those synthetic ones. That of course only if client code uses Spring's BeanUtils.getPropertyDescriptors(…). A lot of Spring Framework ecosystem project code already does that so that we can make this work transparently with the change local to Spring Framework. However, *all other libraries mentioned* would have do something similar to properly support records as replacements for e.g. DTOs to render views, JSON or the like. If Introspector.getBeanInfo(…) changed according to my proposal, that would not be needed and records could be adopted right away in such contexts even with existing releases of those libraries.
>>
>> I think that adoption of records would be severely hindered if we had to wait for all prominent libraries having to add additional support and ship releases for that, as they'd need to make sure that they're build works on JDK 14 in the first place.
>>
>>> If you mean providing a method getRecordCanonicalConstructor() in java.lang.Class with a code roughly similar to
>>> recordClass.getConstructor(Arrays.stream(recordClass.getRecordComponents()).map(RecordComponent::getType).toArray(Class[]::new));
>>> we discuss about that and if I remember correctly defer that item saying we will see if people want that method or not :)
>>
>> That's what I am asking, yes. The crucial bit here being that I'd still be able to identify the constructor taking all record components if potential additional, user declared constructors were defined.
>>
>> Cheers,
>> Ollie
>>
>>> Am 18.01.2020 um 17:23 schrieb Remi Forax <forax at univ-mlv.fr>:
>>>
>>> ----- Mail original -----
>>>> De: "Oliver Drotbohm" <odrotbohm at pivotal.io>
>>>> À: "amber-dev" <amber-dev at openjdk.java.net>
>>>> Envoyé: Samedi 18 Janvier 2020 15:54:42
>>>> Objet: Reflection APIs for records
>>>
>>>
>>> Hi Oliver,
>>>
>>>> Hi all,
>>>>
>>>> the Spring team is currently investigating integration with records in various
>>>> parts of the framework like form binding in Spring WebMVC/WebFlux or object
>>>> mapping in Spring Data.
>>>
>>> Thanks for doing this !
>>>
>>>> Historically those features have worked with the
>>>> PropertyDescriptor APIs adding a few tweaks here and there.
>>>>
>>>> I was wondering whether you'd be willing to consider to expose
>>>> PropertyDescriptors for record types so that they're effectively equivalents to
>>>> a read-only property. I gave the Spring Framework abstraction around this a
>>>> quick spin, plugging in a component that would create a synthetic
>>>> PropertyDescriptor instance like this:
>>>>
>>>> private static PropertyDescriptor toPropertyDescriptor(RecordComponent
>>>> component) {
>>>>
>>>> try {
>>>> return new PropertyDescriptor(component.getName(), component.getAccessor(),
>>>> null);
>>>> } catch (IntrospectionException o_O) {
>>>> throw new RuntimeException("Invalid record definition!", o_O);
>>>> }
>>>> }
>>>>
>>>> This makes Spring Data object mapping work with records without any further
>>>> changes. It also nicely mitigates between towards the different naming
>>>> convention of the accessor methods in records.
>>>
>>> Making a record a bean doesn't worth the pain in my opinion.
>>> Making a record a bean is not free, you have a lot of compatibility tests to pass for mostly no gain.
>>>
>>> A record is not only a class that exposes "properties" like a bean but it's also a class that expose how to marshall/unmarshall itself.
>>> Seeing a record as a bean is likely to not be enough for existing libraries, as you said it will require tweaks.
>>> So you are asking for a kind of compatibility layer that is not enough for most libraries, so either library maintainers will want full support so add more stuffs to the bean spec which is a huge No or will end up by using plain reflection, making the compatibility layer useless.
>>>
>>> We expect library maintainers to be able to directly integrate records quite easily, the fact that you are be able to integrate them in Spring Data confirm that we are on the right track on that point.
>>>
>>>>
>>>> If those PropertyDescriptors were exposed by the reflection APIs in the JDK in
>>>> the first place, other libraries could automatically work with records out of
>>>> the box and would not need similar - or at least less - additional code.
>>>> Jackson, Hibernate, template engines, EL implementations etc.
>>>>
>>>> Slightly less important but still very welcome would be explicit exposure of the
>>>> record constructor so that we don't have to scan and potentially disambiguate
>>>> the one to be used to create instances of those records.
>>>
>>>
>>>
>>>>
>>>> Cheers,
>>>> Ollie
>>>
>>> regards,
>>> Rémi
>>
>
More information about the amber-dev
mailing list