I have got following problem. I defined following service class
package godziszewski.patryk.ElectronicsStore.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import godziszewski.patryk.ElectronicsStore.domain.Cart; import godziszewski.patryk.ElectronicsStore.domain.repository.CartRepository; import godziszewski.patryk.ElectronicsStore.exception.InvalidCartException; import godziszewski.patryk.ElectronicsStore.service.CartService; @Service public class CartServiceImpl implements CartService { @Autowired CartRepository cartRepository; public Cart create(Cart cart) { return cartRepository.create(cart); } public Cart read(String cartId) { return cartRepository.read(cartId); } public void update(String cartId, Cart cart) { cartRepository.update(cartId, cart); } public void delete(String cartId) { cartRepository.delete(cartId); } public Cart validate(String cartId) { Cart cart = cartRepository.read(cartId); if(cart==null || cart.getCartItems().size()==0) { throw new InvalidCartException(cartId); } return cart; } } Class is getting loaded by spring ( It's found by component scan and I can use it in other classes by autowiring) And I need to use this bean in spring web flow. My flow looks like this:
<var name="order" class="godziszewski.patryk.ElectronicsStore.domain.Order" /> <action-state id="addCartToOrder"> <evaluate expression="cartServiceImpl.validate(requestScope.cartId)" result="order.cart" /> <transition to="InvalidCartWarning" on-exception="godziszewski.patryk.ElectronicsStore.exception.InvalidCartException"/> <transition to="loadCustomerAddress" /> </action-state> Everything should work, but somehow expression parser can't resolve my service bean. The error I'm getting:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/ElectronicsStore] threw exception [Request processing failed; nested exception is org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@3d6c7f1e targetAction = [EvaluateAction@43e3c391 expression = cartServiceImpl.validate(requestScope.cartId), resultExpression = order.cart], attributes = map[[empty]]] in state 'addCartToOrder' of flow 'checkout' -- action execution attributes were 'map[[empty]]'] with root cause org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'cartServiceImpl' cannot be found on object of type 'org.springframework.webflow.engine.impl.RequestControlContextImpl' - maybe not public? at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:224) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81) at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:51) at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:87) at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:131) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:299) at org.springframework.binding.expression.spel.SpringELExpression.getValue(SpringELExpression.java:84) at org.springframework.webflow.action.EvaluateAction.doExecute(EvaluateAction.java:75) at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188) at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145) at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51) at org.springframework.webflow.engine.ActionState.doEnter(ActionState.java:101) at org.springframework.webflow.engine.State.enter(State.java:194) at org.springframework.webflow.engine.Flow.start(Flow.java:527) at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:368) at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:223) at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:140) at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:263) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:157) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Unknown Source) Full webflow config:
<?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"> <var name="order" class="godziszewski.patryk.ElectronicsStore.domain.Order" /> <action-state id="addCartToOrder"> <evaluate expression="cartServiceImpl.validate(requestScope.cartId)" result="order.cart" /> <transition to="InvalidCartWarning" on-exception="godziszewski.patryk.ElectronicsStore.exception.InvalidCartException" /> <transition to="loadCustomerAddress" /> </action-state> <action-state id="loadCustomerAddress"> <evaluate expression="customerServiceImpl.getCustomerByEmail(currentUser.name)" result="order.customer" /> <transition to="customer" on-exception="org.springframework.expression.spel.SpelEvaluationException"/> <transition to="customer" /> </action-state> <subflow-state id="customer" subflow="checkout/customer"> <input name="order" value="order"/> <transition on="customerReady" to="orderConfirmation" /> </subflow-state> <view-state id="orderConfirmation"> <transition on="orderConfirmed" to="processOrder" /> <transition on="backToCustomerInfo" to="customer" /> </view-state> <action-state id="processOrder"> <evaluate expression="orderServiceImpl.saveOrder(order)" /> <transition to="thankCustomer" /> </action-state> <view-state id="InvalidCartWarning"> <transition to="endState"/> </view-state> <view-state id="thankCustomer" model="order"> <transition to="endState"/> </view-state> <end-state id="endState"/> <end-state id="cancelCheckout" view = "checkOutCancelled.jsp"/> <global-transitions> <transition on = "cancel" to="cancelCheckout" /> </global-transitions> </flow> flow configuration:
package godziszewski.patryk.ElectronicsStore.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.validation.Validator; import org.springframework.webflow.config.AbstractFlowConfiguration; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter; import org.springframework.webflow.mvc.servlet.FlowHandlerMapping; public class FlowConfiguration extends AbstractFlowConfiguration { @Autowired Validator validator; @Bean public FlowDefinitionRegistry flowRegistry() { return getFlowDefinitionRegistryBuilder() .setBasePath("/WEB-INF/flows") .setFlowBuilderServices(flowBuilderServices()) .addFlowLocationPattern("/**/*-flow.xml") .build(); } @Bean public FlowExecutor flowExecutor() { return getFlowExecutorBuilder(flowRegistry()).build(); } @Bean public FlowHandlerMapping flowHandlerMapping() { FlowHandlerMapping fh = new FlowHandlerMapping(); fh.setFlowRegistry(flowRegistry()); return fh; } @Bean public FlowHandlerAdapter flowHandlerAdapter() { FlowHandlerAdapter fh = new FlowHandlerAdapter(); fh.setFlowExecutor(flowExecutor()); return fh; } @Bean public FlowBuilderServices flowBuilderServices() { return getFlowBuilderServicesBuilder() .setValidator(validator) .build(); } } Also, rest of classes:
package godziszewski.patryk.ElectronicsStore.config; import javax.servlet.FilterRegistration; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class ElectronicsStoreWebInitialiser extends AbstractAnnotationConfigDispatcherServletInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); FilterRegistration.Dynamic encodingFilter = servletContext .addFilter("encoding-filter", new CharacterEncodingFilter()); encodingFilter.setInitParameter("encoding", "UTF-8"); encodingFilter.setInitParameter("forceEncoding", "true"); encodingFilter.addMappingForUrlPatterns(null, true, "/*"); } @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/images", 2097152, 4194304, 0)); } } and class that imports flow config:
package godziszewski.patryk.ElectronicsStore.config; import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.multipart.support.StandardServletMultipartResolver; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.json.MappingJackson2JsonView; import org.springframework.web.servlet.view.tiles3.TilesConfigurer; import org.springframework.web.servlet.view.tiles3.TilesViewResolver; import org.springframework.web.servlet.view.xml.MarshallingView; import org.springframework.web.util.UrlPathHelper; import godziszewski.patryk.ElectronicsStore.domain.Product; @Configuration @Import(godziszewski.patryk.ElectronicsStore.config.FlowConfiguration.class) @EnableWebMvc @ComponentScan(basePackages = "godziszewski.patryk") public class WebConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } @Override public Validator getValidator() { return validator(); } @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { registry.addResourceHandler("/resource/**").addResourceLocations("/resources/"); } @Bean TilesConfigurer tilesConfigurer() { TilesConfigurer tiles = new TilesConfigurer(); tiles.setDefinitions(new String[] { "/WEB-INF/tiles/definition/tile-definition.xml" }); tiles.setCheckRefresh(true); return tiles; } @Bean public ViewResolver tilesViewResolver() { TilesViewResolver tv = new TilesViewResolver(); tv.setOrder(-2); return tv; } @Bean public ResourceBundleMessageSource messageSource() { ResourceBundleMessageSource rb = new ResourceBundleMessageSource(); rb.setBasename("messages"); return rb; } @Bean public StandardServletMultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } @Bean public ContentNegotiatingViewResolver contentResolver() { ContentNegotiatingViewResolver cn = new ContentNegotiatingViewResolver(); List<View> listOfViews = new ArrayList<View>(); listOfViews.add(jsonView()); listOfViews.add(xmlView()); cn.setDefaultViews(listOfViews); return cn; } @Bean public MappingJackson2JsonView jsonView() { MappingJackson2JsonView mj= new MappingJackson2JsonView(); mj.setPrettyPrint(true); return mj; } @Bean public MarshallingView xmlView() { Jaxb2Marshaller ja = new Jaxb2Marshaller(); ja.setClassesToBeBound(Product.class); MarshallingView mv = new MarshallingView(ja); return mv; } @Bean public Validator validator() { LocalValidatorFactoryBean lv = new LocalValidatorFactoryBean(); lv.setValidationMessageSource(messageSource()); return lv; } } Changed file
package godziszewski.patryk.ElectronicsStore.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.context.annotation.Bean; import org.springframework.validation.Validator; import org.springframework.webflow.config.AbstractFlowConfiguration; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter; import org.springframework.webflow.mvc.servlet.FlowHandlerMapping; public class FlowConfiguration extends AbstractFlowConfiguration { @Autowired Validator validator; @Bean public FlowDefinitionRegistry flowRegistry() { return getFlowDefinitionRegistryBuilder(flowBuilderServices()) //flow registry makes flow not recognize beans ? //.setFlowBuilderServices(flowBuilderServices()) .setBasePath("/WEB-INF/flows") .addFlowLocationPattern("/**/*-flow.xml") .build(); } @Bean public FlowExecutor flowExecutor() { return getFlowExecutorBuilder(flowRegistry()).build(); } @Bean public FlowHandlerMapping flowHandlerMapping() { FlowHandlerMapping fh = new FlowHandlerMapping(); fh.setFlowRegistry(flowRegistry()); return fh; } @Bean public FlowHandlerAdapter flowHandlerAdapter() { FlowHandlerAdapter fh = new FlowHandlerAdapter(); fh.setFlowExecutor(flowExecutor()); return fh; } @Bean public FlowBuilderServices flowBuilderServices() { return getFlowBuilderServicesBuilder() .setValidator(validator) .setDevelopmentMode(true) .setConversionService(conversionService()) .build(); } @Bean public DefaultConversionService conversionService() { return new DefaultConversionService(); } } I'm adding github link to my repository, maybe you can find something wrong in there (about the flow) https://github.com/pgod/ElectronicsStore