<div dir="ltr">There is a parallel thread going on which touches on similar things - there people are wanting "record component references." <br><br>I adapted the code from <a href="https://github.com/rilindbicaj/fluentmapper/blob/main/fluentmapper-provider/src/main/java/dev/bici/fluentmapper/provider/expression/parser/ExpressionParser.java">https://github.com/rilindbicaj/fluentmapper/blob/main/fluentmapper-provider/src/main/java/dev/bici/fluentmapper/provider/expression/parser/ExpressionParser.java</a> to use the new classfile api + work for a quick demo of the approach.<br><br>Basically, you can get at the code in the body of a lambda via some serialization hackery. The degree to which this is actually supported is to me unknown.<br><br><font face="monospace">import java.io.IOException;<br>import java.io.Serializable;<br>import java.io.UncheckedIOException;<br>import java.lang.classfile.ClassFile;<br>import java.lang.classfile.ClassModel;<br>import java.lang.classfile.instruction.FieldInstruction;<br>import java.lang.invoke.SerializedLambda;<br>import java.lang.reflect.Field;<br>import java.util.ArrayList;<br>import java.util.List;<br><br>public final class FieldReference {<br>    private final Class<?> root;<br>    private final List<Field> fields;<br><br>    private FieldReference(Class<?> root, List<Field> fields) {<br>        this.root = root;<br>        this.fields = fields;<br>    }<br><br><br>    public Class<?> root() {<br>        return root;<br>    }<br><br>    public List<Field> fields() {<br>        return fields;<br>    }<br><br>    private static SerializedLambda toSerializedLambda(Expression<?, ?> expression) {<br>        try {<br>            var writeReplaceMethod = expression.getClass().getDeclaredMethod("writeReplace");<br>            writeReplaceMethod.setAccessible(true);<br><br>            return (SerializedLambda) writeReplaceMethod.invoke(expression);<br>        } catch (ReflectiveOperationException e) {<br>            throw new IllegalArgumentException("Could not extract SerializedLambda from the provided expression;", e);<br>        }<br>    }<br><br>    public static <T> FieldReference of(Class<T> klass, Expression<T, ?> expression) {<br>        // TODO: This work can likely be cached.<br>        var serializedLambda = toSerializedLambda(expression);<br>        var containingClass = serializedLambda.getImplClass();<br>        var lambdaSignature = serializedLambda.getImplMethodName();<br><br>        // TODO: Unsure if this is the right class loader to use<br>        var classLoader = klass.getClassLoader();<br><br>        byte[] classBytes;<br>        try (var classResource = classLoader.getResourceAsStream(<br>                containingClass.replace('.', '/') + ".class"<br>        )) {<br>            if (classResource == null) {<br>                throw new IllegalArgumentException("Could not find class-file resource in class loader");<br>            }<br><br>            classBytes = classResource.readAllBytes();<br>        } catch (IOException e) {<br>            throw new UncheckedIOException(e);<br>        }<br><br>        ClassModel classModel = ClassFile.of().parse(classBytes);<br><br>        var methodModel = classModel.methods().stream()<br>                .filter(method -> lambdaSignature.equals(method.methodName().toString()))<br>                .findFirst()<br>                .orElseThrow(() -> new IllegalArgumentException("Could not find the implementing method for the expression lambda"));<br>        var code = methodModel.code().orElseThrow();<br><br>        // TODO: This could use a lot of prechecks<br>        var fields = new ArrayList<Field>();<br><br>        Class<?> lastType = klass;<br>        for (var element : code.elementList()) {<br>            if (element instanceof FieldInstruction fieldInstruction) {<br>                try {<br>                    fields.add(<br>                            lastType.getDeclaredField(fieldInstruction.field().name().toString())<br>                    );<br><br><br>                    // TODO: This is almost certainly not sound<br>                    if (fieldInstruction.typeSymbol().packageName().isEmpty()) {<br>                        lastType = classLoader.loadClass(<br>                                fieldInstruction.typeSymbol().displayName()<br>                        );<br>                    }<br>                    else {<br>                        lastType = classLoader.loadClass(<br>                                fieldInstruction.typeSymbol().packageName() + "."<br>                                        + fieldInstruction.typeSymbol().displayName()<br>                        );<br>                    }<br><br>                } catch (NoSuchFieldException e) {<br>                    throw new IllegalArgumentException("Inaccessable field", e);<br>                } catch (ClassNotFoundException e) {<br>                    throw new RuntimeException(e);<br>                }<br>            }<br>        }<br><br><br>        return new FieldReference(klass, List.copyOf(fields));<br>    }<br><br><br>    @FunctionalInterface<br>    public interface Expression<A, B> extends Serializable {<br>        B get(A a);<br>    }<br><br><br>    @Override<br>    public String toString() {<br>        return "FieldReference[" +<br>                "root=" + root.getName() +<br>                ", fields=" + fields.stream().map(Field::getName).toList() +<br>                ']';<br>    }<br>}<br></font><br>And you can use all of that with a lambda that only accesses fields to emulate "field references." <br><br><font face="monospace">class A {<br>    String aa;<br>    B b;<br>}<br><br>class B {<br>    C c;<br>}<br><br> class C {<br>    String v;<br>    D d;<br>}<br><br> class D {<br>    E e;<br>}<br><br> class E {<br>    F f;<br>}<br><br> class F {<br>    G g;<br>}<br><br> class G {<br>    String v;<br>}<br><br>public class Test {<br>    public static void main(String[] args) {<br>        var refA = FieldReference.of(A.class, a -> a.aa);<br>        IO.println(refA);<br>        var refB = FieldReference.of(A.class, a -> a.b.c.d);<br>        IO.println(refB);<br>    }<br>}<br></font><br><font face="monospace">FieldReference[root=A, fields=[aa]]<br>FieldReference[root=A, fields=[b, c, d]]</font><div><font face="monospace"><br></font></div><div><font face="arial, sans-serif">So that is one approach to look into. </font></div></div><div dir="auto"><div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Dec 1, 2025, 8:38 PM Bruno Eberhard <<a href="mailto:bruno.eberhard@pop.ch" target="_blank">bruno.eberhard@pop.ch</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">Am 01.12.2025 um 22:00 schrieb Ethan McCue:<br>
> On that note, i'd say you have somewhat of a bigger problem w.r.t. enums<br>
> [..]<br>
> As with all things in jdk.unsupported, I can't help but wonder if there <br>
> are any VM level invariants you run afoul of by making extra enum <br>
> instances. <br>
<br>
I don't know about the VM internals. I did never run into problems with <br>
these extra enums.<br>
<br>
> My first stab at #2 is to add something like this record [..]<br>
Thank you for your input. I have to try this.<br>
<br>
> I think it's also worth asking - do you have any usage statistics on <br>
> your library? (Maven central used to offer download stats, etc.) If you <br>
> are going to be broken anyways it is probably useful to know the blast <br>
> radius.<br>
<br>
Very good point. As far as I know minimal-j is only used by me for a <br>
smaller and one bigger App. In the bigger App ( An ERP called <br>
<a href="http://lisheane.ch" rel="noreferrer noreferrer" target="_blank">lisheane.ch</a> , currently only available in german ) I invested quite some <br>
time. I would have to rewrite parts of it.<br>
<br>
So the world will not be standing still if minimal-j doesn't work <br>
anymore or has to be changed.<br>
<br>
I would still like the idea of field references ( Person::name , <br>
Person::address::city ) in the java language as equivalent for the $ <br>
constant. It is really nice to use. But I don't have the knowledge how <br>
to add it to the language or how to propose the feature.<br>
</blockquote></div></div></div>