Announcement Announcement Module
Collapse
No announcement yet.
spring:bind tag appending input text delimited by commas Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • spring:bind tag appending input text delimited by commas

    My environment is Spring 1.2 RC2 running on IBM RAD 6.0.1

    I'm having trouble with an annoying problem that I can't get past and it's probably an obvious oversight on my part...

    I'm mimicking the petclinic sample and I have a simple edit form where I can modify the name of a Client command class. The form binds and loads with the current value from the database 'AAAAAAAAAA'. When I clear the text box and type in a new value 'BBBBBBBBBB' and submit the form, whatever I type into the input text gets appended to the original value with a comma delimiter and is passed to the command object in onSubmit() like this: 'AAAAAAAAAA,BBBBBBBBBB'. I log the request parameters in onSubmit() and the name parameter is 'AAAAAAAAAA'. I log the command class and the name property is 'AAAAAAAAAA,BBBBBBBBBB'.

    I've searched the archives here and on the web for a couple of hours, with no luck.

    Any help will be appreciated.


    Here is my JSP, my Controller source code, and my log output:


    <%@ include file="header.jsp" %>

    <!-- Support for Spring errors object -->
    <spring:bind path="command.*">
    <c:forEach var="error" items="${status.errorMessages}">
    <B><font color=RED>
    <BR><c:out value="${error}"/>
    </font></B>
    </c:forEach>
    </spring:bind>

    <table align="left" cellpadding="50">
    <tr>
    <td>
    <form method="post">
    <div class="standard">
    <table align="center" cellspacing="1" cellpadding="0">
    <tr>
    <c:if test="${command.id == null}">
    <th align="center" colspan="2">Add a new Client</th>
    </c:if>
    <c:if test="${command.id != null}">
    <th align="center" colspan="2">Change this Client</th>
    </c:if>
    </tr>
    <tr>
    <td>
    <div class="entry">
    <table width="100%" cellpadding="5">
    <tr>
    <td align="right"><b></b>Client Id:</td>
    <td>
    <c:if test="${command.id == null}">
    <spring:bind path="command.id">
    <font color="red">
    <b><c:out value="${status.errorMessage}"/></b>
    </font>
    <input type="text" maxlength="2" size="2" name="<c:out value="${status.expression}"/>" value="<c:out value="${status.value}"/>" />
    </spring:bind>
    <b></b>
    </c:if>
    <c:if test="${command.id != null}">
    <c:out value="${command.id}" />
    <b></b>
    </c:if>
    </td>
    </tr>
    <tr>
    <td align="right"><b></b>Client Name:</td>
    <td>
    <spring:bind path="command.name">
    <font color="red">
    <b><c:out value="${status.errorMessage}"/></b>
    </font>
    <input type="text" maxlength="50" size="50" name="<c:out value="${status.expression}"/>" value="<c:out value="${status.value}"/>" />
    </spring:bind>
    </td>
    </tr>
    <tr>
    <td align="center" colspan="2">
    <input type="submit" value="Save" />
    </td>
    </tr>
    </table>
    </div>
    </td>
    </tr>
    </table>
    </div>
    </form>
    </td>
    </tr>
    </table>

    <%@ include file="footer.jsp" %>



    public abstract class CmiFormController extends SimpleFormController {

    private Cmi cmi = null;

    public void setCmi(Cmi cmi) {
    this.cmi = cmi;
    }

    protected Cmi getCmi() {
    return this.cmi;
    }

    /**
    * Ensure that the CMI business object has been set by the framework.
    * @throws Exception
    */
    public void afterPropertiesSet() throws Exception {
    if (this.cmi == null) {
    throw new ApplicationContextException("Must set cmi bean property on " + getClass());
    }
    }

    /**
    * Set up a custom property editor for the application's date format.
    */
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, false));
    }

    /**
    * Method disallows duplicate form submission.
    * Prevents duplicate insertion of <code>Entity</code>s into the datastore.
    * Shows a new form with an error message.
    */
    protected ModelAndView disallowDuplicateFormSubmission(HttpServletRequest request, HttpServletResponse response) throws Exception {
    BindException errors = new BindException(formBackingObject(request), getCommandName());
    errors.reject("duplicateFormSubmission", null, "Duplicate form submission");
    return showForm(request, response, errors);
    }
    }



    public class ClientChangeController extends CmiFormController {

    /** Logger for this class */
    private static Logger log = Logger.getLogger(ClientChangeController.class);

    public ClientChangeController() {
    // initialize the form from the formBackingObject
    setBindOnNewForm(true);
    }

    /**
    * Change the <code>Client</code>.
    */
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
    Object command, BindException errors) throws Exception {

    if (log.isDebugEnabled()) {
    log.debug("Entered onSubmit");
    log.debug("Parameters:");
    for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
    String element = (String) e.nextElement();
    log.debug(element + "=" + request.getParameter(element));
    }
    }

    Client client = (Client) command;

    if (log.isDebugEnabled()) {
    log.debug("Changing Client: " + client);
    }

    getCmi().changeClient(client);

    // Display the Clients with the new additions
    return new ModelAndView("clientsView", "clients", getCmi().getClients());
    }

    protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response)
    throws Exception {

    if (log.isDebugEnabled()) {
    log.debug("Entered handleInvalidSubmit");
    log.debug("Parameters:");
    for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
    String element = (String) e.nextElement();
    log.debug(element + "=" + request.getParameter(element));
    }
    }

    return disallowDuplicateFormSubmission(request, response);
    }
    }



    [5/6/05 9:27:59:047 EDT] 00000034 ServletWrappe A SRVE0242I: [/jsp/clientEditForm.jsp]: Initialization successful.
    [5/6/05 9:27:59:141 EDT] 00000034 ResourceBundl I Theme created: name 'theme', basename [theme]
    [5/6/05 9:27:59:156 EDT] 00000034 ExpressionEva I Using JSP 2.0 ExpressionEvaluator
    [5/6/05 9:28:08:047 EDT] 00000033 SystemOut O 06 May 2005 09:28:08,047 WebContainer : 0 DEBUG ClientChangeController - Entered onSubmit
    [5/6/05 9:28:08:047 EDT] 00000033 SystemOut O 06 May 2005 09:28:08,047 WebContainer : 0 DEBUG ClientChangeController - Parameters:
    [5/6/05 9:28:08:047 EDT] 00000033 SystemOut O 06 May 2005 09:28:08,047 WebContainer : 0 DEBUG ClientChangeController - name=AAAAAAAAAA
    [5/6/05 9:28:08:047 EDT] 00000033 SystemOut O 06 May 2005 09:28:08,047 WebContainer : 0 DEBUG ClientChangeController - id=AA
    [5/6/05 9:28:08:047 EDT] 00000033 SystemOut O 06 May 2005 09:28:08,047 WebContainer : 0 DEBUG ClientChangeController - Changing Client: 'AA' 'AAAAAAAAAA,BBBBBBBBBB'

  • #2
    No One Has an Answer for This ?

    I thought you guys would be all over this one.

    Comment


    • #3
      Can you post your Client (command) source?

      I've seen something similar to this before where you mistakenly use the same name attribute for an input field, i.e. and the request parameters get joined together in a comma separated list, but you've clearly got command.name and command.id setup so they won't do that.

      What happens if you debug setName and setId in Client?

      Comment


      • #4
        public abstract class Entity {

        /**
        * A collection of parameters that can be used to build a query string.
        */
        protected HashMap mapping = new HashMap();

        /**
        * Convenience method to clean up form strings sent in a request.
        */
        protected String cleanse(String property) {
        String result = null;
        if (property != null && property.length() > 0) {
        result = property.trim();
        } else {
        result = "";
        }
        return result;
        }

        /**
        * Convenience method to build a number from a String by omitting any characters
        * that are not digits.
        */
        protected String getDigitsFromString(String candidate) {

        StringBuffer result = new StringBuffer();

        if (candidate != null && candidate.length() > 0) {
        char[] characters = candidate.toCharArray();

        for (int i = 0; i < characters.length; i++) {
        if (Character.isDigit(characters[i])) {
        result.append(characters[i]);
        }
        }
        }

        return result.toString();
        }

        /**
        * Convenience method to extract a long from a String.
        */
        public long parseLong(String key) {
        try {
        return Long.parseLong(key);
        } catch (NumberFormatException e) {
        return 0;
        }
        }

        /**
        * Return the mapping of attributes.
        * Convenience method often helpful in Struts applications.
        */
        public Map getMapping() {
        return this.mapping;
        }
        }



        public abstract class NamedEntity extends Entity {

        protected String name = null;

        public void setName(String name) {
        this.name = cleanse(name);
        }

        public String getName() {
        return this.name;
        }
        }



        public class Client extends NamedEntity {

        private String id = null;

        public void setId(String id) {
        this.id = cleanse(id);
        }

        public String getId() {
        return this.id;
        }

        public void setMapping() {
        this.mapping.put("id", this.id);
        this.mapping.put("name", this.name);
        }

        public String toString() {
        return "'" + this.id + "' '" + this.name + "'";
        }
        }



        public class ClientValidator implements Validator {

        public boolean supports(Class theClass) {
        return Client.class.isAssignableFrom(theClass);
        }

        public void validate(Object obj, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "id", "required", "Id is required.");
        ValidationUtils.rejectIfEmpty(errors, "name", "required", "Name is required.");
        }
        }

        Comment


        • #5
          Sorry, don't know. Your code looks good.

          If you've got a setName field, and after a post it's got 2 values in it separated by commas, then i'd still double check that I didn't have 2 input fields in my page.

          Also, you might find it interesting to read up on property editors.

          I'd get rid of the cleanse and getDigitsFromString methods and put that code into property editors.

          Comment


          • #6
            You may be experiencing the same problem that I was having. If your form is submitted with a blank action the browser will send it back to the location from which it originally recieve the form. If by chance you used a get parameter to pass the "AAAAAAA" data when the form is submitted both the get and post data is submitted by the browser.

            I got around this by adding a uri attribute to the request and using it for the action if found otherwise it uses and empty string for the action..

            Comment

            Working...
            X