Page 1 of 3 123 LastLast
Results 1 to 10 of 28

Thread: Object binding problem

  1. #1
    Join Date
    Jul 2010
    Location
    Wrocław, Poland
    Posts
    14

    Default Object binding problem

    Hello,
    I've got some unknown problem with binding value from Spring form select to object referencing this value. Object is Relation class and it has reference to Pet class object in it. When I try to add relation according to created form, Java returns following error:

    Code:
    org.hibernate.PropertyValueException: not-null property references a null or transient value: org.springframework.samples.petclinic.Relation.pet2
    I'll show some code fragments:

    relationForm.jsp
    Code:
    <form:form modelAttribute="relation">
    	<form:select path="pet2" items="${pets}" multiple="false" />
    	<form:checkbox path="positive" />
    	<input type="hidden" name="pet" value="${relation.pet.id}"/>
    	<p class="submit"><input type="submit" value="Add Relation" /></p>
    </form:form>
    addRelationForm.java
    Code:
    package org.springframework.samples.petclinic.web;
    
    // imports
    
    @Controller
    @RequestMapping("/owners/*/pets/{petId}/relations/new")
    @SessionAttributes("relation")
    public class AddRelationForm {
    
    	private final Clinic clinic;
    
    	@Autowired
    	public AddRelationForm(Clinic clinic) {
    		this.clinic = clinic;
    	}
    
    	@InitBinder
    	public void setAllowedFields(WebDataBinder dataBinder) {
    		dataBinder.setDisallowedFields("id");
    	}
    
    	@RequestMapping(method = RequestMethod.GET)
    	public String setupForm(@PathVariable("petId") int petId, Model model) {
    		Pet pet = this.clinic.loadPet(petId);
    		List<Relation> relations=pet.getRelations();
    		Collection<Pet> pets=this.clinic.getPets();
    		pets.remove(pet);
    		for(int i=0; i<relations.size(); i++){
    			pets.remove(relations.get(i).getPet2());
    		}
    		Relation relation = new Relation();
    		relation.setPet(pet);
    		pet.addRelation(relation);
    		model.addAttribute("relation", relation);
    		model.addAttribute("pets", pets);
    		return "pets/relationForm";
    	}
    
    	@RequestMapping(method = RequestMethod.POST)
    	public String processSubmit(@ModelAttribute("relation") Relation relation,
    			BindingResult result, SessionStatus status) {
    		new RelationValidator().validate(relation, result);
    		this.clinic.storeRelation(relation);
    		return "redirect:/owners/" + relation.getPet().getOwner().getId();
    	}
    }
    Hibernate mapping file
    Code:
    <class name="Pet" table="pets">
    		<id name="id" column="id">
    			<generator class="identity" />
    		</id>
    		<property name="name" column="name" />
    		<property name="birthDate" column="birth_date" type="date" />
    		<many-to-one name="owner" column="owner_id"
    			class="org.springframework.samples.petclinic.Owner" />
    		<many-to-one name="type" column="type_id"
    			class="org.springframework.samples.petclinic.PetType" />
    		<set name="visitsInternal" inverse="true" cascade="all" lazy="false">
    			<key column="pet_id" />
    			<one-to-many class="org.springframework.samples.petclinic.Visit" />
    		</set>
    		<set name="relationsInternal" inverse="false" cascade="all" lazy="false">
    			<key column="pet_id"/>
    			<one-to-many class="org.springframework.samples.petclinic.Relation"/>
    		</set> 
    	</class>
    
    <class name="Relation" table="relations">
    		<id name="id" column="id">
    			<generator class="identity" />
    		</id>
    		<property name="positive" column="positive" type="boolean" />
    		<many-to-one name="pet" column="pet_id"
    			class="org.springframework.samples.petclinic.Pet" />
    		<many-to-one name="pet2" class="org.springframework.samples.petclinic.Pet"
    			column="pet2_id" not-null="true" cascade="all" unique="true"/>
    	</class>
    I don't see any errors here, what is wrong?

  2. #2
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    The problem is that you are setting the pet on your relation object but you are not setting the pet2 object on your relation object and your mapping states that pet2 is not nullable.

    You either need to set the pet2 object when you create the Relation object or change your mapping file.

  3. #3
    Join Date
    Jul 2010
    Location
    Wrocław, Poland
    Posts
    14

    Default

    I need to choose pet2 from form. It cannot be nullable. I am real beginner and I don't know, where I made a mistake, which makes pet2 null and not value selected from select field in form.

  4. #4
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    You are close then. What version of Spring are you using? can you post your view code that has your form in it? Also are you using Property editors or the Conversion service?

  5. #5
    Join Date
    Jul 2010
    Location
    Wrocław, Poland
    Posts
    14

    Default

    I am using the latest version of Spring (if I remember correctly: 3.0.3). About view... you mind .jsp? I'll put whole source of file with form and files included:

    relationForm.jsp
    Code:
    <%@ include file="/WEB-INF/jsp/includes.jsp"%>
    <%@ include file="/WEB-INF/jsp/header.jsp"%>
    
    <form:form modelAttribute="relation">
    	<form:select path="pet2" items="${pets}" multiple="false" />
    	<form:checkbox path="positive" />
    	<input type="hidden" name="pet" value="${relation.pet.id}"/>
    	<p class="submit"><input type="submit" value="Add Relation" /></p>
    </form:form>
    <br />
    
    <b>Relations with other pets:</b>
    <table width="333">
    	<tr>
    		<th>Name</th>
    		<th>Relation</th>
    	</tr>
    	<c:forEach var="relationx" items="${relation.pet.relations}">
    
    		<c:if test="${relationx.pet2.name!=null}">
    			<tr>
    				<td>${relationx.pet2}</td>
    				<c:if test="${relationx.positive}">
    					<td class="positive">Positive</td>
    				</c:if>
    				<c:if test="${!relationx.positive}">
    					<td class="negative">Negative</td>
    				</c:if>
    			</tr>
    		</c:if>
    
    	</c:forEach>
    </table>
    
    <%@ include file="/WEB-INF/jsp/footer.jsp"%>
    includes.jsp
    Code:
    <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>\
    header.jsp and footer.jsp (I don't think that they are needed here, but let's have whole view):
    Code:
    <!--
    	PetClinic :: a Spring Framework demonstration
    -->
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
      <link rel="stylesheet" href="<spring:url value="/static/styles/petclinic.css" htmlEscape="true" />" type="text/css"/>
      <title>PetClinic :: a Spring Framework demonstration</title>	
    </head>
    
    <body>
    
      <div id="main">
    Code:
      <table class="footer">
        <tr>
          <td><a href="<spring:url value="/" htmlEscape="true" />">Home</a></td>
          <td align="right"><img src="<spring:url value="/static/images/springsource-logo.png" htmlEscape="true" />" alt="Sponsored by SpringSource"/></td>
        </tr>
      </table>
    
      </div>
    </body>
    
    </html>
    //edit:
    I forgot, I am not using any of them both.
    Last edited by IceMan; Jul 19th, 2010 at 03:30 PM.

  6. #6
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    ok, I would set the itemLabel and the itemValue attributes on the <form:select tag. This tells spring what to display as the label and what to use as the value for the <option> markup that it will generate. In your case it looks like you would set the itemLabel to "name" and the itemValue to "id".

    Finally, you need to setup the ConversionService or a PropertyEditor so that Spring knows how to translate the "id" value of the option markup to the Pet entity.

    I use the ConversionService in most of my apps but you can use either one.

  7. #7
    Join Date
    Jul 2010
    Location
    Wrocław, Poland
    Posts
    14

    Default

    I had itemLabel and itemValue set before, but according to what you write here, these weren't only things missing. I haven't heard about ConversionService or PropertyEditor, tutorials never said anything about them. I'll try tomorrow and hope it will help. Thanks in advance!

  8. #8
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    Take a look at this link. It should help you out.

  9. #9
    Join Date
    Jul 2010
    Location
    Wrocław, Poland
    Posts
    14

    Default

    I don't understand all behind the scene things about ConversionService. I have added following bean to my context.xml file:
    Code:
    <bean id="conversionService"
    		class="org.springframework.context.support.ConversionServiceFactoryBean">
    		<property name="converters">
    			<list>
    				<bean class="org.springframework.samples.petclinic.PetConverter" />
    			</list>
    		</property>
    	</bean>
    and created class PetConverter.java:
    Code:
    package org.springframework.samples.petclinic;
    
    import java.util.ArrayList;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.convert.converter.Converter;
    
    public class PetConverter implements Converter<String,Pet>{
    
    	@Autowired
    	Clinic clinic;
    	
    	public Pet convert(String arg0) {
    		ArrayList<Pet> pets= new ArrayList<Pet>(clinic.getPets());
    		for(Pet pet:pets){
    			if(pet.getId().equals(Integer.getInteger(arg0))) return pet;
    		}
    		return null;
    	}
    }
    What am I doing wrong and what should I do to make it all work?

  10. #10
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    I would run the debugger to see if your converter is truly being invoked and see if the problem is with your converter or with the setup of the conversion service.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •