Grails
  1. Grails
  2. GRAILS-5984

Can't create a flow-scoped service

    Details

    • Type: Bug Bug
    • Status: Reopened
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: WebFlow
    • Labels:
      None

      Description

      Discovered when investigating GRAILS-5953

      Create a flow-scoped service:

      class CardService {
      
         static transactional = false
         static scope = 'flow'
      
         long sum
      
         void addToSum(long i) {
            sum += i
         }
      }
      

      and a simple Webflow controller that uses it:

      class CardController {
      
         def cardService
      
         def index = {
            redirect action: 'order'
         }
      
         def orderFlow = {
            start {
               action {
                  cardService.addToSum(123)
                  success()
               }
               on('success').to 'finish'
            }
      
            finish {}
         }
      }
      

      And when you access the controller you'll get the error

      Error 500: Error creating bean with name 'CardController': Initialization of bean failed;
      nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cardService':
      Scope 'flow' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
      nested exception is java.lang.IllegalStateException: No request context bound to this thread; to access flow-scoped beans you must be running in a flow execution request
      Servlet: grails
      URI: /webfl/grails/card/index.dispatch
      Exception Message: No request context bound to this thread; to access flow-scoped beans you must be running in a flow execution request
      

      and the relevant stacktrace is

      Caused by: java.lang.IllegalStateException: No request context bound to this thread; to access flow-scoped beans you must be running in a flow execution request
              at org.springframework.webflow.scope.AbstractWebFlowScope.getRequiredRequestContext(AbstractWebFlowScope.java:88)
              at org.springframework.webflow.scope.FlowScope.getScope(FlowScope.java:27)
              at org.springframework.webflow.scope.AbstractWebFlowScope.get(AbstractWebFlowScope.java:39)
              at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
      

        Activity

        Hide
        Luke Daley added a comment - - edited

        I can't see how this is ever going to work unless we transparently create scoped proxies for flow scoped services.

        In that case, users will only see this exception if they try and call something on the service outside of a flow.

        Show
        Luke Daley added a comment - - edited I can't see how this is ever going to work unless we transparently create scoped proxies for flow scoped services. In that case, users will only see this exception if they try and call something on the service outside of a flow.
        Hide
        Burt Beckwith added a comment -

        Webflow has dynamic lookup for referenced beans, so removing the 'def cardService' DI field fixes the problem.

        Show
        Burt Beckwith added a comment - Webflow has dynamic lookup for referenced beans, so removing the 'def cardService' DI field fixes the problem.
        Hide
        Burt Beckwith added a comment -

        Even using dynamic lookup, this can still fail. When doing further testing for GRAILS-5953 it turned out that the service proxy was pulling in the ReloadAwareAutowireCapableBeanFactory instance which implements Serializable (since it extends DefaultListableBeanFactory) but has non-serializable fields.

        Show
        Burt Beckwith added a comment - Even using dynamic lookup, this can still fail. When doing further testing for GRAILS-5953 it turned out that the service proxy was pulling in the ReloadAwareAutowireCapableBeanFactory instance which implements Serializable (since it extends DefaultListableBeanFactory) but has non-serializable fields.
        Hide
        Burt Beckwith added a comment -

        Changing to minor since there's a simple workaround to using flow-scoped services; use a serializable stateful helper bean that's explicitly stored in the flow scope. See this comment for implementation details:

        Show
        Burt Beckwith added a comment - Changing to minor since there's a simple workaround to using flow-scoped services; use a serializable stateful helper bean that's explicitly stored in the flow scope. See this comment for implementation details:

          People

          • Assignee:
            Burt Beckwith
            Reporter:
            Burt Beckwith
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Last Reviewed:

              Development