如何使用@EJB,@ PersistenceContext,@ Inject,@ Autowired注入@FacesValidator

时间:2011-09-27 16:14:07

标签: spring validation jsf-2 dependency-injection service-layer

如何在@EJB中注入@PersistenceContext@Inject@AutoWired@FacesValidator等依赖项?在我的具体情况下,我需要通过@AutoWired注入一个Spring托管bean:

@FacesValidator("emailExistValidator")
public class EmailExistValidator implements Validator {

    @Autowired
    private UserDao userDao;

    // ...
}

然而,它没有被注入,它仍然是null,导致java.lang.NullPointerException。 似乎@EJB@PersistenceContext@Inject也不起作用。

如何在验证程序中注入服务依赖项以便我可以访问数据库?

2 个答案:

答案 0 :(得分:62)

@FacesValidator不由注入容器管理。您需要将其设置为托管bean。使用Spring的@Component,CDI的@Named或JSF的@ManagedBean而不是@FacesValidator,以使其成为托管bean,从而有资格进行依赖注入。

例如,假设您要使用JSF的@ManagedBean

@ManagedBean
@RequestScoped
public class EmailExistValidator implements Validator {
    // ...
}

您还需要在EL中将#{name}引用为托管bean,而不是硬编码字符串中的验证器ID。所以,所以

<h:inputText ... validator="#{emailExistValidator.validate}" />

<f:validator binding="#{emailExistValidator}" />

而不是

<h:inputText ... validator="emailExistValidator" />

<f:validator validatorId="emailExistValidator" />

这确实很尴尬。 JSF人员已经证实了这种令人尴尬的疏忽,他们会在即将到来的JSF 2.2 2.3中使@FacesValidator(和@FacesConverter)成为符合条件的注射目标,另请参阅JSF spec issue 763 。对于EJB,可以通过从JNDI手动获取它来解决此问题,另请参阅Getting an @EJB in @FacesConverter and @FacesValidator。如果您碰巧使用CDI扩展程序MyFaces CODI,那么您也可以通过在类上添加@Advanced注释来解决它。

另见:


更新:如果您碰巧使用JSF实用程序库OmniFaces,因为版本1.6增加了对@Inject@EJB @FacesValidator的透明支持1}}没有任何附加配置或注释的类。另请参阅the CDI @FacesValidator showcase example

答案 1 :(得分:0)

现在,如果您使用的是Java EE 8和/或JSF 2.3,则可以注入JSF验证器。

使用Mojarra 2.3.9.payara-p2在Payara Server 5.192 #badassfish上进行了测试。

<?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://xmlns.jcp.org/jsf/html">
    <h:body>
        Hello from Facelets
        <h:form>
            <h:messages/>
            <h:inputText value="#{someBean.txtField}" validator="someValidator"/>
        </h:form>
    </h:body>
</html>
import javax.inject.Named;
import javax.enterprise.context.Dependent;

@Named(value = "someBean")
@Dependent
public class SomeBean {

  private String txtField;

  public String getTxtField() {
    return txtField;
  }

  public void setTxtField(String txtField) {
    this.txtField = txtField;
  }
}
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;

@FacesValidator(value = "someValidator", managed = true)
public class CustomValidator implements Validator<String> {

  @Inject
  NewClass newClass;

  @Override
  public void validate(FacesContext context, UIComponent component, String value)
      throws ValidatorException {

    System.out.println("validator running");
    System.out.println("injected bean: " + newClass);

    if (value != null && value.equals("badvalue")) {
      throw new ValidatorException(new FacesMessage(newClass.getMessage()));
    }
  }
}
public class NewClass {

  public String getMessage() {
    return "secret message";
  }
}
import javax.faces.annotation.FacesConfig;

// WITHOUT THIS INJECTION WILL NOT WORK!
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class ConfigurationBean {
}

应呈现以下内容:

enter image description here

在意识到需要ConfigurationBean之前,我把头撞在墙上约一个小时。从文档中:

  

FacesConfig.Version.JSF_2_3   此值表明CDI应该用于EL解析并启用JSF CDI注入,如第5.6.3节“用于EL解析的CDI”和第5.9节“ CDI集成”中所述

根据GitHub问题,https://github.com/eclipse-ee4j/glassfish/issues/22094

  

默认情况下,除非应用程序中包含带有注解@ javax.faces.annotation.FacesConfig的CDI托管Bean,否则JSF 2.3以与以前版本的JSF兼容的方式运行。要切换到JSF 2.3模式,您将需要一个如下所示的配置bean:(显示ConfigurationBean

     

...

     

需要将JSF切换到“当前版本”这一事实引起了很大争议。几乎整个EG都对此表示反对,但是最终我们无法解决JCP为Java EE和规范负责人强制执行的向后兼容性要求。