Get rid of org.jboss.weld.context.NonexistentConversationException, when a query-string parameter named cid is appended to the URL

后端 未结 3 1305
一向
一向 2020-12-21 06:37

Take a simple CDI (it could also be a JSF managed bean) bean as follows.

import java.io.Serializable;    
import javax.inject.Named;
import javax.faces.view.         


        
相关标签:
3条回答
  • 2020-12-21 07:22

    In the case of a servlet or other context supporting the web.xml context-param, you could set WELD_CONTEXT_ID_KEY as currently noted in the latest Weld documentation on supported environments:

    <context-param>
       <param-name>WELD_CONTEXT_ID_KEY</param-name>
       <param-value>customValue</param-value>
    </context-param>
    
    0 讨论(0)
  • 2020-12-21 07:25

    There's a race condition in AbstractConversationContext when create first conversation scope if it's the first request of one session. Suppose such scenario

    1. User requests a jsf page
    2. weld creates a conversations map in the AbstractConversationContext.associate()
    3. Because it is the first request, there's no session. Weld keep this map in request
    4. A conversation scoped bean is created and put to the map.
    5. In somewhere, a session is created
    6. In the render phase, server sends partial response back. The page need some jsf resource, eg, jsf2 ajax or jsf resource
    7. Browser requests the new jsf resource
    8. At this time The first request has not finished. So it doesn't reach dissociate() and doesn't put conversations map in the session.
    9. Meanwhile The second request reach associate(). There's no conversations map in the session, and the session is existing. It puts its new map! <====
    10. Then, even the first request reach dissociate(), because there's already a map, it doesn't put its owner anymore. <====

    A quick and dirty fix is always create session before associate(). However, it's better to merge the map in the dissociate()

    Please see :

    https://issues.jboss.org/browse/WELD-1418

    WELD-1500 issue

    0 讨论(0)
  • 2020-12-21 07:31

    This is specific to Weld (the implementation), not to CDI (the API). There's in the current Weld 2.2.x version no simple nor native way to disable it. Weld however allows you changing the request parameter name cid to something else via HttpConversationContext#setParameterName(). You could set it to e.g. an java.util.UUID value during application's startup.

    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ApplicationScoped;
    import org.jboss.weld.context.http.HttpConversationContext;
    
    @ManagedBean(eager=true)
    @ApplicationScoped
    public class Application {
    
        @Inject
        private HttpConversationContext conversationContext;
    
        @PostConstruct
        public void init() {
            hideConversationScope();
        }
    
        /**
         * "Hide" conversation scope by replacing its default "cid" parameter name
         * by something unpredictable.
         */
        private void hideConversationScope() {
            conversationContext.setParameterName(UUID.randomUUID().toString());
        }
    
    }
    

    Unfortunately, CDI doesn't have any equivalent for eager=true. Alternative is, if you've EJB at hands:

    import javax.ejb.Startup;
    import javax.ejb.Singleton;
    
    @Startup
    @Singleton
    public class Application {
    

    (you might want to add @TransactionAttribute(NOT_SUPPORTED) to turn off unnecessary DB transaction management around it)

    Or, if you've OmniFaces at hands:

    import org.omnifaces.cdi.Startup;
    
    @Startup
    public class Application {
    
    0 讨论(0)
提交回复
热议问题