Java records private constructor with builder [duplicate]

Solution 1:

Q: Why does this restriction exist for records?

There isn't an explicit justification for that decision in JEP 359 or in the JLS, but I think it is implied by this excerpt from the JEP:

"Because records make the semantic claim of being transparent carriers for their data ..."

A "transparent carrier" means (to me1) that records are designed to have a minimal abstraction boundary. Restricting the access of a constructor implies (to me) an additional abstraction boundary.

In addition, I suspect that record constructors with more restrictive access modifiers could impede or complicate intended use-cases for records in future versions of Java.

Anyway, my take is that if you want fancy stuff like that you should be declaring a class rather than a record.

1 - Transparent is the opposite of opaque, and abstract data types are typically opaque by design. Obviously, this is just my take on what the JEP authors meant.


Q: Are there any plans to remove this restriction in the future?

I am not aware of any. There are no (public) open Java Bugs or RFEs about this.

Indeed, all of the JDK bugs relating to this topic were to ensure that the Java 15+ specifications made the restriction clear. There is no suggestion that the restriction happened by accident or oversight.

Solution 2:

I asked the question on the amber mailing list (http://mail.openjdk.java.net/pipermail/amber-dev/2020-December.txt).

The question was posed:

What exactly is the reason that the canonical constructor must have the same access as the record?

And the answer given was (emphasis added mine):

Records are named tuples, they are defined only by their components, in a transparent manner i.e. no encapsulation. From a tuple, you can access to the value of each component and from all component values, you can create a tuple. The idea is that, in a method, if you are able to see a record, you can create it. Thus the canonical constructor has the same visibility as the record itself.

So the restriction exists to comply with the design goal and fact that if someone has an instance of a record they should be able to deconstruct it and then reconstruct it with the canonical constructor. And of course as a corollary this necessitates the canonical constructor having the same access as the record itself.