这是 JSF 会话范围验证器的正常行为吗?
Is it normal behavior of JSF session-scoped validator?
实施:org.glassfish2.2.12
我有以下会话范围的验证器:
@ManagedBean
@SessionScoped
public class CreateGroupNameValidator extends LengthValidator implements Serializable{
@ManagedProperty(value="#{myDao}")
private MyDao myDao;
//Validate methods
}
尽管是会话范围的并且 Serializable
,验证器无法在回发到来时恢复 属性 myDao
的值。我使用了调试器并发现状态由具有以下构造函数的 class StateHolderSaver
保存:
public StateHolderSaver(FacesContext context, Object toSave) {
className = toSave.getClass().getName();
if (toSave instanceof StateHolder) {
// do not save an attached object that is marked transient.
if (!((StateHolder) toSave).isTransient()) {
Serializable [] tuple = new Serializable[StateHolderTupleIndices.LastMember.ordinal()];
tuple[StateHolderTupleIndices.StateHolderSaverInstance.ordinal()] =
(Serializable) ((StateHolder) toSave).saveState(context);
if (toSave instanceof UIComponent) {
tuple[StateHolderTupleIndices.ComponentAddedDynamically.ordinal()] = ((UIComponent)toSave).getAttributes().containsKey(DYNAMIC_COMPONENT) ? Boolean.TRUE : Boolean.FALSE;
}
savedState = tuple;
} else {
className = null;
}
} else if (toSave instanceof Serializable) {
savedState = (Serializable) toSave;
className = null;
}
}
所以,由于 LenghtValidator
实现了 javax.faces.component.StateHolder
它没有保存我的初始 Dao 值。这是正常行为吗?
这确实是指定的行为。另见 a.o。 Validator
javadoc:
...
Validator
implementations must have a zero-arguments public constructor. In addition, if the Validator class wishes to have configuration property values saved and restored with the view, the implementation must also implement StateHolder
.
...
转换器和验证器可以保存在 JSF 状态中,以便 JSF 实现可以确保它们在恢复视图后具有与呈现先前请求的视图期间完全相同的预期 属性 值(例如如 minimum
和 maximum
在 LengthValidator
的情况下,它们可能会引用动态 EL 表达式)。
虽然我必须承认他们在设计 JSF 1.0 规范(converter/validator 仍然基于该规范)期间确实没有真正考虑过在 JSF converter/validator 中注入业务服务实例的可能性.您当然不想将它保存在 JSF 视图状态中。在托管属性的情况下(因此不是 EJB/CDI 代理),它只会破坏 JSF 视图状态(因此在服务器端状态保存的情况下也会破坏 HTTP 会话)。
如果您不需要您的验证器是 JSF 状态感知的,请使用组合而不是继承。
public class CreateGroupNameValidator {
private LengthValidator lengthValidator;
public CreateGroupNameValidator() {
lengthValidator = new LengthValidator();
}
// ...
}
尽管如此,将验证器放在会话范围内还是有点可疑。这意味着验证器的行为特定于当前的 HTTP 会话。我想不出合理的现实世界用例,因为它们本质上是视图范围的(不是验证器实例,而是验证器属性)。通常,会话范围内的数据(例如登录用户)在线程本地基础上改为 injected/resolved。如果它是有状态的(即验证器属性可能在每个 request/view 基础上有所不同),或者如果它是无状态的(即验证器属性在整个应用程序的生命周期中是相同的),你最好让它在请求范围内。
实施:org.glassfish2.2.12
我有以下会话范围的验证器:
@ManagedBean
@SessionScoped
public class CreateGroupNameValidator extends LengthValidator implements Serializable{
@ManagedProperty(value="#{myDao}")
private MyDao myDao;
//Validate methods
}
尽管是会话范围的并且 Serializable
,验证器无法在回发到来时恢复 属性 myDao
的值。我使用了调试器并发现状态由具有以下构造函数的 class StateHolderSaver
保存:
public StateHolderSaver(FacesContext context, Object toSave) {
className = toSave.getClass().getName();
if (toSave instanceof StateHolder) {
// do not save an attached object that is marked transient.
if (!((StateHolder) toSave).isTransient()) {
Serializable [] tuple = new Serializable[StateHolderTupleIndices.LastMember.ordinal()];
tuple[StateHolderTupleIndices.StateHolderSaverInstance.ordinal()] =
(Serializable) ((StateHolder) toSave).saveState(context);
if (toSave instanceof UIComponent) {
tuple[StateHolderTupleIndices.ComponentAddedDynamically.ordinal()] = ((UIComponent)toSave).getAttributes().containsKey(DYNAMIC_COMPONENT) ? Boolean.TRUE : Boolean.FALSE;
}
savedState = tuple;
} else {
className = null;
}
} else if (toSave instanceof Serializable) {
savedState = (Serializable) toSave;
className = null;
}
}
所以,由于 LenghtValidator
实现了 javax.faces.component.StateHolder
它没有保存我的初始 Dao 值。这是正常行为吗?
这确实是指定的行为。另见 a.o。 Validator
javadoc:
...
Validator
implementations must have a zero-arguments public constructor. In addition, if the Validator class wishes to have configuration property values saved and restored with the view, the implementation must also implementStateHolder
....
转换器和验证器可以保存在 JSF 状态中,以便 JSF 实现可以确保它们在恢复视图后具有与呈现先前请求的视图期间完全相同的预期 属性 值(例如如 minimum
和 maximum
在 LengthValidator
的情况下,它们可能会引用动态 EL 表达式)。
虽然我必须承认他们在设计 JSF 1.0 规范(converter/validator 仍然基于该规范)期间确实没有真正考虑过在 JSF converter/validator 中注入业务服务实例的可能性.您当然不想将它保存在 JSF 视图状态中。在托管属性的情况下(因此不是 EJB/CDI 代理),它只会破坏 JSF 视图状态(因此在服务器端状态保存的情况下也会破坏 HTTP 会话)。
如果您不需要您的验证器是 JSF 状态感知的,请使用组合而不是继承。
public class CreateGroupNameValidator {
private LengthValidator lengthValidator;
public CreateGroupNameValidator() {
lengthValidator = new LengthValidator();
}
// ...
}
尽管如此,将验证器放在会话范围内还是有点可疑。这意味着验证器的行为特定于当前的 HTTP 会话。我想不出合理的现实世界用例,因为它们本质上是视图范围的(不是验证器实例,而是验证器属性)。通常,会话范围内的数据(例如登录用户)在线程本地基础上改为 injected/resolved。如果它是有状态的(即验证器属性可能在每个 request/view 基础上有所不同),或者如果它是无状态的(即验证器属性在整个应用程序的生命周期中是相同的),你最好让它在请求范围内。