【问题标题】:Exception when using wrapper object使用包装对象时出现异常
【发布时间】:2020-05-19 16:54:26
【问题描述】:

我无法使以下工作正常进行。

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

我已经尝试调试它,几个小时,但我无法弄清楚我错过了什么。使用下面的结构,它不起作用,使用没有 Field Wrapper Class 的列表(另见下文)例如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>

SpecialField 类

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,至少没有一个条目。
  • 我尝试删除片段模板,但仍然出现错误

我想这是非常琐碎的事情,但我在这里不知所措。

【问题讨论】:

    标签: java spring-boot spring-mvc thymeleaf


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-06
      • 1970-01-01
      • 2020-08-19
      • 1970-01-01
      • 2012-10-17
      • 2015-03-20
      • 2011-10-24
      • 1970-01-01
      相关资源
      最近更新 更多