jakartaee / jakartaee/faces

Cannot call UIComponent.getCurrentComponent() from UIComponent.restoreState() or UIComponent.saveState()

Open
#792 17 comments 0 reactions 0 assignees View on GitHub
Component: Components/Renderers Priority: Minor Type: Bug
Dominant language
Java
Stars
127
Forks
59
Avg merge
23h
Merged PRs (30d)
7

Description

From jsr-314-open list:

The javadoc of UIComponent.processRestoreState() says this:

"....Perform the component tree processing required by the Restore View phase
of the request processing lifecycle for all facets of this component, all
children of this component, and this component itself, as follows.

* Call the restoreState() method of this component.
* Call pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent).
* Call the processRestoreState() method of all facets and children of this
UIComponent in the order determined by a call to getFacetsAndChildren(). After
returning from the processRestoreState() method on a child or facet, call
popComponentFromEL(javax.faces.context.FacesContext)..."

The javadoc of UIComponent.processSaveState() says this:

".....Perform the component tree processing required by the state saving portion
of the Render Response phase of the request processing lifecycle for all facets
of this component, all children of this component, and this component itself, as
follows.

* consult the transient property of this component. If true, just return null.
* Call pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent).
* Call the processSaveState() method of all facets and children of this
UIComponent in the order determined by a call to getFacetsAndChildren(),
skipping children and facets that are transient. Ensure that
popComponentFromEL(javax.faces.context.FacesContext) is called correctly after
each child or facet.
* Call the saveState() method of this component.
* Encapsulate the child state and your state into a Serializable Object and
return it....."

The question is: Doesn't suppose that when you call
UIComponent.getCurrentComponent() inside UIComponent.restoreState(), it returns
the "current component"?. There is one case when we need to do this call and is
on the wrapper used by UIComponent.subscribeToEvent(). The javadoc of this
method says this:

"....Install the listener instance referenced by argument componentListener as a
listener for events of type eventClass originating from this specific instance
of UIComponent. The default implementation creates an inner SystemEventListener
instance that wraps argument componentListener as the listener argument. This
inner class must call through to the argument componentListener in its
implementation of
SystemEventListener.processEvent(javax.faces.event.SystemEvent) and its
implementation of SystemEventListener.isListenerForSource(java.lang.Object)
must return true if the instance class of this UIComponent is assignable from
the argument to isListenerForSource...."

Both myfaces and mojarra has the wrapper described by the javadoc, and that one
is responsible to save/restore the system event listeners attached. To restore
the "component" reference required, both implementations call
UIComponent.getCurrentComponent() and both call processEvent but for the parent!.

It is obviously a bug (I don't see a valid reason why do the algorithm
described), if you look other methods like processDecodes, you see the right
pattern:

* If the rendered property of this UIComponent is false, skip further
processing.
* Call pushComponentToEL(javax.faces.context.FacesContext,
javax.faces.component.UIComponent).
* Call the processDecodes() method of all facets and children of this
UIComponent, in the order determined by a call to getFacetsAndChildren().
* Call the decode() method of this component.
* Call popComponentFromEL(javax.faces.context.FacesContext) from inside of a
finally block, just before returning.
* If a RuntimeException is thrown during decode processing, call
FacesContext.renderResponse() and re-throw the exception.

I'll change myfaces algorithm to look like processDecodes(). But anyway, it is
necessary to do the proper change on mojarra and on spec javadoc.
#### Environment
Operating System: All
Platform: All
#### Affected Versions
[2.0]

Contributor guide

Open the contributing guide

Research direction

Start with the UIComponent processRestoreState(), processSaveState(), and subscribeToEvent() Javadocs, then compare the MyFaces and Mojarra state-saving algorithms described in the issue. Done means the current component is available while restoring listeners and the specification Javadoc and affected implementations consistently describe that behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.