Constructing records through reflection and module restrictions

Brian Goetz brian.goetz at oracle.com
Mon Dec 9 15:39:02 UTC 2024


There is a better approach than passing around the Lookup (which 
requires everyone to coordinate around the Lookup capability): use open 
modules.  THe concept of "open module" was designed for exactly this 
purpose: to allow packages to be "exported for reflection" so that 
frameworks can reflect over them more liberally than bytecode linkage 
would permit.  If you put your domain objects in a package that is 
opened (either to the framework, or to everyone), no need to play games 
with Lookup.


On 12/8/2024 11:52 AM, Florian Weimer wrote:
> * 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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20241209/4585a171/attachment.htm>


More information about the amber-dev mailing list