This might be possible, and I just couldn't find the documentation or make it work, but in essence it feels like it should be possible to bind form payloads to a Java 14 record via the constructor
record Greeting(String name){}
@Controller
class GreetingsMvcController {
@PostMapping ("/greetings")
void submit (@ModelAttribute Greeting greeting) {
System.out.println( "the name is " + greeting.name()) ;
}
}
Thanks for your consideration, and I apologize if this has already been solved.
Comment From: odrotbohm
This is a visibility issue because Greeting
is package protected. If you make it public, the binding works as expected. I've previously asked for this in #22600 (this comment in particular).
Comment From: jhoeller
It turns out that this is indeed a visibility issue since the Java compiler generates the implicit record constructor as package-visible if the record type itself is also package-visible. We do not insist on the type itself being public, just on the constructor being public; a custom package-visible data class with a public constructor works fine already.
Since constructor visibility is not specifically declared by the user in case of a record, this is a rather unpleasant case. I've revisited our BeanUtils.getResolvableConstructor
algorithm to keep looking for a single public constructor first, but then in case of no public constructors at all to look for a single non-public constructor with arguments before resorting to a default constructor.
I'll repurpose this issue accordingly. Our general advice remains that record types should be declared public, but anyway, we'll leniently handle such non-public scenarios as of 5.3.11 - for record types as well as custom data classes with a single non-public constructor. That said, method visibility still follows JavaBean setter/getter rules; we're not going to bend those for 5.3.x at all.
Comment From: jhoeller
Addressing this at BeanUtils.getResolvableConstructor
level affects DataClassRowMapper
as well. I'm taking the opportunity to add actual record tests to both spring-webmvc
and spring-jdbc
accordingly (for 6.0 whereas 5.3.x just has tests for record-like custom data classes).