<div dir="ltr">Ok, I've managed to implement a working Babylon-based solution. Here's the library code:<div><br></div><div><div style=""><pre style=""><pre style=""><pre style="color:rgb(8,8,8);font-family:"JetBrains Mono",monospace"><span style="color:rgb(0,66,140);font-weight:bold">package </span><span style="color:rgb(0,0,0)">org.example</span>;<br><br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">jdk.incubator.code.Quoted</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">jdk.incubator.code.</span><span style="color:rgb(51,129,255)">Reflect</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">jdk.incubator.code.dialect.core.CoreOp</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">jdk.incubator.code.dialect.java.JavaOp</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">jdk.incubator.code.dialect.java.MethodRef</span>;<br><br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">java.lang.invoke.MethodHandles</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">java.lang.reflect.Method</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">java.lang.reflect.RecordComponent</span>;<br><span style="color:rgb(0,66,140);font-weight:bold">import </span><span style="color:rgb(0,0,0)">java.util.Arrays</span>;<br><br><span style="color:rgb(0,66,140);font-weight:bold">public final class </span><span style="color:rgb(0,0,0)">ReflectUtil </span>{<br>    <span style="color:rgb(51,129,255)">@Reflect<br></span><span style="color:rgb(51,129,255)">    @FunctionalInterface<br></span><span style="color:rgb(51,129,255)">    </span><span style="color:rgb(0,66,140);font-weight:bold">public interface </span><span style="color:rgb(0,0,0)">RecordAccessor</span><<span style="color:rgb(0,126,138)">T </span><span style="color:rgb(0,66,140);font-weight:bold">extends </span><span style="color:rgb(0,0,0)">Record</span>> {<br>        <span style="color:rgb(140,140,140);font-style:italic">/**<br></span><span style="color:rgb(140,140,140);font-style:italic">         * @param </span><span style="color:rgb(61,61,61);font-style:italic">r </span><span style="color:rgb(140,140,140);font-style:italic">record type<br></span><span style="color:rgb(140,140,140);font-style:italic">         * @return result of the record component<br></span><span style="color:rgb(140,140,140);font-style:italic">         * @param </span><span style="color:rgb(61,61,61);font-style:italic"><R> </span><span style="color:rgb(140,140,140);font-style:italic">an unused generic parameter to avoid accidental use with lambda<br></span><span style="color:rgb(140,140,140);font-style:italic">         *           (lambdas cannot bind to generic SAM). <br></span><span style="color:rgb(140,140,140);font-style:italic">         *           Only method references are supported. <br></span><span style="color:rgb(140,140,140);font-style:italic">         */<br></span><span style="color:rgb(140,140,140);font-style:italic">        </span><<span style="color:rgb(0,126,138)">R</span>> <span style="color:rgb(0,0,0)">Object </span><span style="color:rgb(18,19,20)">get</span>(<span style="color:rgb(0,126,138)">T </span><span style="color:rgb(0,0,0)">r</span>);<br>    }<br><br>    <span style="color:rgb(140,140,140);font-style:italic">/**<br></span><span style="color:rgb(140,140,140);font-style:italic">     * @param </span><span style="color:rgb(61,61,61);font-style:italic">accessor </span><span style="color:rgb(140,140,140);font-style:italic">a method reference bound to a record accessor<br></span><span style="color:rgb(140,140,140);font-style:italic">     * @return record component that corresponds to a given accessor <br></span><span style="color:rgb(140,140,140);font-style:italic">     * @param </span><span style="color:rgb(61,61,61);font-style:italic"><T> </span><span style="color:rgb(140,140,140);font-style:italic">record type<br></span><span style="color:rgb(140,140,140);font-style:italic">     * @throws </span><span style="color:rgb(0,0,0);font-style:italic">IllegalArgumentException </span><span style="color:rgb(140,140,140);font-style:italic">if the supplied argument is not a record accessor method reference<br></span><span style="color:rgb(140,140,140);font-style:italic">     * @throws </span><span style="color:rgb(0,0,0);font-style:italic">RuntimeException </span><span style="color:rgb(140,140,140);font-style:italic">if the record accessor cannot be resolved (e.g., due to insufficient access rights)<br></span><span style="color:rgb(140,140,140);font-style:italic">     */<br></span><span style="color:rgb(140,140,140);font-style:italic">    </span><span style="color:rgb(0,66,140);font-weight:bold">public static </span><<span style="color:rgb(0,126,138)">T </span><span style="color:rgb(0,66,140);font-weight:bold">extends </span><span style="color:rgb(0,0,0)">Record</span>> <span style="color:rgb(0,0,0)">RecordComponent </span><span style="color:rgb(18,19,20)">component</span>(<span style="color:rgb(0,0,0)">RecordAccessor</span><<span style="color:rgb(0,126,138)">T</span>> <span style="color:rgb(0,0,0)">accessor</span>) {<br>        <span style="color:rgb(0,0,0)">Quoted quoted </span>= <span style="color:rgb(0,0,0)">CoreOp</span>.<span style="color:rgb(0,0,0)">QuotedOp</span>.<span style="font-style:italic">ofQuotable</span>(<span style="color:rgb(0,0,0)">accessor</span>)<br>                .orElseThrow(() -> <span style="color:rgb(0,66,140);font-weight:bold">new </span>IllegalArgumentException(<span style="color:rgb(106,132,219);font-weight:bold">"Accessor must be quotable"</span>));<br>        <span style="color:rgb(0,66,140);font-weight:bold">if </span>(!(<span style="color:rgb(0,0,0)">quoted</span>.op() <span style="color:rgb(0,66,140);font-weight:bold">instanceof </span><span style="color:rgb(0,0,0)">JavaOp</span>.<span style="color:rgb(0,0,0)">LambdaOp lambda</span>)) {<br>            <span style="color:rgb(0,66,140);font-weight:bold">throw new </span>IllegalArgumentException(<span style="color:rgb(106,132,219);font-weight:bold">"Expected method reference"</span>);<br>        }<br>        <span style="color:rgb(0,0,0)">JavaOp</span>.<span style="color:rgb(0,0,0)">InvokeOp invokeOp </span>= <span style="color:rgb(0,0,0)">lambda</span>.methodReference()<br>                .orElseThrow(() -> <span style="color:rgb(0,66,140);font-weight:bold">new </span>IllegalArgumentException(<span style="color:rgb(106,132,219);font-weight:bold">"Expected method reference"</span>));<br>        <span style="color:rgb(0,66,140);font-weight:bold">if </span>(<span style="color:rgb(0,0,0)">invokeOp</span>.invokeKind() != <span style="color:rgb(0,0,0)">JavaOp</span>.<span style="color:rgb(0,0,0)">InvokeOp</span>.<span style="color:rgb(0,0,0)">InvokeKind</span>.<span style="color:rgb(0,75,159);font-style:italic">INSTANCE</span>) {<br>            <span style="color:rgb(0,66,140);font-weight:bold">throw new </span>IllegalArgumentException(<span style="color:rgb(106,132,219);font-weight:bold">"Method reference bound to record accessor is expected"</span>);<br>        }<br>        <span style="color:rgb(0,0,0)">MethodRef descriptor </span>= <span style="color:rgb(0,0,0)">invokeOp</span>.invokeDescriptor();<br>        <span style="color:rgb(0,0,0)">Method method</span>;<br>        <span style="color:rgb(0,66,140);font-weight:bold">try </span>{<br>            <span style="color:rgb(0,0,0)">method </span>= <span style="color:rgb(0,0,0)">descriptor</span>.resolveToMethod(<span style="color:rgb(0,0,0)">MethodHandles</span>.<span style="font-style:italic">privateLookupIn</span>(<span style="color:rgb(0,0,0)">accessor</span>.getClass(), <span style="color:rgb(0,0,0)">MethodHandles</span>.<span style="font-style:italic">lookup</span>()));<br>        } <span style="color:rgb(0,66,140);font-weight:bold">catch </span>(<span style="color:rgb(0,0,0)">ReflectiveOperationException e</span>) {<br>            <span style="color:rgb(0,66,140);font-weight:bold">throw new </span>RuntimeException(<span style="color:rgb(106,132,219);font-weight:bold">"Cannot resolve descriptor "</span>+<span style="color:rgb(0,0,0)">descriptor</span>, <span style="color:rgb(0,0,0)">e</span>);<br>        }<br>        <span style="color:rgb(0,0,0)">Class</span><?> <span style="color:rgb(0,0,0)">recordClass </span>= <span style="color:rgb(0,0,0)">method</span>.getDeclaringClass();<br>        <span style="color:rgb(0,66,140);font-weight:bold">if </span>(!<span style="color:rgb(0,0,0)">recordClass</span>.isRecord()) {<br>            <span style="color:rgb(0,66,140);font-weight:bold">throw new </span>IllegalArgumentException(<span style="color:rgb(106,132,219);font-weight:bold">"Not a record accessor method"</span>);<br>        }<br>        <span style="color:rgb(0,66,140);font-weight:bold">return </span><span style="color:rgb(0,0,0)">Arrays</span>.<span style="font-style:italic">stream</span>(<span style="color:rgb(0,0,0)">recordClass</span>.getRecordComponents()).filter(<span style="color:rgb(0,0,0)">rc </span>-> <span style="color:rgb(0,0,0)">rc</span>.getAccessor().equals(<span style="color:rgb(25,72,166)">method</span>))<br>                .findFirst()<br>                .orElseThrow(() -> <span style="color:rgb(0,66,140);font-weight:bold">new </span>IllegalArgumentException(<span style="color:rgb(106,132,219);font-weight:bold">"Not a record accessor: "</span>+<span style="color:rgb(25,72,166)">method</span>));<br>    }<br>}<br></pre><pre style="color:rgb(8,8,8);font-family:"JetBrains Mono",monospace"><span style="color:rgb(34,34,34);font-family:Arial,Helvetica,sans-serif;white-space:normal">It could be used like this:</span></pre><pre style=""><div style=""><pre style="color:rgb(8,8,8);font-family:"JetBrains Mono",monospace"><span style="color:rgb(0,66,140);font-weight:bold">package </span><span style="color:rgb(0,0,0)">org.example</span>;<br><br><span style="color:rgb(0,66,140);font-weight:bold">public class </span><span style="color:rgb(0,0,0)">Main </span>{<br>    <span style="color:rgb(0,66,140);font-weight:bold">private record </span><span style="color:rgb(0,0,0)">MyRecord</span>(<span style="color:rgb(0,66,140);font-weight:bold">int </span><span style="color:rgb(0,75,159)">comp</span>, <span style="color:rgb(0,66,140);font-weight:bold">double </span><span style="color:rgb(0,75,159)">comp2</span>) {}<br>    <br>    <span style="color:rgb(0,66,140);font-weight:bold">static void </span><span style="color:rgb(18,19,20)">main</span>() {<br>        <span style="color:rgb(0,0,0)">IO</span>.<span style="font-style:italic">println</span>(<span style="color:rgb(0,0,0)">ReflectUtil</span>.<span style="font-style:italic">component</span>(<span style="color:rgb(0,0,0)">MyRecord</span>::comp));<br>        <span style="color:rgb(0,0,0)">IO</span>.<span style="font-style:italic">println</span>(<span style="color:rgb(0,0,0)">ReflectUtil</span>.<span style="font-style:italic">component</span>(<span style="color:rgb(0,0,0)">MyRecord</span>::comp2));<br>    }<br>}<br></pre><pre style="color:rgb(8,8,8);font-family:"JetBrains Mono",monospace"><span style="white-space:normal;font-family:Arial,Helvetica,sans-serif;color:rgb(34,34,34)">You have to open your module to code-reflection though:</span></pre><pre style=""><div style="color:rgb(8,8,8)"><pre style="font-family:"JetBrains Mono",monospace"><span style="color:rgb(0,66,140);font-weight:bold">module </span>reflectRecords {<br>    <span style="color:rgb(0,66,140);font-weight:bold">requires </span>jdk.incubator.code;<br>    <span style="color:rgb(0,66,140);font-weight:bold">opens </span><span style="color:rgb(0,0,0)">org.example </span><span style="color:rgb(0,66,140);font-weight:bold">to </span>jdk.incubator.code;<br>}</pre></div></pre></div></pre><pre style=""></pre><pre style="color:rgb(8,8,8);font-family:"JetBrains Mono",monospace"><span style="color:rgb(34,34,34);font-family:Arial,Helvetica,sans-serif;white-space:normal">With best regards, </span></pre><pre style="color:rgb(8,8,8);font-family:"JetBrains Mono",monospace"><span style="color:rgb(34,34,34);font-family:Arial,Helvetica,sans-serif;white-space:normal">Tagir Valeev</span></pre><pre style=""></pre></pre></pre></div></div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Dec 1, 2025 at 3:09 PM Tagir Valeev <<a href="mailto:amaembo@gmail.com">amaembo@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">I don't think there are any published JEPs. Here's some information about the project:<div dir="auto"><a href="https://openjdk.org/projects/babylon/" target="_blank">https://openjdk.org/projects/babylon/</a></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Dec 1, 2025, 15:08 David Alayachew <<a href="mailto:davidalayachew@gmail.com" target="_blank">davidalayachew@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">Understood. Thanks for clarifying. For now, I'll hold off on that, as I don't know how stable that is, and I don't really want to.build this new library off of it. Maybe when the respective JEP goes into preview. Could you link me to that JEP, or is there not one yet?</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Dec 1, 2025, 9:01 AM Tagir Valeev <<a href="mailto:amaembo@gmail.com" rel="noreferrer" target="_blank">amaembo@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">Yes, you have to build it from the Babylon repo.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Dec 1, 2025, 14:35 David Alayachew <<a href="mailto:davidalayachew@gmail.com" rel="noreferrer noreferrer" target="_blank">davidalayachew@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div>Thanks <span class="gmail_chip gmail_plusreply" dir="auto"><a href="mailto:amaembo@gmail.com" style="color:rgb(17,85,204);text-decoration:underline" rel="noreferrer noreferrer noreferrer" target="_blank">@Tagir Valeev</a></span>.<div dir="auto"><br></div><div dir="auto">I am still not great at the stuff Babylon is doing, so I can only roughly follow along. Regardless, it sounds like this is depending on Babylon features which have not yet landed in the mainline jdk, yes?</div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Dec 1, 2025, 5:22 AM Tagir Valeev <<a href="mailto:amaembo@gmail.com" rel="noreferrer noreferrer noreferrer" target="_blank">amaembo@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">I think this will surely be possible for RecordComponents with code reflection (project Babylon), using the syntax you propose.<div><br></div><div>You can create a quotable function like this:</div><div><br></div><div>import jdk.incubator.code.*;</div><div><br></div><div>@Reflect<br></div><div>@FunctionalInterface</div><div>interface Accessor {</div><div>  Object get(Record r);</div><div>}</div><div><br></div><div>Then create something like (just a sketch, sorry, I have no time now to provide a full-fledged sample):</div><div><br></div><div>static RecordComponent foo(Accessor acc) {</div><div>  Quoted q = Op.ofQuotable(acc).orElseThrow();</div><div>  // extract a method handle from q using Babylon API</div><div>  // unreflect it and find the corresponding RecordComponent</div><div>}<br><a class="gmail_plusreply" rel="noreferrer noreferrer noreferrer noreferrer"><br></a></div><div>With best regards,</div><div>Tagir Valeev</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Nov 29, 2025 at 8:45 PM David Alayachew <<a href="mailto:davidalayachew@gmail.com" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">davidalayachew@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello <a class="gmail_plusreply" id="m_-6101997749976919977m_1694487069127859089m_3945911691106319862m_-6545955205200716692m_-5341124393457924939m_2513946637271001261plusReplyChip-2" href="mailto:amber-dev@openjdk.org" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">@amber-dev</a>,</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">I asked this on core-libs-dev already, but I figured I should ask here too.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Let's say I have some record User(String firstName, String lastName) {}.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Is there any possible way for me to do the following?</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">java.lang.reflect.RecordComponent firstName = foo(User::firstName);</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">I'll even accept this.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">java.lang.reflect.Method lastName = foo(User::lastName);</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Thank you for your time and consideration.</div><div class="gmail_default" style="font-family:monospace">David Alayachew</div></div>
</blockquote></div>
</blockquote></div></div></div>
</blockquote></div>
</blockquote></div>
</blockquote></div>
</blockquote></div>