我正在使用新的Java 14和Spring Boot。我使用了新的Cool Record,而不是用于数据持有者的常规Java类。
public record City(Long id, String name, Integer population) {}
在我的服务类的后面,我使用SpringBeanPropertyRowMapper
来获取数据。
@Override
public City findById(Long id) {
String sql = "SELECT * FROM cities WHERE id = ?";
return jtm.queryForObject(sql, new Object[]{id},
new BeanPropertyRowMapper<>(City.class));
}
我最后出现了以下错误:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zetcode.model.City]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.zetcode.model.City.<init>()
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:145) ~[spring-beans-5.2.3.RELEASE.jar:5.2.3.RELEASE]
如何为记录添加默认构造函数,或者是否有其他方法可以修复此问题?
2条答案
按热度按时间x33g5p2x1#
只需通过为字段提供默认值来显式声明它:
一个重要的注解。BeanPropertyRowMapper扫描setters/getters来膨胀您的Record示例,因为Record是不可变的,没有setter,并且与Java Beans规范不兼容,您会得到并空Record。请阅读这篇SO。创建记录的唯一方法是使用构造函数。因此,您有两个选择:要么使用纯Java Bean,要么实现定制的行Map器。
它看起来最简单的方式是:
或者,您可以使用reflection:
反射API
以下公共方法将添加到java.lang.Class中:
方法getRecordComponents()返回一个由java.lang.refect.RecordComponent对象组成的数组,其中的java.lang.refirect.RecordComponent是一个新类。此数组的元素与记录的组件相对应,顺序与它们在记录声明中出现的顺序相同。可以从数组中的每个RecordComponent中提取其他信息,包括其名称、类型、泛型类型、注解及其访问器方法。
如果给定类被声明为记录,则方法isRecord()返回TRUE。(请比较isEnum()。)
使用这些方法和类#getConstructor(类...参数类型)和构造函数#newInstance(对象...Initargs),您可以动态创建记录。但要记住,反思可能会带来一些开销,并影响你的表现。
我添加了一个使用反射的RecordRowMapper示例和几个tests:
cxfofazt2#
您可以使用DataClassRowMapper。它可以很好地处理唱片。