这是JSF会话作用域验证器的正常行为吗?

这是JSF会话作用域验证器的正常行为吗?,jsf,jsf-2.2,Jsf,Jsf 2.2,实现:org.glassfish 2.2.12 我有以下会话范围的验证器: @ManagedBean @SessionScoped public class CreateGroupNameValidator extends LengthValidator implements Serializable{ @ManagedProperty(value="#{myDao}") private MyDao myDao; //Validate methods } 尽管是会话

实现:org.glassfish 2.2.12

我有以下会话范围的验证器:

@ManagedBean
@SessionScoped
public class CreateGroupNameValidator extends LengthValidator implements Serializable{ 

    @ManagedProperty(value="#{myDao}")
    private MyDao myDao;
    //Validate methods
}
尽管是会话范围和可序列化的,但当回发时,验证程序无法恢复属性myDao的值。我使用了debugger并计算出状态由类
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.:

验证程序
实现必须具有零参数公共构造函数。此外,如果验证程序类希望在视图中保存和还原配置属性值,则实现还必须实现
StateHolder

转换器和验证器可以保存在JSF状态,这样JSF实现就可以确保它们在恢复视图后,与呈现前一个请求的视图时一样,完全具有预期的属性值(例如
最小值
最大值
长度验证器
的情况下,它们可能引用动态EL表达式)

尽管我必须承认他们在设计JSF 1.0规范(转换器/验证器仍然基于此)时确实考虑过,但他们并没有真正考虑在JSF转换器/验证器中注入业务服务实例的可能性。当然,您不想将其保存在JSF视图状态。如果是托管属性(因此不是EJB/CDI代理),它只会破坏JSF视图状态(在服务器端状态保存的情况下也会破坏HTTP会话)

如果您不需要验证程序是JSF状态感知的,请使用组合而不是继承

public class CreateGroupNameValidator { 

    private LengthValidator lengthValidator;

    public CreateGroupNameValidator() {
        lengthValidator = new LengthValidator();
    }

    // ...
}

尽管如此,将验证器放在会话范围内还是有点可疑。这意味着验证器的行为特定于当前HTTP会话。我想不出有意义的实际用例,因为它们本质上是视图范围(不是验证器实例,而是验证器属性)。通常是会话范围内的数据(例如登录用户)是在线程本地基础上注入/解析的。如果它是有状态的,最好将其设置为请求范围(即每个请求/视图的验证程序属性可能不同),如果它是无状态的,则将其设置为应用程序范围(即验证程序属性在应用程序的整个生命周期内都相同).

什么是
MyDao
?这个名字意味着它是一个服务类或EJB,不能使用
@ManagedProperty
注入,如果是这样的话(并且需要像
@EJB
@Inject
@Autowired
)这样的注释)。真正的验证器(或转换器)最多只能有两个作用域中的一个,请求作用域(
@FacesValidator
)或者应用程序作用域。其余的作用域没有多大意义。@Tiny它是一个spring bean。无法为此想出合理的现实世界用例,因为它们本身就是视图作用域。实际上,应用程序作用域会更好。您当然不想将其保存在JSF视图状态。实际上,从安全角度来看,这是不安全的。但是如果对象没有实现
StateHolder
,但是
Serializable
,如果不在
javax.faces.viewState
中,它什么时候被保存?仅仅通过
savedState=(Serializable)很难说什么toSave;className=null;
或者它是一个依赖于实现的东西,而我们实际上并不关心它?如果它实现了可序列化的
,那么它也保存在状态中。JSF规范说,附加到组件实例的对象(转换器、验证器和侦听器)也保存在状态中。但是在客户端视图状态下,我们向客户端公开我们的EJB。它安全吗?数据库实时EJB通常包含
DataSource
实现,该实现反过来保存DB url和user/passowrd
属性
EJB(和CDI bean)被注入为。