Results 1 to 8 of 8

Thread: Nested validation of an List

  1. #1
    Join Date
    Aug 2009
    Posts
    4

    Question Nested validation of an List

    Hi,

    I have Problems with validating an List of SubObjects.

    I have an Customer with a List of addresses (one to many-relationship):
    Later on the user should be able to add as much address objects as wanted by javascript.

    After sending my webform I want to check if the street property (e.g.) of each address but all my tries failed.

    My question is how to do a nested validation of an List.

    Thank you for all help and advices.

    These are my classes:

    Customer.java
    Code:
    @Entity
    @Table(name = "customer")
    public class Customer {
    
    	private Integer id;
    	private String name;
    	
    	public List<Address> addresses = new AutoPopulatingList(new AddressFactory());
    
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    	public List<Address> getAddresses() {
    		return addresses;
    	}
    	public void setAddresses(List<Address> addresses) {
    		this.addresses = addresses;
    	}
    	
    	public void addAddress(Address address) {
            this.addresses.add(address);
        }
    
    }
    Address.java
    Code:
    @Entity
    @Table(name = "address")
    public class Address implements IAddress,Serializable {
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	
    	private Integer id;
    	private String addressname;
    	private String street;
    
    	
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getAddressname() {
    		return addressname;
    	}
    	public void setAddressname(String addressname) {
    		this.addressname = addressname;
    	}
    	
    	public String getStreet() {
    		return street;
    	}
    	public void setStreet(String street) {
    		this.street = street;
    	}	
    }
    CustomerValidator.java
    Code:
    public class CustomerValidator implements Validator {
    
    	public boolean supports(Class clazz) {
    		return clazz.equals(Customer.class);
    	}
    
    	public void validate(Object obj, Errors errors) {
    		Customer customer = (Customer) obj;
    		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required.name", "Name muss gesetzt sein");
    		errors.setNestedPath("addresses");
    		try {
    			
    			for (Address address : customer.getAddresses()) {
    				AddressValidator addressValidator = new AddressValidator();
    				ValidationUtils.invokeValidator(addressValidator, address, errors);
    		
    			}
    		} finally {
    			errors.popNestedPath();
    		}
    	}
    
    }
    AddressValidator .java
    Code:
    public class AddressValidator implements Validator {
    	
    	
    	public boolean supports(Class clazz) {
    		return true;//clazz.equals(Address.class);
    	}
    
    	public void validate(Object obj, Errors errors) {
    		Address address = (Address)obj;
    		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "street", "required.street", "Strasse muss gesetzt sein");
    	
    	}
    
    }
    CustomerCreateController.java
    Code:
    @Controller
    public class CustomerCreateController extends CustomerBasicController {
    
    	@Override
    	protected Object formBackingObject(HttpServletRequest request) throws Exception {
    		Customer customer = new Customer();
    		Address address = new Address();
    		address.setAddressname("Firmenaddresse");
    		customer.getAddresses().add(address);
    		return customer;
    	}
    	
    	protected void doSubmitAction(Object command) throws Exception {
    		Customer customer = (Customer) command;
    		customer = customerDao.save(customer);
    		logger.debug("Customer saved");
    	}
    	
    
    }
    customerCreate.jsp
    Code:
    <%@ include file="header.jspf"%>
    
    	<form:form commandName="customer" method="POST" action="create.do">
    		<fieldset style="width: 500px;">
    			<legend>Kundendaten</legend>
    			<spring:hasBindErrors name="customer">
    				<font color="red"> <c:forEach items="${errors.allErrors}"
    					var="error">
    					<p><spring:message code="${error.code}" text="${error.defaultMessage}" /></p>
    				</c:forEach> 
    				</font>
    			</spring:hasBindErrors> 
    			
    			<form:input path="name" /> 
    			
    			<c:forEach items="${customer.addresses}" var="address" varStatus="itemRow">
    				<fieldset>
    				<legend>${address.addressname}</legend> 
    					<label for="addresses[${itemRow.index}].street">Strasse <br />
    					<input type="text" name="addresses[${itemRow.index}].street" id="addresses[${itemRow.index}].street" value="${address.street}" />
    					</label>
    				</fieldset>
    			</c:forEach>
    		</fieldset>
    		<br />
    		<input type="submit" value="Kunde anlegen" />
    	</form:form>
    	
    <%@ include file="footer.jspf"%>

    Thank you.

  2. #2
    Join Date
    Aug 2009
    Posts
    4

    Lightbulb Solved

    Hi,

    I think I solved the problem.

    I modified the CustomerValidator.java

    Code:
    public class CustomerValidator implements Validator {
    
    	private AddressValidator addressValidator;
    	
    	public AddressValidator getAddressValidator() {
    		return addressValidator;
    	}
    
    	public void setAddressValidator(AddressValidator addressValidator) {
    		this.addressValidator = addressValidator;
    	}
    
    	public boolean supports(Class clazz) {
    		return clazz.equals(Customer.class);
    	}
    
    	public void validate(Object obj, Errors errors) {
    		Customer customer = (Customer) obj;
    		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required.name", "Name muss gesetzt sein");
    		int i=0;
    		for (Address address : customer.getAddresses()) {
    			errors.pushNestedPath("addresses["+i+"]");
    			ValidationUtils.invokeValidator(this.addressValidator, address, errors);
    			errors.popNestedPath();
    			i++;
    		}		
    	}
    
    }
    I hope this is correct and it helps.
    Last edited by rognox; Aug 12th, 2009 at 09:59 AM.

  3. #3
    Join Date
    Aug 2009
    Posts
    8

    Default Thank you very much

    I have spend a lot of time trying find out it. Very thank you

  4. #4
    Join Date
    Nov 2009
    Posts
    3

    Default Validator must not be null error

    Hi,
    I have implemented this as well (and nearly exact, but in an airline demo).
    My addressValidator seems to be null, though, because I receive the error
    "Validator must not be null".

    Any advice on this?
    Thank you
    ~ b

  5. #5
    Join Date
    Aug 2009
    Posts
    8

    Default Post your code, please

    I will hope your code.

  6. #6
    Join Date
    Nov 2009
    Posts
    3

    Default Code results in "Validator must not be null" error

    Hi, here's my code

    BookingValidator.java

    Code:
    package org.springframework.ws.samples.airline.web;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.Errors;
    import org.springframework.validation.ValidationUtils;
    import org.springframework.validation.Validator;
    import org.springframework.ws.samples.airline.domain.Passenger;
    import org.springframework.ws.samples.airline.web.beans.Booking;
    
    class BookingValidator implements Validator{
    	
    	private PassengerValidator passengerValidator;
    	
    	public PassengerValidator gePassengerValidator() {
    		return passengerValidator;
    	}
    
    	public void setPassengerValidator(PassengerValidator passengerValidator) {
    		this.passengerValidator = passengerValidator;
    	}
    	
    	@Override
    	@SuppressWarnings("unchecked")
    	public boolean supports(Class clazz) {
            return Booking.class.equals(clazz);
    	}
    	
    	@Override
    	public void validate(Object obj, Errors errors) {
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "departureDateAsString", "required", "Departure date is required.");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "flightNumber", "required", "FlightNumber is required.");
            Booking b = (Booking)obj;
            
            int i=0;
    		for (Passenger passenger : b.getPassengers()) {
    			errors.pushNestedPath("passengers["+i+"]");
    			ValidationUtils.invokeValidator(this.passengerValidator, passenger, errors);
    			errors.popNestedPath();
    			i++;
    		}
    	}
    }
    PassengerValidator.java
    Code:
    import org.springframework.validation.Errors;
    import org.springframework.validation.ValidationUtils;
    import org.springframework.validation.Validator;
    import org.springframework.ws.samples.airline.domain.Passenger;
    
    class PassengerValidator implements Validator{
    	@Override
    	public boolean supports(Class clazz) {
            return Passenger.class.equals(clazz);
    	}
    	
    	@Override
    	public void validate(Object obj, Errors errors) {
            Passenger p = (Passenger)obj;
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "first", "required", "First name is required.");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "last", "required", "Last name is required.");
    	}
    
    }
    the applicable stuff from
    FlightsController.java
    Code:
    @RequestMapping(value="/bookFlight" )
        public String bookFlight(@ModelAttribute("booking") Booking booking, Errors errors,
                                 ModelMap model) {
        	    new BookingValidator().validate(booking, errors);
        	    if (errors.hasErrors()){
        	    	return "booking";
        	    }
        	log.debug("Flight number in Booking is: " + booking.getFlightNumber());
        	log.debug("Departure Date in Booking is: " + booking.getDepartureDateAsString());
        		
        	if (log.isDebugEnabled()) {
            	log.debug("Passengers in Booking:");
    			for (Passenger passenger : booking.getPassengers()) {
    				log.debug("Passenger First Name:" + passenger.getFirst());
    				log.debug("Passenger Last Name:" + passenger.getLast());
    			}
        	}
    		
            try {
        		Date departureDate = getDateFormat().parse(booking.getDepartureDateAsString());
        		
    			model.addAttribute("ticket",airlineServiceAdapter.bookFlight(booking.getFlightNumber(), new DateTime(departureDate.getTime()),booking.getPassengers()));
    		} catch (DatatypeConfigurationException e) {
    			log.error("DatatypeConfigurationException when booking flight", e);
    		} catch (ParseException e) {
    			log.error("ParseException when booking flight", e);
    		}
        	
            return "bookingConfirmed";
        }
    This results in the error message "Validator must not be null"
    Thank you for your help :-)
    ~ b

  7. #7
    Join Date
    Aug 2009
    Posts
    8

    Default Log your PassengerValidator

    You have said:

    Validator must be not null

    ValidationUtils.invokeValidator API says:

    must be not null

    So i think your PassengerValidator is null when you pass it as argument to ValidationUtils.invokeValidator method. Before calling invokeValidator method, check whether PassengerValidator is really not null.

    regards,

  8. #8
    Join Date
    Nov 2009
    Posts
    3

    Default

    Thanks for your response.

    I missed the obvious. I simply had to create a new passengerValidator in my BookingValidator so that it wasn't null.
    :-)
    Last edited by bkrawczuk; Nov 20th, 2009 at 01:22 PM.

Tags for this Thread

Posting Permissions

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