Reflection on records

Brian Goetz brian.goetz at oracle.com
Mon Dec 1 18:37:56 UTC 2025


Let me replay some analysis that was done on this topic in the past.

There are two separate things going on here:

 - Can we use symbolic constants instead of string constants to do reflective lookups
 - Can we have more kinds of symbolic reflective constants (field literals, method literals, record component literals, method handle literals, etc.)

The first one is more shallow; David is exploiting a special case of records where (a) there is already a method reference form for accessors, which could potentially be bootstrapped into service here and (b) very luckily, the shape of all such accessor method references vary only parametrically in shape.  So one could write a method:

    interface AccessorShape<T, U> {
        U access(T t);
    }

    <R extends Record, U> RecordComponent component(Accessor<R, U> c) { … }

Which would allow us to say

    RecordComponent rc = component(Foo::component)

Where the parameter is a method reference but from which we can strip-mine the name and type and turn it into a component lookup.  That’s a clever trick, and there is no intrinsic reason why we couldn’t do this, but it doesn’t scale beyond this particular case.  Field and method lookups would still use strings and could fail at runtime for all the reasons.

The second is one that was explored fairly deeply during Lambda.  Reflective literals for jlr.{Field,Method,Constructor} are an obvious move, and have a few challenges, some of which are workable, but the biggest of which is: overloading.  With method reference targeted at functional interfaces, the functional interface provides a signature shape with which we can do overload selection.  But if we had an overloaded method m, then

    Method m = Foo::m

We have no information with which to select the proper m.  (Please, don’t take this as an invitation for a syntax discussion; they’ve all been explored, and besides, there are deeper problems here than syntax.)


On Dec 1, 2025, at 12:13 PM, Archie Cobbs <archie.cobbs at gmail.com<mailto:archie.cobbs at gmail.com>> wrote:

I'm guessing what underlies David's question is this thought: Why can't the compiler provide more compile-time checking of Field and Method reflection objects?

After all, it does this for Class objects by providing us with Class literals (remember in the old days you could only obtain them via Class.forName()).

I have wondered the same thing, though I also appreciate that the devil is in the details.

For example, David's question could be addressed by adding Method and Field literals:

public class Foo {
    public static void meth(int x) { ... }
}

Method m = Foo::meth.method;
m.invoke(123);

Of course, this is still imprecise because Method is not generic and so this would fail if there were overloads, among other problems.

So I think the intuition is valid. Whether a practical solution exists is another question.

-Archie

On Mon, Dec 1, 2025 at 10:46 AM Chen Liang <chen.l.liang at oracle.com<mailto:chen.l.liang at oracle.com>> wrote:
Hi David, before we investigate solutions, what is the problem you want to resolve?
If you want to obtain a Method on a record class, you can do recordClass.getMethod("variable") to find that accessor method.
Note that the Java Virtual Machine does not validate a record, that it may recognize a class with the record attribute but has no corresponding accessor methods or canonical constructor as a record class.
--
Archie L. Cobbs

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20251201/af8bc988/attachment-0001.htm>


More information about the amber-dev mailing list