I am trying to follow the code for Spring Webflow from 'Spring in Action'. However, when I tried to run the application, I got the following error:
org.springframework.webflow.engine.FlowInputMappingException: Errors occurred during input mapping on startup of the 'pizza' flow; errors = [[RequiredError#13cb4078 mapping = order -> flowScope.order, code = 'required', error = true, errorCause = [null], originalValue = [null], mappedValue = [null]]]
I believe the line that instantiates the order object in the following flow xml is responsible for the exception:
<var name="order" class="com.mycompany.pizza.domain.Order" />
<subflow-state id="customer" subflow="customer-flow">
<input name="order" value="order"/>
<transition on="customerReady" to="buildOrder" />
</subflow-state>
My subflow xml looks like this:
<view-state id="welcome">
<transition on="phoneEntered" to="lookupCustomer" />
</view-state>
<action-state id="lookupCustomer">
<evaluate result="order.customer"
expression="pizzaFlowActions.lookupCustomer(requestParameters.phoneNumber)" />
<transition to="registrationForm"
on-exception="com.mycompany.pizza.service.CustomerNotFoundException" />
<transition to="customerReady" />
</action-state>
Hope there's someone who could point me at the right direction. Thanks!
The error is saying you are REQUIRED to pass a NOT NULL input param/obj "order" to your subflow and you are passing a null value in the order input. So if it is not provided it will throw the exception you see. At the top of your subflow should look something like this:
<input name="order" required="true" type="com.mycompany.pizza.domain.Order"/>
That being said, generally I think when passing pojos between flows/subflows it is good practice to be very explicit and fill out the 'type' attribute in both input tags on the caller of the subflow and the subflow itself and to fill out the scope prefix for the value attribute (e.g flowScope.order)
Moreover, I think your problem is that the <var> tag is NOT initializing your Order pojo that is why it is null it is the equiv of:
Order order = null;
You should explicitly set flowScope.order via a new operator or a factory-method call using the 'set' tag inside an 'on-start' tag in beginning of your parent flow. Something like this:
<on-start>
<set name="flowScope.order" value="new com.mycompany.pizza.domain.Order()"/>
<!-- for development purposes... assuming you are using log4j grab the logger and check that order is in fact NOT null -->
<evaluate expression="T(org.apache.log4j.Logger).getLogger('someLogger').info(flowScope.order)"/>
</on-start>
and then (still inside your parent flow) change your subflow call to look like this:
<subflow-state id="customer" subflow="customer-flow">
<input name="order" value="flowScope.order" type="com.mycompany.pizza.domain.Order"/>
<transition on="customerReady" to="buildOrder" />
</subflow-state>
and... Make sure you also fill out the type attribute inside the input tag of your subflow.xml for order like so:
<input name="order" required="true" type="com.mycompany.pizza.domain.Order"/>
Related
I have a sub-flow that is being shown in a popup. When the popup is closed, due to clicking a submit or cancel button, transitioning back to the view-state of the main flow causes a full page reload. The problem is that my underlying parent-flow page contains a file chooser control that loses the user selection when the page is refreshed. In order to retain the inputted data, I would like to update a fragment of the parent-flow's page the way that I can when transitioning between view-states of the same flow.
Here is my flow xml:
Main Flow:
<view-state id="main">
<transition on="start" to="child-flow"/>
<transition on="finish" to="finished"/>
</view-state>
<subflow-state id="child-flow" subflow="main/childFlow">
<transition on="submitted" to="main">
<render fragments="popupClosed" />
</transition>
</subflow-state>
<end-state id="finished" />
Child Flow:
<view-state id="childFlow" view="main/childFlow" popup="true">
<transition on="submit" to="popupClosed" />
<transition on="cancel" to="popupClosed" />
</view-state>
<end-state id="popupClosed" />
I'm using Spring WebFlow v2.0.8 with Tiles and JSPs.
Thanks,
Steph
if you want javascript type pop up/modal functionality dont use the 'popup' attribute implement it like this.
How to include a pop-up dialog box in subflow
I'm trying to add a Forgot Password path to an existing view. I created a new view, action, model bean, and some states in my webflow. Instead of seeing the view, I keep getting the error java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'forgotPassword' available as request attribute. I know the bean exists, and it should be visible. I think I set up the webflow properly, but I'm not 100% sure. Does anybody know what I might be doing wrong?
casLoginView.jsp:
Forgot Password
login-webflow.xml:
<var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />
<var name="forgotPasswordBean" class="com.mycompany.authentication.ForgotPasswordBean" />
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
<transition on="forgotPassword" bind="false" validate="false" to="forgotPasswordView"/>
</view-state>
<view-state id="forgotPasswordView" view="myForgotPasswordView.jsp" model="forgotPasswordBean">
<binder>
<binding property="username" required="true"/>
</binder>
<transition on="submit" to="forgotPassword"/>
</view-state>
<action-state id="forgotPassword">
<evaluate expression="forgotPasswordAction.submit(flowScope.forgotPasswordBean)" />
<transition on="success" to="newPasswordSentView"/>
<transition on="forbidden" to="forgotPasswordForbiddenView"/>
<transition on="error" to="forgotPasswordView"/>
</action-state>
<end-state id="newPasswordSentView" view="myNewPasswordSentView" />
<end-state id="forgotPasswordForbiddenView" view="forgotPasswordForbiddenView" />
Your <form:form ... > tag should reference the correct bean. Your configuration mentions a forgotPasswordBean and not a forgotPassword one.
Either your form object should reference the correct bean
<form:form modelAttribute="forgotPasswordBean" ... >
Or you should rename the bean in your webflow configuration (including all the references to it).
<var name="forgotPassword" class="com.mycompany.authentication.ForgotPasswordBean" />
Does anybody know if it's possible to define dynamic transitions in a Spring Web Flow definition?
Example 1 - using a properties file:
<action-state id="createSubscription" >
<evaluate expression="myvar" />
<transition on="$[test.result.valid]" to="subscribeUser-successResponse" />
<transition to="subscribeUser-exceptionResponse" />
</action-state>
Example 2 - using the value of the variable itself:
<action-state id="createSubscription" >
<evaluate expression="myvar" />
<transition to="$[myvar]" />
</action-state>
It's not mandatory, but could help to design more generic flows.
Thanks in advance to everyone.
You can do definitely do for transition "to".
Suppose flow xml has some action and view state as:
<action-state id="createSubscription">
<evaluate expression="myAction.prepareNextState(flowScope.formBean)"/>
<transition to="${flowScope.formBean.displayNextState}">
</action-state>
<view-state id="someView" view="someView" model="formBean">
...
</view-state>
and myAction class with prepareNextState method is as:
public class MyAction implements Serializable{
....
public void prepareNextState(FormBean formBean){
//displayNextState is a String field in FormBean
formBean.setDisplayNextState("someView");
}
....
}
This way we can define generic transitions for transition "to".
I'm going to save my entity ID into the session in one of action states:
<on-exit>
<evaluate expression="persistantService.saveOrUpdate(flowScope.entity)"/>
<evaluate expression="externalContext.sessionMap.put('entityId', flowScope.entity.Id)"/>
</on-exit>
Actually, entity.Id field - is int.
On the start of the flow i'm trying to get entityId from the session, if it exists, load it from storage, else - create new one. Here how I suppose to do it:
<decision-state id="test">
<if test="externalContext.sessionMap.contains('entityId')"
then="findExistingEntity"
else="creteNewEntity"/>
</decision-state>
<action-state id="findExistingEntity">
<evaluate expression="persistantService.findEntityById(externalContext.sessionMap.entityId)"
result="flowScope.entity" />
</action-state>
The problem is that persistantService.findEntityById accepts int, but not Object or Integer that are taken from session.
How can I resolve it? How can I convert externalContext.sessionMap.entityId to int?
Or probably there is another way, to test that entity is saved and load it from persistant storage?
i'd use the conversationScope
<on-exit>
<evaluate expression="persistantService.saveOrUpdate(flowScope.entity)"/>
<set name="conversationScope.entityId" value="flowScope.entity.Id"/>
</on-exit>
...
<decision-state id="test">
<if test="conversationScope.entityId != null"
<!-- i'm not sure if that works you might put the test in a method in a bean and call that--!>
then="findExistingEntity"
else="creteNewEntity"/>
</decision-state>
<action-state id="findExistingEntity">
<evaluate expression="persistantService.findEntityById(conversationScope.entityId)"
result="flowScope.entity" />
</action-state>
I Have problem with Spring Webflow. My flow XML definition is:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" parent="changeLang">
<input name="hash" required="true"/>
<action-state id="decideAction">
<set name="flowScope.goTo" value ="verifyActionService.verifyHash(hash)" />
<transition to="${goTo}" ></transition>
</action-state>
<view-state id="correctVerify" view="registered" model="userAddressesForm">
<transition on="addPhoneNumber" to="correctVerify">
<evaluate expression="verifyActionService.addPhoneNumber(userAddressesForm)" />
</transition>
<transition on="deletePhoneNumber" to="correctVerify">
<evaluate expression="verifyActionService.deletePhoneNumber(userAddressesForm, requestParameters.deleteNumber)" />
</transition>
</view-state>
<view-state id="notCorrectVerify" view="register"></view-state>
</flow>
The method verifyHash return a state id equal "correctVerify" like this:
public String verifyHash(String hash) {
return "correctVerify";
}
When I run it, a get an error like this:
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.IllegalArgumentException: Cannot find state with id '${goTo}' in flow 'verify' -- Known state ids are 'array<String>['decideAction', 'correctVerify', 'notCorrectVerify', 'start']'
at org.springframework.webflow.engine.Flow.getStateInstance(Flow.java:348)
at org.springframework.webflow.engine.support.DefaultTargetStateResolver.resolveTargetState(DefaultTargetStateResolver.java:60)
at org.springframework.webflow.engine.Transition.execute(Transition.java:217)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:391)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214)
at org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:119)
Can anybody help me?
The to attribute of transition takes a string literal. If you want to combine string literals and EL, you need to use a template expression:
<transition to="#{goTo}"/>
Information about the two different types of expression can be found in this section of the documentation.
Also, are you sure you need to be returning a view-state name from your service layer? The general pattern for <action-state> is you call a method using <evaluate> and then define different transitions to different states based on the result of the <evaluate>... similar to a switch statement. Take a look at this section on action states.