Announcement Announcement Module
Collapse
No announcement yet.
Problem with JSF, JSF-Custom-Converter, Spring Faces Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem with JSF, JSF-Custom-Converter, Spring Faces

    Hello Spring Community,

    this is my first post here so I hope I'll make it right.

    As you can see in title I have a problem with converter like a lot of others (i searched the forum for that). The base is the swf-booking-faces application which comes with the spring-webflow-2.0.9.RELEASE.zip.
    So now i would like to go in more detail:

    I try to map an jsf multiple selectbox to an model property of type set. Cause of this thread http://forum.springsource.org/showth...=jsf+converter where Keith Donald explained that JSF Conversion is not supported in Web-Flow-Converters i try to use JSF-Converters configured in the faces-config.xml.

    The funny thing is, the converter works like expected, at least in the render phase, where the getAsString() Method is called. But when i submit the form spring web flow (at least i think it is) trys to convert an shows an conversion error in the view.

    If i set the transition to bind="false" then i have no data in the model at all.

    So is there a best practice to use Spring Web Flow with JSF, espeacially for the Model binding and Conversion?

    My working environment is:
    spring-(Core, MVC, Security) 3.0.2
    spring-webflow 2.0.9
    spring-faces 2.0.9
    sun.facelets 1.1.14
    javax.faces 1.2.0.09
    sun.faces 1.2.0.09

    faces-config.xml
    Code:
    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
        <!-- Enables Facelets -->
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    </application>
    
    <converter>
        <converter-for-class>de.malberg_edv.mambo.objects.Usergroup</converter-for-class>
        <converter-class>de.malberg_edv.mambo.web.converter.UsergroupConverter</converter-class>
    </converter>
    webflow-config.xml

    Code:
    <webflow:flow-executor id="flowExecutor">
        <webflow:flow-execution-listeners>
            <webflow:listener ref="hibernateFlowExecutionListener" />
    	<webflow:listener ref="securityFlowExecutionListener" />
    	<webflow:listener ref="viewStateFlowExecutionListener" />
        </webflow:flow-execution-listeners>
    </webflow:flow-executor>
    
    <webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices" base-path="/WEB-INF/flows">
        <webflow:flow-location-pattern value="/**/*-flow.xml" />
    </webflow:flow-registry>
    
    <faces:flow-builder-services id="facesFlowBuilderServices" conversion-service="mamboConversionService" expression-parser="expressionParser"/>
    
    <bean id="expressionParser" class="org.springframework.webflow.expression.el.WebFlowELExpressionParser">
        <constructor-arg>
            <bean class="org.jboss.el.ExpressionFactoryImpl"/>
        </constructor-arg>
        <property name="conversionService" ref="mamboConversionService"/>
    </bean>
    <bean id="hibernateFlowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
        <constructor-arg ref="sessionFactory" />
        <constructor-arg ref="transactionManager" />
    </bean>
    <bean id="securityFlowExecutionListener" class="de.malberg_edv.mambo.security.CustomSecurityFlowExecutionListener" />
    createUser-flow.xml
    Code:
    ...
    <persistence-context />
    <input name="userId" required="false" />
    
    <on-start>
        <evaluate expression="userService.getUser(userId)" result="flowScope.user" />
    </on-start>
    
    <view-state id="newUserForm" model="user">
        <on-render>
            <evaluate expression="SelectItems.selectItems(usergroupService.getAllUserGroups(),'Id', 'Name')" result="viewScope.allUsergroups" />
        </on-render>
        <transition on="proceed" to="reviewNewUser" />
    </view-state>
    
    <view-state id="reviewNewUser" model="user">
        <transition on="confirm" to="newUserConfirmed" />
        <transition on="revise" to="newUserForm" />
    </view-state>
    ...
    newUserForm.xhtml
    Code:
    ...
    <h:form id="newUserForm">
    ...
    <h:selectManyListbox id="usergroups" value="#{user.usergroups}" >
        <f:selectItems value="#{allUsergroups}" />
    </h:selectManyListbox>
    ...
    <sf:validateAllOnClick>
        <sf:commandButton id="proceed" action="proceed" processIds="*" value="#{labels.proceed}" />*
    </sf:validateAllOnClick>
    ...
    </h:form>
    UsergroupConverter.java
    Code:
    package de.malberg_edv.mambo.web.converter;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.convert.Converter;
    import javax.faces.convert.ConverterException;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import de.malberg_edv.mambo.objects.Usergroup;
    import de.malberg_edv.mambo.service.UsergroupService;
    
    public class UsergroupConverter implements Converter
    {
    	@Autowired
    	UsergroupService usergroupService;
    
    	public UsergroupConverter()
    	{
    	     //Just the make sure the Converter ist created
                 System.out.println("UsergroupConverter");
    	}
    
    	/**
             *should return a Usergroup for a given Id but don't even get called
             */
            @Override
    	public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException
    	{
    		if(value == null)
    			return null;
    		else if(value.equals("") || value.equals("-1"))
    			return null;
    		else
    		{
    			try
    			{
    				return usergroupService.getUsergroup(Long.parseLong(value));
    			}
    			catch (Exception e)
    			{
    				// TODO: handle exception
    				throw new ConverterException(new FacesMessage(e.getLocalizedMessage()));
    			}
    		}
    	}
    
    	
            /**
             * returns the id as String for the given Object
             */
            @Override
    	public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException
    	{
    		if(value == null)
    			return null;
    		else if(value instanceof Usergroup)
    			return Long.toString(((Usergroup)value).getId());
    		else if(value instanceof String)
    			return (String)value;
    		else if(value instanceof Long)
    			return ((Long)value).toString();
    		else if(value instanceof Integer)
    			return ((Integer)value).toString();
    		else
    		{
    			throw new ConverterException(new FacesMessage("UsergroupConverter: wrong Type"));
    		}
    
    	}
    
    	public static String getAsString(Usergroup usergroup)
    	{
    		return usergroup.getName();
    	}
    }

  • #2
    For one, if you're using JSF, I don't think there's any advantage to using the model attribute in your view-state. It's already easy enough to bind values to your model with JSF alone. I think this is used mostly when using Spring MVC instead of JSF.

    As for myself, I HATE the way JSF deals with selectItems. It puzzles me why one should write converters to translate Strings to and from custom objects, when one might be able to use selected indices to find the exact object in the underlying collection.

    I've previously created a helper class to make it simpler to deal with selectOne elements. I imagine it wouldn't be much harder to make a similar class or an extension for SelectMany elements.

    Comment


    • #3
      Thanks InverseFalcon for the quick reply.

      Your approach is intersting but didn't worked for me. Cause with the SelectMany* component spring faces trys to convert no matter what.
      Additionally the c:forEach nor the ui:repeat tag was working in my application, so I couldn't use the index.

      The converter approatch is working now.

      The problem was in the model, where user.usergroups is an HashSet<Usergroup>. So the getAsString() was called, but not the getAsObject() method.

      Now if I change the type of user.usergroups to List<Usergroup> the converter is working and there is no interference with Spring Face Conversion like I think there was.

      But anyway, thanks for the help.

      Comment

      Working...
      X