Stack Exchange
Spring form binding issue with nested object empty fields
I am having rather an awkward issue with spring @ModelAttribute form binding. I have the following Entity class which is used in form binding as a nested class of Policy class.
@javax.persistence.Entity
@Table(name = "entity")
@XmlRootElement
public class Entity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "entity_id")
    private Integer entityId;

    @Basic(optional = false)
    @NotNull
    @Column(name = "entity_type")
    private int entityType;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 2147483647)
    @Column(name = "entity_name")
    private String entityName;

    public Entity() {
    }

    public Entity(Integer entityId) {
        this.entityId = entityId;
    }

    public Entity(Integer entityId, int entityType, String entityName) {
        this.entityId = entityId;
        this.entityType = entityType;
        this.entityName = entityName;
    }

    public Integer getEntityId() {
        return entityId;
    }

    public void setEntityId(Integer entityId) {
        this.entityId = entityId;
    }

    public int getEntityType() {
        return entityType;
    }

    public void setEntityType(int entityType) {
        this.entityType = entityType;
    }

    public String getEntityName() {
        return entityName;
    }

    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }
}

And the main interest of my problem, Policy class, which is the top level class and main binding is as follows:
@Entity
@Table(name = "policy")
@XmlRootElement
public class Policy implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "policy_id")
    private Integer policyId;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 2147483647)
    @Column(name = "reference_number")
    private String referenceNumber;

    @JoinColumn(name = "adjuster_id", referencedColumnName = "entity_id", nullable = true)
    @ManyToOne(optional = true)
    private Entity adjusterId;

    public Policy() {
    }

    public Policy(Integer policyId) {
        this.policyId = policyId;
    }

    public Integer getPolicyId() {
        return policyId;
    }

    public void setPolicyId(Integer policyId) {
        this.policyId = policyId;
    }

    public String getReferenceNumber() {
        return referenceNumber;
    }

    public void setReferenceNumber(String referenceNumber) {
        this.referenceNumber = referenceNumber;
    }


    public Entity getAdjusterId() {
        return adjusterId;
    }

    public void setAdjusterId(Entity adjusterId) {
        this.adjusterId = adjusterId;
    }
}

And this is the controller method which takes in a ModelAttribute annotated Policy parameter from view binding.
@RequestMapping(value = "/create", method = RequestMethod.POST)
    public ModelAndView create(@ModelAttribute Policy p) {
        policyService.create(p);
        return new ModelAndView("viewName");
    }

Finally this is the form/view part of the code:
<form id="policyInformationForm" role="form" th:object="${policy}" th:action="@{${mode == 'CREATE'} ? '/policy/create' : '/policy/update'}" method="post">
                        <div class="box-body">
                            <div class="form-group">
                                <label for="policyId">Policy Id</label>
                                <input type="text" th:field="*{policyId}" class="form-control" id="policyId" placeholder="" readonly="readonly" />
                            </div>

                            <div class="form-group">
                                <label for="referenceNumber">Policy Number (May change while saving!!!)</label>
                                <input type="text" th:field="*{referenceNumber}" class="form-control" id="referenceNumber" placeholder="Enter Policy Number" th:readonly="${mode == 'UPDATE'}" />
                            </div>

                            <div class="form-group">
                                <label for="adjusterName">Adjuster</label>
                                <div class="input-group">
                                    <input type="hidden" th:field="*{adjusterId.entityId}" class="form-control" id="adjusterId" />
                                    <input type="text" th:field="*{adjusterId.entityName}" class="form-control" id="adjusterName" placeholder="Enter Adjuster" />
                                    <div class="input-group-btn">
                                        <button id="adjusterSearchBtn" type="button" class="btn btn-success"><span class="glyphicon glyphicon-search"></span></button>
                                        <button id="adjusterCreateBtn" type="button" class="btn btn-success"><span class="glyphicon glyphicon-plus"></span></button>
                                    </div>
                                </div>
                            </div>

                        </div>

                        <div class="box-footer">
                            <button type="submit" class="btn btn-primary">Submit</button>
                            <a th:href="@{'/policy/list'}" class="btn btn-warning">Cancel</a>
                        </div>
                    </form>

The problem is when i submit the form; spring form binding binds the form parameters to respective fields of the Policy class but if the adjuster is not selected, namely hidden field of adjusterId value is blank (which is perfectly fine regarding the application) then spring instantiates a new Entity class with all fields having null values. This creates a problem on JPA persistence part of the application because of ManyToOne relation and JPA validations.
Any pointers on how to overcome this problem. If the adjusterId from the view (form hidden input field) is null; then form binding should not instantiate a new Entity class with null field values. Instead it should set the adjusterId property of the Policy class as null.
By the way i already gone through many of the similar questions, which in turn most of them are not relevant. One of them is exactly the same question which is unanswered
Thanks in advance...

By the way i tracked the problem down to spring form binding IdToEntityConverter. Any information overriding the default converter would be much appreciated

In the contoller, you could just do:
@RequestMapping(value = "/create", method = RequestMethod.POST)
public ModelAndView create(@ModelAttribute Policy p) {
    if (p.getAdjusterId().getEntityId() == null) {
        p.setAdjusterId(null);
    }
    policyService.create(p);
    return new ModelAndView("viewName");
}


I have already done that and it is the most suitable workaround; thats way it is accepted as an answer. I believe IdToEntityConverter should somehow understand the incoming (field) parameter is null and should not construct the object.

Actually, it's not a workaround, it's the solution itself. Overriding IdToEntityConverter would be a non-standard way and it's not worth the effort in this case. If you don't want to write same logic (checking if entityId is null) in every controller method that Policy involved, you can use ModelAttribute annotation in method level. Take a look at the doc
