2017-01-10 109 views
6

私は、Spring Web Model-View-Controller(MVC)フレームワークに基づくプロジェクトを持っています。 Spring Web Model-View-Controller(MVC)フレームワークのバージョンは3.2.8です。org.springframework.beans.NullValueInNestedPathException:Spring 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> 

コントローラ:私はGETメソッドで、フォームを送信したときに、私はエラーを次しまった

/** 
    * @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";  
    } 

しかし、私はエラーなしで同じページを持っ

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 

答えて

0

フォームであなたがこれを持っているので、あなたがエラーを取得します:

<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()はヌルを返します。したがって、例外は です。

GETハンドラで作成して埋め込んだDeviceFormが使用されますが、Spring MVCはステートレスですので、 はセッションスコープ内にセッションスコープに格納して再利用する必要があります。論理。

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args

....から来るtheinstanceことができ、上記の例を考えると? は、いくつかのオプションは、それがデフォルトコンストラクタより良いアプローチは、しかし、以下のようになるためにあなたのフォームを変更することです

を使用してインスタンス化することが も[他のオプションが存在しない場合に] .....があります。

<form:radiobutton path="device.criteria" value="${criteria.id}"/> 

送信したパラメータを変換して対応するエンティティインスタンスをバインドするコンバータを登録します。

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert

@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 
    } 
} 
関連する問題