Tapestry
  1. Tapestry
  2. TAPESTRY-2276

Required validation fails when used with select and blankOption="ALWAYS"

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.0.11
    • Fix Version/s: 5.0.12
    • Component/s: None
    • Labels:
      None

      Description

      I have drop down defined like this:

      <t:select t:model="selectModel" label="message:orient.admin.entity.manufacturer.edit.country" t:id="countrySelectDrop" t:value="manufacturer.country.id" t:validate="required" blankLabel="message:select-blanklabel" blankOption="ALWAYS"></t:select>

      I thought that this should produce the normal "You must provide value for xxxxx." notification, but it results in type coersion error (manufacturer.counrty.id is Integer.)

      It seems that the coersion happens before required validation and in select one only catches ValidationException.

      try

      { _fieldValidationSupport.validate(selectedValue, _resources, _validate); _value = selectedValue; }

      catch (ValidationException ex)

      { _tracker.recordError(this, ex.getMessage()); }

      Is this a bug or am I missing something obvious?

      StackTrace:

      1. java.lang.NumberFormatException
        For input string: ""

      Stack trace

      • java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
      • java.lang.Long.parseLong(Long.java:424)
      • java.lang.Long.<init>(Long.java:671)
      • org.apache.tapestry.ioc.services.TapestryIOCModule$7.coerce(TapestryIOCModule.java:159)
      • org.apache.tapestry.ioc.services.TapestryIOCModule$7.coerce(TapestryIOCModule.java:157)
      • org.apache.tapestry.ioc.services.CoercionTuple$CoercionWrapper.coerce(CoercionTuple.java:54)
      • org.apache.tapestry.ioc.internal.services.CompoundCoercion.coerce(CompoundCoercion.java:46)
      • org.apache.tapestry.ioc.internal.services.TypeCoercerImpl.coerce(TypeCoercerImpl.java:126)
      • org.apache.tapestry.internal.services.TypeCoercedValueEncoderFactory$1.toValue(TypeCoercedValueEncoderFactory.java:45)
      • org.apache.tapestry.corelib.components.Select.processSubmission(Select.java:146)
      • org.apache.tapestry.corelib.base.AbstractField.processSubmission(AbstractField.java:184)
      • org.apache.tapestry.corelib.base.AbstractField.access$100(AbstractField.java:33)
      • org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionAction.execute(AbstractField.java:97)
      • org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionAction.execute(AbstractField.java:91)
      • org.apache.tapestry.corelib.components.Form.executeStoredActions(Form.java:405)
      • org.apache.tapestry.corelib.components.Form.onAction(Form.java:331)
      • org.apache.tapestry.corelib.components.Form.dispatchComponentEvent(Form.java)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl.dispatchEvent(ComponentPageElementImpl.java:851)
      • org.apache.tapestry.internal.structure.ComponentPageElementImpl.triggerContextEvent(ComponentPageElementImpl.java:1004)
      • org.apache.tapestry.internal.services.ComponentEventRequestHandlerImpl.handle(ComponentEventRequestHandlerImpl.java:67)
      • org.apache.tapestry.internal.services.ImmediateActionRenderResponseFilter.handle(ImmediateActionRenderResponseFilter.java:42)
      • org.apache.tapestry.internal.services.AjaxFilter.handle(AjaxFilter.java:42)
      • org.apache.tapestry.services.TapestryModule$40.handle(TapestryModule.java:2110)
      • org.apache.tapestry.internal.services.ComponentEventDispatcher.dispatch(ComponentEventDispatcher.java:135)
      • org.apache.tapestry.services.TapestryModule$13.service(TapestryModule.java:944)
      • com.orient.webshop.services.AppModule$1.service(AppModule.java:76)
      • com.orient.webshop.services.AppModule$3.service(AppModule.java:128)
      • org.apache.tapestry.internal.services.LocalizationFilter.service(LocalizationFilter.java:42)
      • org.apache.tapestry.services.TapestryModule$3.service(TapestryModule.java:553)
      • org.apache.tapestry.services.TapestryModule$2.service(TapestryModule.java:520)
      • org.apache.tapestry.internal.services.StaticFilesFilter.service(StaticFilesFilter.java:79)
      • org.apache.tapestry.internal.services.CheckForUpdatesFilter$2.invoke(CheckForUpdatesFilter.java:93)
      • org.apache.tapestry.internal.services.CheckForUpdatesFilter$2.invoke(CheckForUpdatesFilter.java:84)
      • org.apache.tapestry.ioc.internal.util.ConcurrentBarrier.withRead(ConcurrentBarrier.java:77)
      • org.apache.tapestry.internal.services.CheckForUpdatesFilter.service(CheckForUpdatesFilter.java:106)
      • org.apache.tapestry.services.TapestryModule$12.service(TapestryModule.java:924)
      • org.apache.tapestry.upload.internal.services.MultipartServletRequestFilter.service(MultipartServletRequestFilter.java:43)
      • org.apache.tapestry.internal.services.IgnoredPathsFilter.service(IgnoredPathsFilter.java:62)
      • org.apache.tapestry.TapestryFilter.doFilter(TapestryFilter.java:168)
      • org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      • org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:265)
      • org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107)
      • org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
      • org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:124)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
      • org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
      • org.acegisecurity.ui.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
      • org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
      • org.acegisecurity.securechannel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:138)
      • org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
      • org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:149)
      • org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:183)
      • org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:138)
      • org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      • org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      • org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
      • org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:75)
      • org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      • org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      • org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
      • org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
      • org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
      • org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
      • org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      • org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
      • org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
      • org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
      • org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
      • java.lang.Thread.run(Thread.java:619)

        Activity

        Hide
        Howard M. Lewis Ship added a comment -

        The empty string is now treated as null prior to validation.

        Show
        Howard M. Lewis Ship added a comment - The empty string is now treated as null prior to validation.
        Hide
        Ville Virtanen added a comment -

        Hmm, tested this 8.4.2008, and it still occurred. (Used the nightly build.) Solution for us is to use our homegrown encoders. (That actually check against the nulls ) That's no biggie, just few more lines to maintain.

        Show
        Ville Virtanen added a comment - Hmm, tested this 8.4.2008, and it still occurred. (Used the nightly build.) Solution for us is to use our homegrown encoders. (That actually check against the nulls ) That's no biggie, just few more lines to maintain.
        Hide
        Kristian Marinkovic added a comment -
        Show
        Kristian Marinkovic added a comment - this issue was solved by https://issues.apache.org/jira/browse/TAPESTRY-2260
        Hide
        Ville Virtanen added a comment - - edited

        Well, did some digging and found out that the IntegerTranslator doesn't do what the comments say... It's missing

        if(clientValue.trim().equals(EMPTY_STRING))

        { return null; }

        from parseClient and

        if(value == null)

        { return EMPTY_STRING; }

        from toClient (And anywhere on the body you like: private static final String EMPTY_STRING = ""

        Below is the current implementation from 5.0.11:

        /**

        • A translator for type integer.
          */
          public final class IntegerTranslator implements Translator<Integer>
          {
          public Class<Integer> getType() { return Integer.class; }

        /**

        • Parses blank values to null, otherwise parses the client value to an integer.
          *
        • @throws ValidationException if the clientValue can not be parsed as an integer
          */
          public Integer parseClient(String clientValue, Messages messages) throws ValidationException
          {

        try

        { return new Integer(clientValue.trim()); }

        catch (NumberFormatException ex)

        { throw new ValidationException(messages.format("integer-format-exception", clientValue)); }

        }

        /**

        • Converts null to the blank string, non-null to a string representation.
          */
          public String toClient(Integer value) { return value.toString(); }

        }

        Show
        Ville Virtanen added a comment - - edited Well, did some digging and found out that the IntegerTranslator doesn't do what the comments say... It's missing if(clientValue.trim().equals(EMPTY_STRING)) { return null; } from parseClient and if(value == null) { return EMPTY_STRING; } from toClient (And anywhere on the body you like: private static final String EMPTY_STRING = "" Below is the current implementation from 5.0.11: /** A translator for type integer. */ public final class IntegerTranslator implements Translator<Integer> { public Class<Integer> getType() { return Integer.class; } /** Parses blank values to null, otherwise parses the client value to an integer. * @throws ValidationException if the clientValue can not be parsed as an integer */ public Integer parseClient(String clientValue, Messages messages) throws ValidationException { try { return new Integer(clientValue.trim()); } catch (NumberFormatException ex) { throw new ValidationException(messages.format("integer-format-exception", clientValue)); } } /** Converts null to the blank string, non-null to a string representation. */ public String toClient(Integer value) { return value.toString(); } }
        Hide
        Ville Virtanen added a comment -

        Typos away!

        Show
        Ville Virtanen added a comment - Typos away!

          People

          • Assignee:
            Howard M. Lewis Ship
            Reporter:
            Ville Virtanen
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development