myfaces _DeltaList and PartialStateHolder
-----------------------------------------
Key: MYFACES-3228
URL: https://issues.apache.org/jira/browse/MYFACES-3228
Project: MyFaces Core
Issue Type: Bug
Components: Archetype
Affects Versions: 2.1.1
Environment: tomcat 7.0.14 myfaces 2.1.1 mojarra 2.1.1-b04
Reporter: lkw
Priority: Minor
hi.
at first, i'm not native english speaker
and this subject which i will explain is something complex.
so forgive me please even though cant easily understand this.
this is something uncommon case. let's see follow code.
javax.faces.PARTIAL_STATE_SAVING=true
javax.faces.STATE_SAVING_METHOD=client
===
package com.mycompany.mavenproject31;
import java.io.IOException;
import javax.faces.component.ActionSource2;
import javax.faces.component.PartialStateHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.faces.view.facelets.ComponentHandler;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.TagConfig;
import javax.faces.view.facelets.TagHandler;
public class AnotherActionListenerTagHandler extends TagHandler {
static public class AnotherActionListener implements ActionListener,
PartialStateHolder {
transient boolean isInitialState = false, isTransient = false;
Integer state1 = null;
public AnotherActionListener() {
state1 = 100;
}
@Override
public void processAction(ActionEvent actionEvent) throws
AbortProcessingException {
return;
}
@Override
public void clearInitialState() {
isInitialState = false;
}
@Override
public boolean initialStateMarked() {
return isInitialState;
}
@Override
public void markInitialState() {
isInitialState = true;
}
@Override
public Object saveState(FacesContext context) {
if(isInitialState==true || isTransient==true)
return null;
return state1;
}
@Override
public void restoreState(FacesContext context, Object state) {
state1 = (Integer) state;
}
@Override
public boolean isTransient() {
return isTransient;
}
@Override
public void setTransient(boolean newTransientValue) {
isTransient = newTransientValue;
}
public Integer getState1() {
return state1;
}
public void setState1(Integer state1) {
boolean nullFlag1 = this.state1 == null, nullFlag2 =
state1 == null;
if(nullFlag1==nullFlag2 && nullFlag1==true)
return;
if(nullFlag1!=nullFlag2)
clearInitialState();
else
if(this.state1.equals(state1)==false)
clearInitialState();
this.state1 = state1;
}
}
public AnotherActionListenerTagHandler(TagConfig tagConfig) {
super(tagConfig);
}
@Override
public void apply(FaceletContext ctx, UIComponent parent) throws
IOException {
if(ComponentHandler.isNew(parent)==false)
return;
ActionSource2 actionSource2 = (ActionSource2) parent;
actionSource2.addActionListener(new AnotherActionListener());
}
}
<tag>
<tag-name>anotherActionListener</tag-name>
<handler-class>com.mycompany.mavenproject31.AnotherActionListenerTagHandler</handler-class>
</tag>
===
and follow is test code(not unit test!).
===
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:sample2="http://sample.sample2">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:commandButton value="iii"
binding="#{anotherManagedBean.iii}">
<sample2:anotherActionListener/>
<sample2:anotherActionListener/>
</h:commandButton>
<h:commandButton value="aaa"
actionListener="#{anotherManagedBean.aaaActionListener}"/>
</h:form>
</h:body>
</html>
package com.mycompany.mavenproject31;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UICommand;
import javax.faces.event.ActionEvent;
@ManagedBean
@ViewScoped
public class AnotherManagedBean implements Serializable {
transient UICommand iii;
public void aaaActionListener(ActionEvent event) {
AnotherActionListenerTagHandler.AnotherActionListener listener
= (AnotherActionListenerTagHandler.AnotherActionListener)
iii.getActionListeners()[0];
listener.setTransient(true);
listener =
(AnotherActionListenerTagHandler.AnotherActionListener)
iii.getActionListeners()[1];
listener.setState1(101);
return;
}
public UICommand getIii() {
return iii;
}
public void setIii(UICommand iii) {
this.iii = iii;
}
}
===
and test as follow.
1.load index2.xhtml
2.push "iii" button and check AnotherActionListener.processAction method's
twice call.
3.push "aaa" button.
4.push "iii" button again and check listener method's twice call. but method
call count is just one.
i testet this with myfaces 2.1.1 and mojarra-2.1.1-b04.
in mojarra this is fine,
but in myfaces, something strange.
i found something strange point in source code, but i cant explain detailed.
so i just point source code line number.
that is _DeltaList.java's 231-234 line.
delete these lines and duplicated counter variable(local variable name is "int
j").
i think that duplicated counter("j") is not necessary.
but in common case,
because we dont use listener or validator as stateful object which is often
state changed,
instead at use listener or validator as stateful object which is almost not
state changed.
this is not explicit big problem.
but i think that this is potentially problem.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira