问题
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
来源:https://stackoverflow.com/questions/39171554/spring-web-flow-cant-resolve-service-bean