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