我有一个基于 Spring Web 模型- View - Controller (MVC) 框架的项目。 Spring Web模型- View - Controller (MVC)框架的版本是3.2.8。
这门课
public class DeviceForm {
Device device;
List<String> selectedItems = Collections.emptyList();
public DeviceForm() {
super();
}
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public List<String> getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(List<String> selectedItems) {
this.selectedItems = selectedItems;
}
}
还有这个
public class Device implements java.io.Serializable {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CRITERIA")
private BaseCriteria criteria;
public BaseCriteria getCriteria() {
return criteria;
}
public void setCriteria(BaseCriteria criteria) {
this.criteria = criteria;
}
}
还有这个
@Entity
@Table(name = "CRITERIA")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
@SequenceGenerator(name = "seqCriteria", sequenceName = "SEQ_CRITERIA", allocationSize = 1)
public abstract class BaseCriteria {
public BaseCriteria() {
super();
}
private Long id;
private String code;
private Date adoptionDate;
private Date expirationDate;
@Transient
public abstract String getGroupKey();
@Transient
public abstract Long getGroupId();
@Transient
public abstract String getRefColumnName();
@Id
@Column(name = "ID", unique = true, nullable = true)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqCriteria")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "CODE")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Column(name = "ADOPTION_DATE")
@Temporal(TemporalType.TIMESTAMP)
public Date getAdoptionDate() {
return adoptionDate;
}
public void setAdoptionDate(Date adoptionDate) {
this.adoptionDate = adoptionDate;
}
@Column(name = "EXPIRATION_DATE")
@Temporal(TemporalType.TIMESTAMP)
public Date getExpirationDate() {
return expirationDate;
}
@Transient
public boolean isExpired() {
return getExpirationDate().before(new Date());
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
@Override
public String toString() {
return "BaseCriteria [id=" + id + ", code=" + code + ", adoptionDate="
+ adoptionDate + ", expirationDate=" + expirationDate + "]";
}
}
和 JSP
<form:form commandName="deviceForm"
name="deviceForm"
id="deviceFormId"
method="post"
action="${contextPath}/newdesign/manage/device/${deviceForm.device.id}"
htmlEscape="yes">
<div class="col-sm-6 text-right">
<button class="btn btn-primary" type="submit">Save device</button>
</div>
</div>
<c:forEach items="${deviceForm.device.productGroup.criteria}" var="criteria">
<div class="row">
<div class="col-md-3">
<form:radiobutton path="device.criteria.id" value="${criteria.id}"/>
<label for="basic-url">Criteria:</label>
<input value="${criteria.code}" disabled="disabled" class="form-control"/>
</div>
<div class="col-md-3">
<label for="basic-url">Adoption date:</label>
<input value="<fmt:formatDate type="date" value="${criteria.adoptionDate}" />" disabled="disabled" class="form-control"/>
</div>
<div class="col-md-3">
<label for="basic-url">Expiration Date:</label>
<input value="<fmt:formatDate type="date" value="${criteria.expirationDate}" />" disabled="disabled" class="form-control"/>
</div>
</div>
</c:forEach>
</form:form>
Controller :
/**
* @throws Exception
*
*/
@RequestMapping(value = { "/newdesign/manage/device/{appId}",
"/newdesign/manage/device/{appId}/"}, method = {RequestMethod.GET})
public String viewDevicesWithStatus(
@ModelAttribute("deviceForm") DeviceForm deviceForm,
@PathVariable Long appId,
HttpServletRequest request,
Model model ) throws Exception {
Device device = manageLicenseService.getDeviceById(appId, true);
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
deviceForm.setDevice(device);
fillModel (model, request, device);
return "cbViewDeviceInfo";
}
/**
* @throws Exception
*
*/
@RequestMapping(value = { "/newdesign/manage/device/{appId}",
"/newdesign/manage/device/{appId}/"}, method = {RequestMethod.POST})
public String saveDevicesWithStatus(
@ModelAttribute("deviceForm") DeviceForm deviceForm,
@PathVariable Long appId,
HttpServletRequest request,
Model model ) throws Exception {
Device device = manageLicenseService.getDeviceById(deviceForm.getDevice().getId());
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
//TODO: audit
device.updateDevice(deviceForm.getDevice());
manageLicenseService.saveDevice(device);
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
deviceForm.setDevice(device);
fillModel (model, request, device);
return "cbViewDeviceInfo";
}
但是当我提交表单时出现以下错误,在 GET 方法上我得到了相同的页面而没有错误
org.springframework.beans.NullValueInNestedPathException: Invalid property 'device.criteria' of bean class [com.tdk.iot.controller.newdesign.manage.DeviceForm]: Could not instantiate property type [com.tdk.iot.domain.criteria.BaseCriteria] to auto-grow nested property path: java.lang.InstantiationException
最佳答案
你得到错误是因为在你的表单中有这个:
<form:radiobutton path="device.criteria.id" value="${criteria.id}"/>
在你的 POST 处理程序中你有这个:
public String saveDevicesWithStatus(@ModelAttribute("deviceForm") DeviceForm deviceForm){
}
这意味着 MVC 框架将尝试自动设置属性
deviceForm.device.criteria.id。
现在,因为在任何范围内都没有现有的 DeviceForm,所以它将创建一个新的,当然 device.getCriteria() 返回 null,
因此异常(exception)。
您可能认为您在 GET 处理程序中创建并填充的 DeviceForm 将被使用,但是 Spring MVC 是无状态的,因此您 需要将其存储在请求之间的 session 范围内,以便重新使用或以其他方式修改您的逻辑。
.... Given the above example where can theinstance come from? There are several options.....[in the absence of any other option] It may be instantiated using its default constructor
然而,更好的方法是将您的表单更改为如下所示:
<form:radiobutton path="device.criteria" value="${criteria.id}"/>
并注册一个转换器来转换提交的参数并绑定(bind)相应的实体实例。
@Component
public class StringToCriteriaConverter implements Converter<String, BaseCriteria> {
@Autowired
private CriteriaService service;
//source is the ID passed by the page
public BaseCriteria convert(String source) {
// lookup and return item with corresponding ID from the database
}
}
关于java - org.springframework.beans.NullValueInNestedPathException : auto-grow nested property path in Spring MVC 3. 2.8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41570626/