Constructing records through reflection and module restrictions

Florian Weimer fw at deneb.enyo.de
Sun Dec 8 16:52:42 UTC 2024


* Remi Forax:

>> Syntax-wise, it is very tempting to use this with very localized
>> record types for various kinds of custom deserialization scenarios.
>> For example, to read a CSV file with two colums, something like this
>> could be used:
>> 
>>            record Row(String name, int index) {}
>>            var csv = CSVReader.newReader(r, Row.class);
>>            while (true) {
>>                var row = csv.readRow();
>>                if (row == null)
>>                    break;
>>                // Use the row variable.
>>                ...
>>            }
>> 
>> But it would equally work for SQL result set rows, binary structures,
>> and so on.
>
> Why not sending the lookup object here :
>
> var csv = CSVReader.newReader(r, Row.class, MethodHandles.lookup());

Thanks.  Not surpringly, this works for constructor access.  It should
help with using defineHiddenClass() as well if I read the
documentation correctly (although maybe I can get what I want just
using method handles).  Syntax-wise, I think it's okay, although it
will certainly look like magic to newcomers if this programming
pattern ever catches on (and similarly in other APIs that use
reflective access behind the covers).  But from a conceptual
perspective, it's really clear.

It appears that MethodHandles.lookup() uses an intrisified
getCallerClass(), so it's probably not necessary to turn this into
MethodHandles::lookup, to the lookup when it is not needed.

>> I think some people use interfaces and java.lang.reflect.Proxy for a
>> similar purpose, hoping that method declaration order matches
>> reflection order (not a good idea, I know).  As far as I can see, the
>> proxy mechanism does not perform a module encapsulation check and can
>> create instaces at points where a regular class declaration with an
>> implements clause could not reference to the interface.  Records would
>> be a better replacement because they provide ordering of components.
>
> If you use an abstract deconstructors/pattern method, you get the declaration order
>
>   interface Row {
>     abstract deconstructor (String name, int index) Row();   // or a similar syntax
>   }
>
>   ...
>   Row(var name, var index) = csv.readRow(); 
>   // use name and index here
>
> and i suppose that j.l.r.Proxy will be updated to implement such pattern.

Is this already under discussion somewhere?  I've seen some references
to generalizing pattern matching to custom types, but nothing along
what you describe.


More information about the amber-dev mailing list