Announcement Announcement Module
Collapse
No announcement yet.
strange binding result Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • strange binding result

    Hi,

    I'm binding attributes of a command object within a form in my jsp in the following way (I'm using Spring 1.2.8):
    Code:
    <spring:bind path="user.username">
        <input type="text"
            name="<c:out value="${status.expression}"/>"
            value="<c:out value="${status.value}"/> "/>
    </spring:bind>
    In the associated form controller (which extends SimpleFormController) I populate the command object's username property with a value from formBackingObject(). All works fine so far, with the value showing up as expected in the input field.

    Now the problem is that when the form is submitted, the username attribute of the user command object contains both the original value (set by formBackingObject()) followed by a comma and then followed by the new user entered value!

    Can anyone tell me what's happening here please? It smells like a property editor issue, but I'm not sure. I can see that returning both the original value and the new value might have it's uses, but in most cases I would have thought that the new property value is all that is required.

    Any help would be much appreciated.

    Thanks,

    Peeper.

  • #2
    Can you post also the code of the relevant controller and the applicationcontext of that controller? Might give some more insights.

    Comment


    • #3
      Here's the relavant part of the DispatcherServlet configuration file:
      Code:
      <beans>
      	...
      	<bean id="userEditValidator" class="bus.UserEditValidator"/>
      	<bean id="userEditForm" class="web.UserEditFormController">
      		<property name="sessionForm">
      			<value>true</value>
      		</property>
      		<property name="commandName">
      			<value>user</value>
      		</property>
      		<property name="commandClass">
      			<value>bus.User</value>
      		</property>
      		<property name="validator">
      			<ref bean="userEditValidator"/>
      		</property>
      		<property name="formView">
      			<value>user-edit</value>
      		</property>
      		<property name="successView">
      			<value>user-management</value>
      		</property>
      		<property name="userManager">
      			<ref bean="userManager"/>
      		</property>
      	</bean>
      	...
      </beans>
      Here's the code for the Controller (fairly bare until I resolve this problem):
      Code:
      public class UserEditFormController extends SimpleFormController
      {
      	private UserManager userManager;
      
      	protected ModelAndView onSubmit(Object command) throws Exception
      	{
      		User user = (User)command;
      		
      		return new ModelAndView(getSuccessView());
      	}
      
      	protected Object formBackingObject(HttpServletRequest request)
      		throws Exception
      	{
      		String	username;
      		User	user;
      		
      		username = request.getParameter("username");
      		if (username != null)
      		{
      			user = userManager.getUser(username);
      			if (user == null)
      			{
      				// username not found so create a new user with the given name
      				user = new User();
      				user.setUsername(username);
      			}
      			return user;
      		}
      
      		// no username parameter found so just create an empty, default user
      		return new User();
      	}
      
      	public UserManager getUserManager()
      	{
      		return userManager;
      	}
      
      	public void setUserManager(UserManager userManager)
      	{
      		this.userManager = userManager;
      	}
      }
      And the validator:
      Code:
      public class UserEditValidator implements Validator
      {
      	public boolean supports(Class clazz)
      	{
      		return clazz.equals(User.class);
      	}
      
      	public void validate(Object obj, Errors errors)
      	{
      		ValidationUtils.rejectIfEmptyOrWhitespace(errors, 
      				"username",
                      "user-edit-error.username-required",
                      "Username required");
      	}
      }
      Thanks,

      Peeper.

      Comment


      • #4
        Originally posted by peeper
        Hi,

        I'm binding attributes of a command object within a form in my jsp in the following way (I'm using Spring 1.2.8):
        Code:
        <spring:bind path="user.username">
            <input type="text"
                name="<c:out value="${status.expression}"/>"
                value="<c:out value="${status.value}"/> "/>
        </spring:bind>
        In the associated form controller (which extends SimpleFormController) I populate the command object's username property with a value from formBackingObject(). All works fine so far, with the value showing up as expected in the input field.

        Now the problem is that when the form is submitted, the username attribute of the user command object contains both the original value (set by formBackingObject()) followed by a comma and then followed by the new user entered value!

        Can anyone tell me what's happening here please? It smells like a property editor issue, but I'm not sure. I can see that returning both the original value and the new value might have it's uses, but in most cases I would have thought that the new property value is all that is required.

        Any help would be much appreciated.

        Thanks,

        Peeper.
        I got same kind of "errors" and the problem was that there was the used the same field binding twice in the same form.

        Comment


        • #5
          Originally posted by noon
          I got same kind of "errors" and the problem was that there was the used the same field binding twice in the same form.
          I don't think that is the case in my situation. Here is the whole of the jsp file, which only contains the one field:
          Code:
          <%@ include file="/WEB-INF/jsp/include.jsp"%>
          <%@ taglib prefix="spring" uri="/spring"%>
          
          <html>
          <head>
          <title><fmt:message key="app.title"/></title>
          </head>
          <body>
          
          <h1><fmt:message key="user-edit.heading"/></h1>
          
          <form method="post">
          	<spring:bind path="user.username">
          		<input type="text"
          			name="<c:out value="${status.expression}"/>"
          			value="<c:out value="${status.value}"/>" />
          	</spring:bind>
          	<p>
          	<input type="submit" alignment="center" value="Submit">
          </form>
          
          </body>
          </html>
          As you can see there's only one field so there can't be any duplication!

          Any other ideas gratefully received!

          Thanks,

          Peeper.

          Comment


          • #6
            I'm a bit confused in what you are doing. Try the following......

            I don't think you need sessionForm = true (set to false)

            Your formBackingObject should simply return a new User() object

            The onSubmit method which gets called after the post will populate the User() object for you which you have done but don't do anything with.

            Basically the logic should be in the onSubmit method, something like:

            Code:
            protected ModelAndView onSubmit(Object command) throws Exception
            {
              User user = (User)command;		
              User matchedUser = userManager.getUser(user.getUsername());
              if (matchedUser != null)
              {
                // probably set matchedUser in session as an attribute (up to you!!)
                return new ModelAndView(getSuccessView());
              }
              else
              {
                errors.reject("incorrectLogin","Incorrect user please try again");
                return showForm(request, response, errors);
              }
            }
            errors.reject will create a global error for the user command object. You can use errors.rejectValue if you want a field specific error.

            Hope this helps.

            Comment


            • #7
              I think you should not set the value in formBackingObject. Just create the new object and Spring will bind the value with the model setters.

              This is how I have done in my Spring projects. If model was 'new', I just created a new model (POJO). Otherwise I fetch the real model e.g. from database by its id or something.

              I hope you solve this problem.

              Comment


              • #8
                Thanks for you suggestions guys. Let me explain the rationale behind what I'm doing and ask a couple of questions that may finally help me resolve this...

                The form is used to edit user details, so the fields must be populated when it is first shown (i.e. upon GET). So I create the User command object in formBackingObject() and then set its properties so that the form fields can be taken from this. Is this the correct way to do this? From paulf's and noon's comments I'm beginning to suspect that formBackingObject() is not the right place to populate User properties when first showing the form.

                As paulf says, onSubmit() isn't doing a great deal at the moment, but my intention is to update the user's details from the command object - that is, upon POST. Is this the right thing to do?

                Thanks,

                Peeper.

                Comment


                • #9
                  the formBackingObject() is the right place to create your User object so that it is displayed in your form on the first subsequent GET.

                  It depends on your requirements. You may want to create a different object when it is GET or POST. To be more precise you should call isFormSubmission() which will tell you if it is a form submission. By default a POST is treated as a form submission and a GET as simply displaying the form. (It's best to call this method in case you overide the method later and decide on an alternative stratedgy on what is a form submission and what is not)

                  For some reason you know the username before the form is displayed and is passed in the URL as a parameter. So yes you could do what you are doing to obtain the relevant User object to be displayed in the initial form. So in formBakingObject check isFormSubmission == false and then return your user object based on the username parameter.

                  If isFormSubmission == true then again it is up to you what object you want auto binded by Spring on the form submission. You may simply return a new User() object to be populated so you can compare this object with the USre object returned from your userManager. It depends on what you are trying to do so I can only speculate.

                  I found reading the workflow section in the javadoc of AbstractFormController very useful. It is all explained there.

                  Anyway you seem to have the idea so best of luck!!!

                  Comment


                  • #10
                    Many thanks for the suggestions.

                    I finally discovered that the original problem was the result of a simple mistake/ommision in the <form> element of my jsp. I'd neglected to provide the 'action' attribute in the opening form tag. So rather than using something like:
                    Code:
                    <form action="<c:url value="user-edit.html"/>" method="post">
                    I was using the incorrect code:
                    Code:
                    <form method="post">
                    Now to try to understand why a missing 'action' attribute results in weird field values...

                    Peeper.

                    Comment


                    • #11
                      hi,
                      i got the solution for this problem.

                      this is just because you have the same parameter value in GET while getting the user object for filling the form and in POST for submitting changes. formbackingObject is called twice, once when the form is displayd and once the form is submitted. If submitting, the formBackingObject reads the username-param from POST AND GET and seperates both with a COMMA.

                      just rename the parameter in the url and have fun!

                      Comment

                      Working...
                      X