Announcement Announcement Module
Collapse
No announcement yet.
SOLVED: ConverterNotFoundException for Roo entity in WebFlow Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • SOLVED: ConverterNotFoundException for Roo entity in WebFlow

    NOTE: This started out as a question, but ended up being a great way to talk myself through identifying the issue. Since I'd already written it all up, I'm posting anyway in case it helps someone. I have seen other workarounds to this error, but this eliminates hand-coding Converters & leverages existing Roo generated artifacts - it seems the right way to me.

    The experience also suggests some potential improvements to Roo WebFlow integration:
    1. Register the ConversionServiceExposingInterceptor with FlowHandlerMapping by default when generating webflow-config.xml
    2. Remove the AnnotationMethodHandlerAdapter bean definition from webflow-config.xml. This bean is already registered by the <mvc:annotation-driven> magic.
    3. Remove the SimpleControllerHandlerAdapter bean definition from webflow-config.xml. Roo uses Annotation-based Controllers by default - if someone wants to use concrete Controller implementations, they can explicitly add this bean definition back, and probably put it in webmvc-config.xml where it belongs.

    Anyway, here's the details:
    ----------------------------------------

    I am getting an error when rendering a Roo entity using the autogenerated show.jspx view from a Web Flow. The error is:

    Code:
    org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from 'java.util.Set' to 'java.lang.String'
    I think this is not a Roo-specific issue; however, the Roo-generated Controllers do not exhibit the issue so I though it was worth posting here.

    I have a working Roo project with a couple of entities, including OneToMany and ManyToMany relationships between some of them. For instance I have a Metric entity and a PracticeItem entity that has a Set<Metric> of "supportedMetrics", marked @ManyToMany.

    The Roo-generated MVC controllers & views render these entities properly. I have created a flow for PracticeItems & copied across the autogenerated CRUD view JSPX files into the flow folder. I configured the flow's views.xml to point at these copies. Finally, I've edited the flow to make the PracticeItem entity instance available to the view in requestScope. When navigating to this view via the flow, I get the above error.

    After some research, I found that WebFlow configures its own ConversionService in the FlowBuilderServices bean. Further this is a Spring Binding ConversionService that has a different package name & method signatures from the Spring Core ConversionService. Roo has auto-generated an ApplicationConversionServiceFactoryBean of the latter (Spring Core) type that includes custom Converters for PracticeItem and Metric entities.

    I tried creating a Spring Binding DefaultConversionService which can delegate to a Spring Core ConversionService passed in to the constructor; I wired this to FlowBuilderServices. This did not help.

    Remote debugging through the code, I eventually found that the problem originates in the Spring EvalTag used in the Roo-generated display.tagx tag handler. That eval tag is used to render the entities property like using a Spring EL expression:

    HTML Code:
    <spring:eval expression="object[field]" />
    It appears that sometimes that tag expects to retrieve the ConversionService from the pageContext/request. If it's not there, it creates a default one - without the custom converters. That was the origin of my problem.

    With further research I found that the <mvc:annotation-driven /> magic registers a ConversionServiceExposingInterceptor which does what it says, and makes sure that ConversionService is always available on the request (docs point out specifically that eval tag relies on this). This is great - but it only does this for MVC HandlerMappings!

    SOLUTION: contstruct an instance of ConversionServiceExposingInterceptor, passing in Roo-generated ApplicationConversionService. Register this intercepter with FlowHandlerMapping's "interceptors" property. A fragment of webflow-config.xml is below. Note that applicationConversionService is the Roo-generated artifact defined in webmvc-config.xml

    HTML Code:
    <bean id="conversionServiceExposingInterceptor" class="org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor">
        <constructor-arg ref="applicationConversionService" />
    </bean>
    	
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
        <property name="order" value="0" />
        <property name="flowRegistry" ref="flowRegistry" />
        <property name="interceptors">
            <array>
                <ref bean="conversionServiceExposingInterceptor"/>
            </array>
        </property>
    </bean>
    
    <!-- NOTE: commenting out these as they appear unnecessary!!! -->
    <!--Dispatches requests mapped to POJO @Controllers implementations-->
    <!--  <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> -->
    
    <!-- Dispatches requests mapped to org.springframework.web.servlet.mvc.Controller implementations -->
    <!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> -->

  • #2
    Nice work

    Good digging for what looks like an elegant solution; why not log your suggested improvements as a JIRA issue?

    Comment


    • #3
      JIRA issue

      Good point, I did that this morning: ROO-2275

      Comment


      • #4
        Thanks for your efforts there. I'll look at this soon and integrate it in our default scaffolding.

        Comment

        Working...
        X