Feedback for records: Accessors name() vs. getName()

Kamil Ševeček kamil at sevecek.net
Wed Aug 5 12:51:52 UTC 2020


Hello

I tried the Java 14 records preview feature in a number of technologies and
found many quirks with accessors not following JavaBeans convention of
getName() for fields.

Some examples
=============
Let's say we have Invoice and Address classes and Customer record:
~~~
public class Invoice {

    private Customer c;

    public Invoice(Customer c) {
        this.c = c;
    }

    public Customer getCustomer() {
        return c;
    }

    // equals() & hashCode() & toString()
}

public record Customer(String firstName, String lastName, Address address)
{ }

public class Address {

    private String city;

    public Address(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    // equals() & hashCode() & toString()
}
~~~

Let's have:
~~~
Address adr = new Address("Brno");
Customer c1 = new Customer("Jack", "Sparrow", adr);
Invoice inv = new Invoice(c1);
~~~


1. java.beans.Introspector not recognizing accessors
----------------------------------------------------
Let's have:
~~~
BeanInfo personBeanInfo = Introspector.getBeanInfo(Customer.class);
for (PropertyDescriptor desc : personBeanInfo.getPropertyDescriptors()) {
    System.out.println(desc.getName() + " <- " +
desc.getReadMethod().getName() + "()");
}
~~~

You will only get:
~~~
class <- getClass()
~~~
and miss firstName(), lastName() and address().

I was able to find this email (
https://mail.openjdk.java.net/pipermail/amber-dev/2020-January/005479.html)
regarding the same issue but the only thing I could see was a proposal to
shoehorn Introspector to recognize records instead of making records
standards-compliant and not having changing anything in the APIs above
java.lang.


2. Unified expression language (EL) in JSP, JSF
--------------------------------------------------------------
Web expression language will look quite weird as well (address() method
versus customer and city properties):

${inv.customer.address().city}


3. Spring Framework hacks, Spring (SpEL)
----------------------------------------
The same email (
https://mail.openjdk.java.net/pipermail/amber-dev/2020-January/005479.html)
also mentioned that Spring would have to come with hacks to allow for
records.

Spring Expression Language (SpEL) would be affected the same way as
UnifiedEL.
${inv.customer.address().city}


3. Groovy inconsistency
-----------------------
You can access getName() getters in Groovy using short syntax:
~~~
inv.customer.address().city
~~~

4. Kotlin inconsistency
-----------------------
The same as in Groovy also applies to Kotlin:
~~~
inv.customer.address().city
~~~


5. All libraries will have to be adapted
----------------------------------------
There are a lot of libraries that depend on the get/set convention and you
would prevent their usage for records. Such as BeanTableModel (swing
TableModel implementation), Jackson JSON parser and many others.


6. Impossibility to retrofit existing record-like classes as records
---------------------------------------------------------------------
https://mail.openjdk.java.net/pipermail/amber-dev/2020-April/005900.html
"records alone don't hit enough targets in my opinion"
There are a lot of existing classes which have only JavaBeans-compliant
getters, equals() & hashCode() in the JDK library and in the wold. Far more
than non-compliant getters. Many of them could have been rewritten as
records if records followed the getName() strategy.

---

I went through the Amber-dev mailing list, read quite a few articles by
Brian Goetz but never came across any reasoning why the accessors would be
name() and not something else.
Are there any benefits of using name() accessors?
Overall, I would strongly suggest generating getters in compliance with 22
years of practice in Java and avoid introducing a new kid on the block.

Regards
Kamil Sevecek


More information about the amber-dev mailing list