Announcement Announcement Module
Collapse
No announcement yet.
Handle excpetions from custom property editor spring 2.5 Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Handle excpetions from custom property editor spring 2.5

    Hi,
    I am comparatively new to spring.
    I have a web form from where I expect a numeric field (phoneNo).
    I have defined a POJO for the same and having a Long field to capture the phone number.
    The problem is ,when the user type in an invalid phone numbers like alphabets ,the aplication crashes.I have defined a custome property editor and registred it with a WebBindingInitializer,which is configured in me app-servlet.xml.
    In the property editor

    public void setAsText(String text) throws IllegalArgumentException {
    // If the text is null or empty string, then set to default value.

    if (StringUtils.isEmpty(text) == true) {
    setValue(this.defaultValue);
    }

    // use given NumberFormat for parsing text
    else if (this.numberFormat != null) {
    setValue(NumberUtils.parseNumber(text, this.numberClass,
    this.numberFormat));
    }

    // use default valueOf methods for parsing text
    else {
    setValue(NumberUtils.parseNumber(text, this.numberClass));
    }

    }


    Here the property editor thows the excpetion when the input field is invalid.How can I handle this excpetion and provide a valid error mesage to the user?
    Or if anybody can help me by advicing ,what is the best approch for this validation,that would be great.

    Thanks in advance
    Shaiju

  • #2
    Spring automatically throws an exception when you try to bind characters to a Long property. Why do you need a custom property editor for that?

    If you want to format the number for display you could use JSTL tag library for formatting.

    Comment


    • #3
      Hi,
      Thanks for the update.But my intention is not displaying nut capturing the data from form field and save.does jstl format can help in this?

      Shaiju

      Comment


      • #4
        Can you post the relative jsp, command & controller code.

        Comment


        • #5
          1) Why create a custom editor whereas spring already provides 1
          2) Read the chapter about binding and messages in the reference guide and check the sample applications.
          3) Configure a MessageSource in your application
          4) include a errorCode in your message which is suitable for your needs (check DefaultMessageCodeResolver for the strategies)

          Comment


          • #6
            1) I tried to use the editor provided by Spring.But I believe it does not handle the numberformat exception generated when tryig to convert a invalid number e.g "abc" , to Long.And hence did not helped me.

            2) I went through the sample application (petstore), and followed the same appoch they have used for petType, I could not run and test the petsrote application though. Following the same steps did not help me.

            3)DefaultMessageCodeResolver , I am not aware about this. I will check out this. Is it configurable in the application context file?

            My jsp
            Code:
            <form:form modelAttribute="dmsUser" onsubmit="return validate();">
             <table style="width: 100%" align="center">
                <c:if test="${!empty error && error== 'fatal'}">
                  <tr><td colspan=4>					<center><b><font color="RED">
            		<h3><fmt:message key="error.saveUser.fatal" /></h3>
            		</font></b>
            	</center>
            	</td>
                  </tr>
               </c:if> 
               <tr>
            <td><fmt:message key="userDetails.userName" /></td>
            <td><form:input path="userName" readonly="${readonly }" tabindex="1"/>
            	<form:errors path="userName"/></td>
            <td><fmt:message key="userDetails.role" /></td>
            <td><select name="role.roleId" size="1" tabindex="2">
            	<c:forEach var="role" items="${roles}">
            	<c:choose>		
            	<c:when test="${role.roleId==dmsUser.role.roleId}">
            								<option selected value="${role.roleId}">"${role.roleDesc}"</option>
            	</c:when>
            							<c:otherwise>
            								<option value="${role.roleId}">${role.roleDesc}</option>
            							</c:otherwise>
            							</c:choose>
            	</c:forEach>
            	</select>
            	<form:errors path="role"/>
            	</td>
            </tr>
            <tr>
            <c:if test="${dmsUser.userId==0 }">
            <td><fmt:message key="userDetails.password" /></td>
            <td><form:input path="password"  tabindex="3"/>
            <form:errors path="password"/></td>
            </c:if>
            <td><fmt:message key="userDetails.phoneNo" /></td>
            		
            <td><form:input path="phoneNo" readonly="${readonly }" />
            <form:errors path="phoneNo"/></td>
            				
            </tr>
            <tr>
            <c:if test="${dmsUser.userId==0}">
            <td><fmt:message key="userDetails.confirmPassword" /></td>
            <td><input type="text" name="cpassword"  tabindex="4"/>&nbsp;</td>
            </c:if>
            <td><fmt:message key="userDetails.emailId" /></td>
            <td><form:input path="emailId" readonly="${readonly }" />
            <form:errors path="emailId"/></td>
            </tr>
            <tr>
            <td><fmt:message key="userDetails.org" /></td>
            <td><form:input path="user_org" readonly="${readonly }" tabindex="7"/>&nbsp;</td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
            </tr>
            <tr>
            <td>&nbsp;</td>
            <c:if test="${!readonly }">
            <td class="style1"><input name="search" type="submit"
            			value="Save" tabindex="8" >&nbsp;</td>
            </c:if>
            <td><input name="reset" type="reset" value="Reset" tabindex="9">&nbsp;</td>
            <td>&nbsp;</td>
            				</tr>
            			</table>
            		</form:form>
            my controller's handler method
            The class level annotation for the controller
            @Controller
            @SessionAttributes ({"user","dmsUser"})
            @RequestMapping("/userDetails.do")

            Code:
            @RequestMapping(method = RequestMethod.POST)
              public String saveUser(@ModelAttribute("user") DMSUser user,
                                     @ModelAttribute("dmsUser")DMSUser dmsUser, 
                                     BindingResult result,
                                       Model model) {
            
                String forward = "";
                try{
                validator.validate(dmsUser, result);
                if(result.hasErrors()){
                  model.addAttribute("roles", userService.getRoles());
                  return "dmsUserDetails";
                }
                
                        
              
                if (user == null || user.getPermissions().get("manageuser") < 2) {
            
                  model.addAttribute("message", "unauhorized operation");
                  forward = "dmsHome";
                } else {
                  try {
                    logger.info("Saving the user");
                    if(dmsUser.getUserId()!=0)
                      userService.updateUser(dmsUser);
                    else
                      userService.saveUser(dmsUser);
                    forward = "success";
                  } catch (Exception e) {
                    logger.error("Error occured while saving the user");
                    model.addAttribute("roles", userService.getRoles());
                    model.addAttribute("error", "fatal");
                    forward = "dmsUserDetails";
                  }
            
                }
                }catch (Exception e) {
                  logger.error("Invalid Number");
                  //result.addError(new Err)
                }
                return forward;
              }
            My command class
            Code:
            package com.scientia.dms.commons.vo;
            
            import java.io.Serializable;
            import java.util.Map;
            
            import org.apache.commons.lang.builder.HashCodeBuilder;
            
            public class DMSUser implements Serializable {
              private int userId;
            
              private String userName;
            
              private String password;
            
              private String passwordEncr="n";
            
              private String emailId;
            
              private Long phoneNo;
            
              private DMSRole role=new DMSRole();
              
              private Map<String, Integer> permissions;
              
              private String user_org ;
              
            
              public DMSUser() {
               
              }
              public String getEmailId() {
                return emailId;
              }
            
              public void setEmailId(String emailId) {
                this.emailId = emailId;
              }
            
              public String getPassword() {
                return password;
              }
            
              public void setPassword(String password) {
                this.password = password;
              }
            
              public String getPasswordEncr() {
                return passwordEncr;
              }
            
              public void setPasswordEncr(String passwordEncr) {
                this.passwordEncr = passwordEncr;
              }
            
              
              
              public DMSRole getRole() {
                return role;
              }
            
              public void setRole(DMSRole role) {
                this.role = role;
              }
            
              public int getUserId() {
                return userId;
              }
            
              public void setUserId(int userId) {
                this.userId = userId;
              }
            
              public String getUserName() {
                return userName;
              }
            
              public void setUserName(String userName) {
                this.userName = userName;
              }
            
              public Map<String, Integer> getPermissions() {
                return permissions;
              }
            
              public void setPermissions(Map<String, Integer> permissions) {
                this.permissions = permissions;
              }
            
              public String getUser_org() {
                return user_org;
              }
            
              public void setUser_org(String user_org) {
                this.user_org = user_org;
              }
              public Long getPhoneNo() {
                return phoneNo;
              }
              public void setPhoneNo(Long phoneNo) {
                this.phoneNo = phoneNo;
              }
              
              
            }

            Comment


            • #7
              The PropertyEditors shouldn't convert anything only valid values, if something went wrong throw an exception. That exception will be handled by the controller. Which generates a list of messages code, that is where the DefaultMessageCodesResolver comes in.

              So in your case if you would be using the default PropertyEditor there would the following error codes.

              Code:
              typeMismatch.dmsUser.phoneNo
              typeMismatch.phoneNo
              typeMismatch.java.lang.Long
              typeMismatch
              Now if you configure a MessageSource inside your application context and include a properties file which includes one of those error codes, spring will use the message from the properties file.

              Comment


              • #8
                The PropertyEditors shouldn't convert anything only valid values, if something went wrong throw an exception. That exception will be handled by the controller.
                Here the problem is I am not able to handle the excpetion thrown by the PropertyEditor in my controller, as the excpetion is not reaching there.
                Here is my PropertyEditor's setAsText() code
                Code:
                public void setAsText(String text) throws IllegalArgumentException {
                    // If the text is null or empty string, then set to default value.
                   
                    if (StringUtils.isEmpty(text) == true) {
                      setValue(this.defaultValue);
                    }
                
                    // use given NumberFormat for parsing text
                    else if (this.numberFormat != null) {
                      setValue(NumberUtils.parseNumber(text, this.numberClass,
                          this.numberFormat));
                    }
                
                    // use default valueOf methods for parsing text
                    else {
                         
                              NumberUtils.parseNumber(text, this.numberClass);
                    }
                   
                  }
                This would throw a NumberFormatException from the PropertyEditor, which I am not getting in the controller.It is directly thrown back to the DispatcherServlet and hence crashing the session!!!
                I tried to put a try catch in my controller but nothing happened.Is there anything else I should do to get it in the controller.

                Appreciating your efforts
                Shaiju

                Comment


                • #9
                  Why are you expecting a NumberFormatException? This method as well as NumberUtils.parseNumber(..,..,..) throws an IllegalArgumentException not the NumberFormatException. Shouldn't you be looking for that instead?

                  Comment


                  • #10
                    What I mean is I am trying to catch the generic Exception.
                    Not even NumberFormat or IllegalArgumentExcpetion.
                    Btw , Just now I found out that the issues is becasue my handler method pasted below
                    (Please note that I have a class level annotation @SessionAttributes ("user"))
                    Code:
                    @RequestMapping(method = RequestMethod.POST)
                      public String saveUser(@ModelAttribute("user") DMSUser user,
                                                     @ModelAttribute("dmsUser")DMSUser dmsUser, 
                                             BindingResult result,
                                               Model model)
                    if you see here I have two different objects of DMSUSer passed in modelattribute (one "user" is a session attribute and the other "dmsUser" is the model attribute,where I expected spring wound bind the data from the form the the binding result would be available in "result").I am not sure I am doing right here.
                    WHen I closely looked at the error log its showed me that the exception aroused when spring binds the values to "user" object.I dont know why spring tries to bind it to "user" object .I have mentioned the model attribute in my jsp as
                    Code:
                    <form:form modelAttribute="dmsUser" onsubmit="return validate();">
                    but spring tries to bind the form input to "user" object,not the dmsUser object and hence the bindng result is not captured in the "result".
                    I have tried to add one more BindingResult as
                    Code:
                      @RequestMapping(method = RequestMethod.POST)
                      public String saveUser(@ModelAttribute("user") DMSUser user,
                                              BindingResult result1,
                                             @ModelAttribute("dmsUser")DMSUser dmsUser, 
                                             BindingResult result,
                                               Model model) {
                    and it worked.But I dont think this is the right way!!!
                    Last edited by shaiju; Aug 20th, 2008, 01:39 PM. Reason: Added code snipllets

                    Comment


                    • #11
                      The latter is the right way. You need a BindingResult for each object you are binding to.

                      Comment


                      • #12
                        OK.Thank you
                        Btw can you tellme why spring tries to bind teh values inot the "user" object which is a session attribute,rather than binding to "dmsUser" which is a request attribute??

                        Shaiju

                        Comment

                        Working...
                        X