java - 使用包装对象时出现异常
问题描述
我无法进行以下工作。
我有一个使用 Thymeleaf 和 Spring MVC 的“工作”Spring Boot 应用程序。当我尝试将请求发送回服务器时,它会引发以下错误:
Internal Server Error
java.lang.IllegalStateException: Default value must not be null
at org.springframework.util.Assert.state(Assert.java:73)
at org.springframework.beans.AbstractNestablePropertyAccessor.setDefaultValue(AbstractNestablePropertyAccessor.java:873)
at org.springframework.beans.AbstractNestablePropertyAccessor.getNestedPropertyAccessor(AbstractNestablePropertyAccessor.java:842)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyAccessorForPropertyPath(AbstractNestablePropertyAccessor.java:816)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyAccessorForPropertyPath(AbstractNestablePropertyAccessor.java:817)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyHandler(AbstractNestablePropertyAccessor.java:724)
at org.springframework.beans.AbstractNestablePropertyAccessor.isWritableProperty(AbstractNestablePropertyAccessor.java:562)
at org.springframework.web.bind.WebDataBinder.checkFieldMarkers(WebDataBinder.java:242)
at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:196)
at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:107)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:157)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:160)
我已经尝试调试它,几个小时,但我无法弄清楚我错过了什么。使用下面的结构,它不起作用,使用没有字段包装类的列表(另见下文),例如private List<DTO> dtoList = new ArrayList<>();
它起作用。我在最后描述了我的一些尝试。
我的结构:
使用片段的模板表行:
<tr th:each="pac,i : *{dtoList}">
<div th:include="details/frag :: table_check('dtoList', 'approval', true)"></div>
</tr>
百里香片段frag.html:
<th:block th:fragment="table_check (list, field, wrapped)">
<td>
<div class="custom-control custom-checkbox">
<input th:field="*{__${list}__[__${i.index}__]__${wrapped ? '.currentValue':''}__.__${field}__}"
type="checkbox" class="custom-control-input" th:id="|${list}_${field}_${i.index}|">
<th:block th:if="${wrapped}">
<input th:field="*{__${list}__[__${i.index}__].originalValue.__${field}__}" type="hidden">
</th:block>
<label class="custom-control-label" th:for="|${list}_${field}_${i.index}|"></label>
</div>
</td>
</th:block>
特殊领域类
public class SpecialField extends BasicField<DTO> {
public SpecialField() {
}
public SpecialField(DTO value, boolean changeable) {
super(value, changeable);
}
public SpecialField(DTO value) {
super(value);
}
@Override
public boolean hasChanged() {
//some code to check this
return false;
}
}
BasicField类_
public abstract class BasicField<T> implements Field<T> {
protected boolean changeable = false;
@DateTimeFormat(pattern = YYYY_MM_DD)
protected T originalValue;
@DateTimeFormat(pattern = YYYY_MM_DD)
protected T currentValue;
public BasicField() {
}
protected BasicField(T value, boolean changeable) {
this.originalValue = value;
this.currentValue = value;
this.changeable = changeable;
}
protected BasicField(T value) {
this.originalValue = value;
this.currentValue = value;
}
// getter and setter though one is special
public void setCurrentValue(T value) {
if (isChangeable()) {
currentValue = value;
}
}
public boolean isChangeable() {
return changeable;
}
}
DTO类_
public class DTO extends AbstractDto {
private boolean approval;
// getter and setter
}
包含 dtoList 的类
@Validated
public class BaseDTO extends AbstractDTO {
private List<SpecialField> dtoList = new ArrayList<>();
// getter and setter
}
我的控制器类(其实我不会走到这一步)
@RequestMapping(value = "/details", params = { "update" })
public ModelAndView update(final @Valid @ModelAttribute(name = "baseDto") BaseDto baseDto,
final BindingResult bindingResult, WebRequest request, final Model model) {
//do smth
}
尝试修复:
- 我尝试使用默认值设置@Value Annotation,但无法弄清楚如何设置默认对象。
- 我尝试了一种通用方法(ListField T 是 BaseDto 而不是 SpecialField),但得到了 ArrayIndexOutOfBoundsException,因为我的 List 被初始化为一个空的 ArrayList,至少没有一个条目。
- 我试图删除片段模板,但仍然得到错误
我想这是一件非常微不足道的事情,但我在这里不知所措。
解决方案
我找到了处理它的方法。我替换了默认的 BasicField 构造函数
public BasicField() {}
和
public BasicField(Supplier<T> supplier) {
this.supplier = supplier;
this.originalValue = supplier.get();
this.currentValue = supplier.get();
}
并相应地调整了 SpecialField 构造函数
public SpecialField() {
super(DTO::new);
}
因此,如果我需要 originalValue 和 currentValue 可以有新的实例,如果没有,则没有。肯定有更好的解决方案,但它是一种方式。
推荐阅读
- java - 如何根据用户输入从数组中删除元素?
- javascript - fetch delete 一直被视为获取
- reactjs - 无法创建 React 应用程序,因为 NPM “无法解析依赖树”
- c - 使用 c 脚本将存储在变量中的数据插入 Postgres 数据库表
- css - 如何使用 Angular 在 Tailwind(深色模式)中切换主题?
- algorithm - 混合 A* 算法与 A* 算法,两者在伪代码中有什么区别
- python - 运行 streamlit hello 后访问被拒绝
- reactjs - 错误:元素类型无效:需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)react-native
- python - 从 Python 中的小样本中识别自然语言
- python - 对 django rest framework social oauth2 的 TokeView 的串行请求导致错误