首页 > 解决方案 > 使用包装对象时出现异常

问题描述

我无法进行以下工作。

我有一个使用 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
}

尝试修复:

我想这是一件非常微不足道的事情,但我在这里不知所措。

标签: javaspring-bootspring-mvcthymeleaf

解决方案


我找到了处理它的方法。我替换了默认的 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 可以有新的实例,如果没有,则没有。肯定有更好的解决方案,但它是一种方式。


推荐阅读