views:

410

answers:

2

While creating my first swf application with JSF integration, I get the following error : Unable to load class 'dataModel' when parsing my flow definition on the first request.

It appears that the FacesConversionService (the class that understands the 'dataModel' alias) is not invoked while trying to find a class for that alias, although my webflow application context contains the <faces:flow-builder-services/> tag in it.

Doing some debug while trying to find out the cause, I noticed the following:

  1. the xml file containing <faces:flow-builder-services/> is loaded by the context loader listener, and the facesConversionService bean is registered
  2. the flow handler mapping and adapter are correctly invoked and the request is forwarded to the expected flow, which definition is created on the fly.
  3. while creating internal infrastructure objects for the flow, swf creates a web application context on top of the app context loaded by the listener. This new wac contains the definitions for the swf scopes, etc, and has the listener's application context from above as parent.
  4. the flow definition file for my flow is found and parsed, and when it tries to find the class for the result type of an evaluate element, the conversion service does not know about the 'dataModel' alias.

Actually, the funny thing on the last point is that the conversion service is either looked up as a local bean in the application context created on point 3. above, or -if not found- looked up in the parent flow builder context.

The faces conversion service is neither a local bean of the context (it is registered in the parent context of the flow context), nor is it registered as the conversion service of the flow builder context (at least the FlowBuilderContextImpl that is created by the <flow:flow-registry/> element).

Does anybody know what went wrong ?

I don't think it's related to the application server, but just in case, I'm running on websphere 6.1.0.23, with spring 2.5.6 and webflow 2.0.8.RELEASE.

Here are my configuration files:

web.xml:

<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext-*.xml</param-value>
</context-param>
...
<servlet>
  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value></param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
  <url-pattern>/swf/*</url-pattern>
</servlet-mapping>

Beans definitions for the MVC part (/WEB-INF/applicationContext-webmvc.xml):

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
  <property name="flowRegistry" ref="flowRegistry" />
  <property name="defaultHandler">
    <bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
  </property>
</bean>

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
  <property name="flowExecutor" ref="flowExecutor" />
</bean>

<bean id="faceletsViewResolver" 
  class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  <property name="viewClass" value="org.springframework.faces.mvc.JsfView" />
  <property name="prefix" value="/WEB-INF/" />
  <property name="suffix" value=".jspx" />
</bean>

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

Beans definitions for the swf part (/WEB-INF/applicationContext-webflow.xml):

<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows">
  <flow:flow-location path="/navigation/navigation.xml"/>
  <flow:flow-location path="/edition/edition.xml"/>
</flow:flow-registry>

<flow:flow-executor id="flowExecutor">
  <flow:flow-execution-listeners>
      <flow:listener ref="jpaFlowExecutionListener" criteria="edition"/>
  </flow:flow-execution-listeners>
</flow:flow-executor>

<faces:flow-builder-services id="facesFlowBuilderServices" development="true"/>

<bean id="jpaFlowExecutionListener" 
        class="org.springframework...JpaFlowExecutionListener">
  <constructor-arg ref="entityManagerFactory" />
  <constructor-arg ref="transactionManager" />
</bean>

The stack trace for the exception:

[Servlet Error]-[Spring MVC Dispatcher Servlet]: java.lang.IllegalArgumentException: Unable to load class 'dataModel'                                                                
 at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.toClass(FlowModelFlowBuilder.java:965)                                                                    
 at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseEvaluationActionResultExposer(FlowModelFlowBuilder.java:867)                                         
 at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseEvaluateAction(FlowModelFlowBuilder.java:858)                                                        
 at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseActions(FlowModelFlowBuilder.java:834)                                                               
 at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseAndAddViewState(FlowModelFlowBuilder.java:547)                                                       
 at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.buildStates(FlowModelFlowBuilder.java:207)                                                                
 at org.springframework.webflow.engine.builder.FlowAssembler.directAssembly(FlowAssembler.java:106)                                                                                 
 at org.springframework.webflow.engine.builder.FlowAssembler.assembleFlow(FlowAssembler.java:91)                                                                                    
 at org.springframework.webflow.engine.builder.DefaultFlowHolder.assembleFlow(DefaultFlowHolder.java:109)                                                                           
 at org.springframework.webflow.engine.builder.DefaultFlowHolder.getFlowDefinition(DefaultFlowHolder.java:84)                                                                       
 at org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl.getFlowDefinition(FlowDefinitionRegistryImpl.java:61)                                                
 at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:138)                                                                                
 at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:193)                                                                                  
 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)                                                                                        
 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)                                                                                         
 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)                                                                                      
 at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)                                                                                               
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:743)
A: 

I had the same problem but it was because I was specifying my own conversion service which extended DefaultConversionService rather than FacesConversionService.

Dean
A: 

I forgot to specify the flow-builder-services attribute on flow:flow-registry element !!! Works perfectly now.

<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows" flow-builder-services="facesFlowBuilderServices">
   <flow:flow-location path="/navigation/navigation.xml"/>
   <flow:flow-location path="/edition/edition.xml"/>
</flow:flow-registry>

<faces:flow-builder-services id="facesFlowBuilderServices" development="true"/>
Gaetan