One more question: How does the code today work around things like the small integer cache?
On Mon, Dec 1, 2025 at 2:04 PM Ethan McCue <[email protected]> wrote: > Can you elaborate more on how form.line($.address.city); uses the > identity of city? > > How does Backend.find(Person.class, By.field($.address.zip, 8000)); figure > out that $.address.zip refers to the corresponding field in Address? > > On Mon, Dec 1, 2025 at 1:56 PM Remi Forax <[email protected]> wrote: > >> ----- Original Message ----- >> > From: "Bruno Eberhard" <[email protected]> >> > To: "valhalla-dev" <[email protected]> >> > Sent: Wednesday, November 26, 2025 10:43:30 AM >> > Subject: Valhalla breaks minimal-j framework >> >> > Hi, >> > >> > I really like the concepts and the gains you make with Valhalla. But it >> > breaks some essential points of my framework called «minimal-j» (on >> > https://github.com/BrunoEberhard/minimal-j ). I would kindly ask if you >> > can provide a replacement for what is not possible in Valhalla anymore. >> > >> > Let me show the problem and then propose a solution. In the minimal >> > design all fields of a class representing a business entity (only those) >> > are public. No getter or setter. Then a static constant $ is defined >> > like this: >> > >> > public class Person { >> > public static final Person $ = Keys.of(Person.class); >> > >> > @NotEmpty >> > public Integer number; >> > >> > @Size(100) >> > @Searched >> > @NotEmpty >> > public String name; >> > >> > public final Address address = new Address(); >> > } >> > >> > With the $ constant there is a reference to the fields of the class. >> > With theses references a UI can be specified: >> > >> > var form = new Form<Person>(); >> > form.line($.number); >> > form.line($.name); >> > form.line($.address.city); >> > >> > Or a query to the persistence layer can be formulated: >> > >> > Backend.find(Person.class, By.field($.name, "Bruno")); >> > Backend.find(Person.class, By.field($.address.zip, 8000)); >> > >> > In the background the framework fills the fields of the $ constant with >> > values that are later used to identify which field should be used. For >> > this identity is vital. Things like "new String(..)" and "new >> > Integer(..)" is used to make $.number unique. >> > >> > If Integers loose their identity this is now longer feasable. >> > >> > A possible replacement for this trick would be references to fields. >> > Best in this way: >> > >> > Backend.find(Person.class, By.field(Person::name, "Bruno")); >> > >> > Person::name should result in a java.lang.reflect.Field >> > >> > Backend.find(Person.class, By.field(Person::address::zip, 8000)); >> > >> > Here Person::address::zip should result in a java.lang.reflect.Field[] >> > or in a new class containing chained Fields. >> > >> > Of course I could instead write getter and setter and the use >> > Person::getName . But Person::getAddress::getZip doesn't work. And I >> > would really like not to have getter and setter (for which I have to >> > check all names and parameters are correct). Lombok or Kotlin hide >> > getter and setter. But I don't really like hiding something. Especially >> > if it is not really needed. >> > >> > So if it is possible to add this construct to the java language it would >> > make me really happy. Otherwise I would never be able to use a Java >> > version which contains Valhalle for this kind of framework. >> >> Integers, and others are marked as value-based classes >> ( >> https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/doc-files/ValueBased.html >> ) >> since quite some time, so your framework is currently violating this >> non-enforced spec. >> >> I don't blame you, not at all, i've done the same in ASM at some point in >> time, but we have to fix the errors of the past ; Integer should be a >> lightweight boxing with no identity guarantee ; because it improve 99.9% of >> the existing codes. >> >> I've seen a mocking framework having the same issue a lot time ago before >> and after Integers where cached. >> >> They moved to a representation using interfaces + dynamic proxies instead >> of classes. >> >> public interface Person { >> public static final Person $ = Keys.of(Person.class); >> >> @NotEmpty >> public int number(); >> >> @Size(100) >> @Searched >> @NotEmpty >> public String name(); >> >> public final Address address(); >> } >> >> with the information being stored out of the line in ThreadLocal (I >> believe you can now use ScopeValue for that) >> instead of using a special return value. >> >> On the positive side, you do not have to use Integer anymore, you can use >> int (see numbers()), >> on the negative side, it's obviously not backward compatible with your >> existing framework. >> >> > >> > regards >> >> regards, >> Rémi >> >
