Spring WebFlow doesn't use the the implemented validator - spring-boot

Spring webflow does not use the custom validator PatientValidator to validate Patient model while transitioning from selectPatient state to selectDoctor state.
Here is my code
Patient.java
#Data
#Entity
public class Patient implements Serializable {
private static final long serialVersionUID = -5116169782847291743L;
...
}
PatientValidator.java
#Component
public class PatientValidator extends FieldValidator {
public PatientValidator() { }
public void validateSelectPatient(Patient patient, Errors errors) {
System.out.println("PatientValidator . validateSelectPatient");
}
public void validateSelectDoctor(Patient patient, Errors errors) {
System.out.println("PatientValidator . validateSelectDoctor");
}
}
submit-request-flow.xml
<?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">
<secured attributes="ROLE_OFFICER" match="any"/>
<on-start>
<evaluate expression="submitRequestFlow.getPatient()" result="flowScope.patient"></evaluate>
</on-start>
<view-state id="selectPatient" view="flows/requests/new/select-patient" model="patient">
<transition on="select" to="selectDoctor"></transition>
</view-state>
<view-state id="selectDoctor" view="flows/requests/new/select-doctor">
<transition on="select" to="selectTestType"></transition>
<transition on="back" to="selectPatient"></transition>
</view-state>
...
<end-state id="finishFlow" view="externalRedirect:#{uri.get('requests')}">
<output name="success" value="'Request has been added successfully'"/>
</end-state>
<end-state id="cancelFlow" view="externalRedirect:#{uri.get('requests')}">
</end-state>
<global-transitions>
<transition on="cancel" to="cancelFlow" history="discard" bind="false" validate="false"></transition>
</global-transitions>
</flow>
Even if I use the validation method inside Patient.java, the webflow uses it.
#Data
#Entity
public class Patient implements Serializable {
private static final long serialVersionUID = -5116169782847291743L;
...
public void validateSelectPatient(Errors errors) {
errors.reject("NoResultFound");
}
}
I have to use the custom validation rather than the model one, it works just the first time, but I guess after I rebooted spring boot project it doesn't work anymore.
Update #1
I am using
Spring boot 1.5.6.RELEASE
Spring WebFlow 2.4.5.RELEASE
Thymeleaf 3.0.7.RELEASE
Thymeleaf SpringSecurity4 3.0.2.RELEASE

I guess issue is related how spring DevTools works, here is a workaround I have done for another issue here SpelEvaluationException Method cannot be found.

Related

Spring Web Flow flowExecutionUrl is empty

I'm making simple order-flow via Spring Web Flow, also i have Spring MVC on my project. I've been doing everything according to guides, but my web-app doesn't react to my flow at all. Spring Web Flow Config:
#Configuration
#ComponentScan(basePackages = "config")
public class WebFlowConfig extends AbstractFlowConfiguration {
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setDevelopmentMode(true).build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(
Collections.singletonList(this.webMvcConfig.resourceViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
#Autowired
private DispatcherConfig webMvcConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
FlowDefinitionRegistry registry = getFlowDefinitionRegistryBuilder().addFlowLocation("/WEB-INF/flows/order/flowcnf.xml","order").build();
return registry;
}
#Bean
public FlowExecutor flowExecutor() {
return
getFlowExecutorBuilder(flowRegistry()).build();
}
#Bean
public FlowHandlerMapping flowHandlerMapping(){
final FlowHandlerMapping handeler = new FlowHandlerMapping();
handeler.setFlowRegistry(flowRegistry());
handeler.setFlowUrlHandler(defaultFlowUrlHandler());
return handeler;
}
#Bean
public DefaultFlowUrlHandler defaultFlowUrlHandler(){
return new DefaultFlowUrlHandler();
}
#Bean
public FlowHandlerAdapter adapter(){
FlowHandlerAdapter adapter = new FlowHandlerAdapter();
adapter.setFlowUrlHandler(defaultFlowUrlHandler());
adapter.setFlowExecutor(flowExecutor());
return adapter;
}
}
As I said I'm using Spring MVC maybe the problems occurs due to it.
Code snippet below must run "thankCustomer" view-state, but it doesn't.
I get 404 eror if i click the link.
<a class=button href="${flowExecutionUrl}&_eventId=thankCustomer">Замовити!</a>
And the flow code:
<?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"
start-state="identify">
<var name="order" class="entity.BookOrder"/>
<subflow-state id="identify" subflow="order/custom" >
<output name="user" value="order.custName" />
<transition on="userIsReady" to="buildOrder"/>
</subflow-state>
<subflow-state id="buildOrder" subflow="order/build">
<input name="order" value="order" />
<transition to="takePayment" on="orderBuilt" />
</subflow-state>
<subflow-state id="takePayment" subflow="order/takePayment" >
<input name="order" value="order"/>
<transition on="paymentTaken" to="saveOrder" />
</subflow-state>
<action-state id="saveOrder">
<evaluate expression="userServiceImpl.addOrder(order.custName,order)"/>
<transition to="thankCustomer" />
</action-state>
<view-state id="thankCustomer" view="/WEB-INF/pages/greeting.jsp" >
<transition to="end-point" />
</view-state>
<end-state id="end-point"/>
<global-transitions>
<transition on="cancel" to="end-point" />
</global-transitions>
</flow>
I've tried to put flow id (order) instead of empty flowExecutionUrl, but still the same eror, I'll be grateful for any kinda help.
I needed to set "order" to my FlowHandlerMapping Bean, couse i already had 2 viewResolvers.

Is a declarative service a singleton by default?

The configuration:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" enabled="true" immediate="true" name="printing">
<implementation class="printing.PrinterManager"/>
<service>
<provide interface="service.printing.IPrinterManager"/>
</service>
</scr:component>
The class:
public class PrinterManager implements IPrinterManager {
public void activate(BundleContext ctx) {
System.err.println("hello");
}
public void deactivate(BundleContext ctx) {
System.err.println("bye");
}
}
When I inject an object of that class somewhere else in my code like this:
#Inject
IPrinterManager pm;
Do I always get the same instance of that class or not?
How to make that instance a singleton with the help of osgi/equinox facilities if it's not a singleton already? (I know how to write a singleton the java/vanilla way, that's not my question)
Yes a DS component is a singleton by default. See Multiple Component Instances with OSGi Declarative Services

Spring Webflow + Spring MVC: Action Bean in Java Annotation

I'm using Spring MVC + Spring Webflow 2.
I would like to define a #Bean for an action-state, but i don't know how to do this in Java Annotation, as i get this error:
Method call: Method execute() cannot be found on
com.myapp.action.GaraAgenziaAction type
here an example of what i want to do: spring-webflow-no-actions-were-executed
My Bean:
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
public class GaraAgenziaAction implements Action {
#Override
public Event execute(RequestContext rc) throws Exception {
return new Event(this, "success");
}
}
Flow XML:
<transition on="fail" to="gara-agenzie"/>
<transition on="success" to="gara-conferma"/>
My webAppConfig:
#Bean
public Action GaraAgenziaAction()
{
GaraAgenziaAction garaAgenziaAction = new GaraAgenziaAction();
return garaAgenziaAction;
}
Thank you very much
UPDATE resolved thanks to #Prasad suggestions:
My Bean (added #Component):
import org.springframework.stereotype.Component;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
#Component
public class GaraAgenziaAction implements Action {
#Override
public Event execute(RequestContext rc) throws Exception {
return new Event(this, "success");
}
}
My webAppConfig (changed name of the bean with lowercase):
#Bean
public Action garaAgenziaAction()
{
GaraAgenziaAction beanAction = new GaraAgenziaAction();
return beanAction;
}
Flow XMl configuration (changed bean name to lowercase and pass flowRequestContext as parameter):
<action-state id="action-agenzie">
<evaluate expression="garaAgenziaAction.execute(flowRequestContext)"></evaluate>
<transition on="fail" to="gara-agenzie"/>
<transition on="success" to="gara-conferma"/>
</action-state>
Now it's working fine!
Define the action class in your servlet xml file as:
<!--Class which handles the flow related actions-->
<bean id="garaAgenziaAction" class=" com.myapp.action.GaraAgenziaAction">
</bean>
or annotate it with Component as:
#Component
public class GaraAgenziaAction implements Action{
#Override
public Event execute(RequestContext rc) throws Exception {
return new Event(this, "success");
}
}
In your flow xml access it as:
<action-state id="action-agenzie">
<evaluate expression="garaAgenziaAction.execute(flowRequestContext)"></evaluate>
<transition on="fail" to="gara-agenzie"/>
<transition on="success" to="gara-conferma"/>
</action-state>
For configuration details you can find it in the answer in this link.

How to inject Spring bean into JSF converter [duplicate]

This question already has answers here:
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
(5 answers)
Closed 7 years ago.
I need to inject Spring beans into a JSF (Primefaces) converter. I tried to inject beans by using EL resolver. However, the beans are null inside the converters.
My JSF converter:
public class DepartmentConverter implements Converter {
private DepartmentService departmentService;
//getter setter for this property
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
//codes
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
//Codes
}
}
faces-config.xml:
<converter>
<converter-id>DepartmentConverter</converter-id>
<converter-class>com.studinfo.jsf.converter.DepartmentConverter</converter-class>
<property>
<property-name>departmentService</property-name>
<property-class>com.studinfo.services.DepartmentService</property-class>
<default-value>#{DepartmentService}</default-value>
</property>
</converter>
EL resolver:
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
When I debug my code, the departmentService property is null. I can access the Spring beans inside a managed JSF bean the same way.
Until JSF 2.3, converters are no injection targets. Make the converter a JSF or Spring managed bean instead. The below example makes it a JSF managed bean:
#ManagedBean
#RequestScoped
public class DepartmentConverter implements Converter {
// ...
}
And use it as #{departmentConverter} instead of DepartmentConverter.
E.g.
<h:inputSome ... converter="#{departmentConverter}" />
or
<h:someComponent>
<f:converter binding="#{departmentConverter}" />
</h:someComponent>
Don't forget to remove the <converter> from faces-config.xml (which was at its own already unnecessary if you used the #FacesConverter annotation, but that aside).

How to enable JSR-303 bean validation in Facelets?

I'm using spring CDI and a customized "View" scope. (See this about how it works.)
The view bean is annotated with JSR-303 validation rules as following:
#Scope("view")
public class MyBean implements Serializable {
String message;
#NotNull
#Size(min = 10)
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void action1() {
...
}
}
And the user form:
...
<h:form id="form1">
<h:inputText name="message" value="${myBean.message}" />
<p:commandButton value="Update" actionListener="${myBean.action1}" />
</h:form>
However, the validation doesn't work. Am I missing something in faces-config.xml? I guess there should be some proxy classes involved in, which maybe generated by AspectJ weaver or so. Right?
JSR 303 validation for JSF is auto enabled if you add implementation jar to classpath.

Resources