Announcement Announcement Module
No announcement yet.
Translating PropertyEditor exceptions to messages Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Translating PropertyEditor exceptions to messages

    My PropertyEditor class resolves "id strings" (essentially primary keys) to domain objects of some specific class.
    A manager class (could be a Dao or higher level service) is injected for this purpose.

    These are three possible failure points in the setAsText method execution:

    1) The string representation being converted is not of the correct format.(NumberFormatException)
    2) No object can be found for the supplied id.(ObjectNotFoundException thrown by manager)
    3) The object exists, but is not authorized for use by the current user.(SecurityException thrown by manager)

    public class FoobarPropertyEditor extends PropertyEditorSupport
        private FoobarManager manager;
    	public FoobarPropertyEditor(FoobarManager manager)
    		this.manager = manager;
    	public String getAsText()
            Foobar foobar = (Foobar)getValue();
            if(foobar == null) return "";
            else return String.valueOf(foobar.getId());
        public void setAsText(String text) throws IllegalArgumentException
    			int id = Integer.parseInt(text);
    			foobar = manager.find(id);
    		catch(NumberFormatException nfe)
    			throw new IllegalArgumentException("Invalid value", nfe);
    		catch(EntityNotFoundException enfe)
    			throw new IllegalArgumentException("Foobar not found", enfe)
    		catch(SecurityException se)
    			throw new IllegalArgumentException("Access to foobar denied", se)
    I can't find much information in the reference docs or the sample apps on how to handle exceptions from custom PropertyEditors.
    How do I customize the translation from various IllegalArgumentExceptions to user-friendly messages?

    Some piece of code should examine the IllegalArgumentException, retrieve the nested cause, and work with that. But how do I inject such logic into the DataBinder?

  • #2
    I've explored the DataBinder and BeanWrapper source a bit...

    Unfortunately the current implementation of the DataBinder swallows the original exception cause coming from a PropertyEditor (through the BeanWrapper).

    The relevant source snippet is quoted below (spring 1.1.2):
    (, lines 312-326)
    try {
    	// bind request parameters onto params, ignoring unknown properties
    	this.errors.getBeanWrapper().setPropertyValues(pvs, true);
    catch (PropertyAccessExceptionsException ex) {
    	PropertyAccessException[] exs = ex.getPropertyAccessExceptions();
    	for &#40;int i = 0; i < exs.length; i++&#41; &#123;
    		// create field with the exceptions's code, e.g. "typeMismatch"
    		String field = exs&#91;i&#93;.getPropertyChangeEvent&#40;&#41;.getPropertyName&#40;&#41;;
    				new FieldError&#40;this.errors.getObjectName&#40;&#41;, field, exs&#91;i&#93;.getPropertyChangeEvent&#40;&#41;.getNewValue&#40;&#41;, true,
    				this.errors.resolveMessageCodes&#40;exs&#91;i&#93;.getErrorCode&#40;&#41;, field&#41;,
    				getArgumentsForBindingError&#40;field&#41;, exs&#91;i&#93;.getLocalizedMessage&#40;&#41;&#41;&#41;;
    The PropertyAccessExceptions coming from the BeanWrapper have a cause property (derived form Throwable).
    However, this piece of information is not stored in the FieldError instance created.
    All FieldErrors caused by PropertyEditor exceptions are coded as "typeMismatch", since BeanWrapperImpl#doTypeConversionIfNecessary() translates all IllegalArgumentExceptions to TypeMismatchExceptions.

    I'm quite curious how Spring's claim of being able to "do away with ActionForms and bind to your domain model" works out for others.
    Having built quite a number of enterprise applications, I know that there are quite a number of failure paths for translating an String id to a live domain object instance.

    How can I bind to a rich domain model other then by using PropertyEditors?
    How can I use PropertyEditors if I can't differentiate between various, distinct, potential failures?


    • #3
      you might want to take a look at the Validator interface (org.springframework.validation)....

      you simply implement a validator and register it with your controller

      in the validate() method of your validator, you simply complete all of your tests, and set appropriate errors.. .which are then displayed by the status.errorMessage part of your spring:bind tags


      • #4
        Validation takes place after binding.

        Since the binding failure for the field hides the reason for the failure, there's no data for the validation phase to work with.


        • #5
          user-friendly messages

          In order to customize the translation from various IllegalArgumentExceptions to user-friendly messages you could take a look at "DefaultMessageCodesResolver"

          E.g. in case of code "typeMismatch", object name "user", field "age":

          try "typeMismatch.user.age"


          • #6
            Re: user-friendly messages

            Originally posted by njayalath
            In order to customize the translation from various IllegalArgumentExceptions to user-friendly messages you could take a look at "DefaultMessageCodesResolver"

            E.g. in case of code "typeMismatch", object name "user", field "age":

            try "typeMismatch.user.age"
            The problem with above work-around is that the nondescriptive typeMismatch.user.age could be caused by different domain exceptions.

            I want to be able to distinguish between
            -object not found
            -security failure
            -some domain specific logic preventing the user from obtaining the entity instance
            -perhaps an actual type mismatch (e.g. user filled in nonsense input)

            By the time my message translator gets a chance, the relevant information has already been dropped by the databinder.

            To summarize, the functionality I'm after is a strategy interface to let the binding infrastructure translate IllegalArgumentExceptions (actually the nested cause) thrown by a PropertyEditor to custom message codes.