Announcement Announcement Module
Collapse
No announcement yet.
Nested validation of an List Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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, 09:59 AM.

    Comment


    • #3
      Thank you very much

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

      Comment


      • #4
        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

        Comment


        • #5
          Post your code, please

          I will hope your code.

          Comment


          • #6
            Code results in &quot;Validator must not be null&quot; 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

            Comment


            • #7
              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,

              Comment


              • #8
                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, 02:22 PM.

                Comment

                Working...
                X