Details
-
Bug
-
Status: Resolved
-
Major
-
Resolution: Fixed
-
2.3-next-M7, 4.0.0-RC3
-
None
-
None
Description
A regression was discovered in our testing in RC3 with the switch from JSF managed implicit objects to cdi managed implicit objects.
In essence, RC2 always used the flowmap (storage?) of the current flow, but RC3 does not.
Previously (RC2), the flow scope map was created as with the following stack:
FlowScopeMap.<init>(BeanManager, String) line: 42 DefaultCDIFacesFlowProvider.lambda$getCurrentFlowScope$0(FacesContext, Flow, Object) line: 107 1548856593.apply(Object) line: not available HashMap<K,V>.computeIfAbsent(K, Function<? super K,? extends V>) line: 1134 DefaultCDIFacesFlowProvider.getCurrentFlowScope(FacesContext) line: 104 <----- Key Call FlowHandlerImpl.getCurrentFlowScope() line: 464 FlowScopeImplicitObject.getValue(ELContext) line: 45 ImplicitObjectResolver.getValue(ELContext, Object, Object) line: 200 CompositeELResolver.getValue(ELContext, Object, Object) line: 62
Note flow map is initialized with a unique flowMapKey
public FlowScopeMap(DefaultFacesFlowProvider provider, String flowMapKey) { this._provider = provider; this._flowMapKey = flowMapKey; }
As for the storage, it's created during a map#put call:
FlowScopeContextualStorageHolder(AbstractContextualStorageHolder<T>).getContextualStorage(String, boolean) line: 98 FlowScopeContextualStorageHolder.getFlowScopeMap(BeanManager, String, boolean) line: 95 FlowScopeMap.getWrapped(boolean) line: 65 FlowScopeMap.put(Object, Object) line: 106 MapELResolver.setValue(ELContext, Object, Object, Object) line: 89
The flowscope is then saved as an attribute on the facesContext (but is cleared once the facesContext is released at the end of the request). A new map is then created in subsequent requests.
As for RC3, FlowScopeContext is now the "implict object manager (equivalent o FlowScopeImplicitObject) " of the flow map. (also see FlowScopeExtension for registration details).
The problem lies in RC3 is with FlowScopeContext#get(Contextual<T> bean) and FlowScopeContext#get(Contextual<T> bean, CreationalContext<T> creationalContext)
They look at all activeFlowMapKeys when they should look at only the current flow (as in RC2):
List<String> activeFlowMapKeys = getStorageHolder(facesContext).getActiveFlowMapKeys(facesContext); for (String flowMapKey : activeFlowMapKeys) { ContextualStorage storage = getContextualStorage(facesContext, false, flowMapKey); if (storage == null) { continue; } Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage(); ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean)); if (contextualInstanceInfo == null) { continue; } return (T) contextualInstanceInfo.getContextualInstance(); }
Relevant Weld Code:
FlowScopeContext.get(Contextual<T>) line: 182 PassivatingContextWrapper$ContextWrapper(PassivatingContextWrapper$AbstractPassivatingContextWrapper<C>).get(Contextual<T>) line: 78 ContextualInstanceStrategy$DefaultContextualInstanceStrategy<T>.get(Bean<T>, BeanManagerImpl, CreationalContext<?>) line: 95 ContextualInstance.get(Bean<T>, BeanManagerImpl, CreationalContext<?>) line: 50 BeanManagerImpl.getReference(Bean<?>, Type, CreationalContext<?>, boolean) line: 680 WeldELResolver(AbstractWeldELResolver).lookup(BeanManagerImpl, ELContext, String) line: 107 WeldELResolver(AbstractWeldELResolver).getValue(ELContext, Object, Object) line: 90
Note if get(bean) returns null then get(bean, creationalContext) is called. Then the FlowScopeMap object is actually created with this call: storage.createContextualInstance(bean, creationalContext);
bean argument in this case is "ForwardingBean flowScope for org.apache.myfaces.cdi.FacesArtifactFlowMapProducer@23deee9" (contains the create(e -> FacesContext.getCurrentInstance().getApplication().getFlowHandler().getCurrentFlowScope())
Attachments
Attachments
Issue Links
- links to