Cómo inyectar @EJB, @PersistenceContext, @Inject, @Autowired, etc. en @FacesConverter?

¿Cómo puedo inyectar una dependencia como @EJB , @PersistenceContext , @Inject , @AutoWired , etc. en @FacesConverter ? En mi caso específico, necesito inyectar un EJB a través de @EJB :

 @FacesConverter public class MyConverter implements Converter { @EJB protected MyService myService; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { // myService.doSomething } } 

Sin embargo, no se inyectó y permanece null , lo que da como resultado NPE. Parece que @PersistenceContext y @Inject tampoco funcionan.

¿Cómo puedo inyectar una dependencia de servicio en mi convertidor para poder acceder al DB?

¿Puedo usar @EJB para inyectar mi servicio en @FacesConverter ?

No, hasta que se libere JSF 2.3. Los chicos de JSF / CDI están trabajando en eso para JSF 2.3. Ver también el número de especificación JSF 1349 y este relacionado “¿Qué hay de nuevo en JSF 2.3?” artículo de mi compañero Arjan Tijms. Solo entonces la dependency injection como @EJB , @PersistenceContext , @Inject , etc. funcionará en @FacesConverter cuando agregue explícitamente el atributo managed=true a la anotación.

 @FacesConverter(value="yourConverter", managed=true) public class YourConverter implements Converter { @Inject private YourService service; // ... } 

Si no, ¿cuál es la forma “correcta” de hacer esto?

Antes de JSF 2.3, tienes varias opciones:

  1. En cambio, conviértalo en un frijol administrado. Puede convertirlo en un bean gestionado JSF, CDI o Spring a través de @ManagedBean , @Named o @Component . El siguiente ejemplo lo convierte en un bean gestionado JSF.

     @ManagedBean @RequestScoped public class YourConverter implements Converter { @EJB private YourService service; // ... } 

    Y el siguiente ejemplo lo convierte en un frijol administrado por CDI.

     @Named @RequestScoped public class YourConverter implements Converter { @Inject private YourService service; // ... } 

    Referenciarlo como lugar de , o como lugar de . ¡No olvides eliminar la anotación @FacesConverter !

    La desventaja es que no puede especificar forClass y, por lo tanto, necesita definir manualmente el convertidor en todas partes en la vista donde sea necesario.

  2. Inyectarlo en un frijol administrado regular en su lugar.

     @ManagedBean @RequestScoped public class YourBean { @EJB private YourService service; // ... } 

    Y en tu convertidor, cógelo o llámalo por EL.

     YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class); // Then eg either YourEntity yourEntity = yourBean.getService().findByStringId(value); // Or YourEntity yourEntity = yourBean.findEntityByStringId(value); 

    De esta manera puedes seguir usando @FacesConverter .

  3. Manualmente toma el EJB de JNDI.

     YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService"); 

    La desventaja es que existe un cierto riesgo de que esto no sea totalmente portátil. Consulte también Inyectar el bean EJB del bean gestionado JSF mediante progtwigción .

  4. Instala OmniFaces . Desde la versión 1.6, agrega de forma transparente soporte para @EJB (y @Inject ) en un @FacesConverter sin más modificaciones. Ver también el escaparate . Si necesita el convertidor para , entonces la alternativa es usar SelectItemsConverter que realizará automáticamente el trabajo de conversión basado en elementos seleccionados sin la necesidad de ninguna interacción con la base de datos.

      

    Consulte también el valor de configuración del error de conversión para ‘convertidor nulo’ .

Ver también:

  • Cómo inyectar en @FacesValidator con @EJB, @PersistenceContext, @Inject, @Autowired
  • Inyección de CDI en un FacesConverter
  • Obtener un @EJB en @FacesValidator y @FacesConverter

La respuesta es Sí, si puede acomodar el módulo Seam Faces en su aplicación web. Compruebe esta publicación Injection of EntityManager o CDI Bean en FacesConverter . Puedes usar @EJB de manera similar.

Puede acceder a él indirectamente a través de FacesContext, que es un parámetro en ambos métodos de conversión.

El convertidor también puede ser anotado CDI con el nombre de Alcance de la aplicación. Al acceder a la fachada, se usan dos instancias de la misma clase. Una es la instancia del convertidor en sí misma, tonta, sin conocer la anotación EJB. Otra instancia se conserva en el scope de la aplicación y se puede acceder a través de FacesContext. Esa instancia es un objeto con nombre, por lo que conoce la anotación EJB. Como todo se hace en una sola clase, el acceso se puede mantener protegido.

Vea el siguiente ejemplo:

 @FacesConverter(forClass=Product.class) @Named @ApplicationScoped public class ProductConverter implements Converter{ @EJB protected ProductFacade facade; protected ProductFacade getFacadeFromConverter(FacesContext ctx){ if(facade==null){ facade = ((ProductConverter) ctx.getApplication() .evaluateExpressionGet(ctx,"#{productConverter}",ProductConverter.class)) .facade; } return facade; } @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { return getFacadeFromConverter(context).find(Long.parseLong(value)); } ... 

@Inject solo funcionará en instancias administradas por CDI

Esto solo funciona al menos en el servidor Java EE 7 y CDI 1.1 :

 @FacesConverter public class MyConverter implements Converter { protected MyService myService; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { myService = CDI.current().select(MyService .class).get(); myService.doSomething(); } } 

Por Luis Chacon, Sv

Funciona bien, probado

definición EJB:

 @Stateless @LocalBean public class RubroEJB { @PersistenceContext(unitName = "xxxxx") private EntityManager em; public List getAllCfgRubroPres(){ List rubros = null; Query q = em.createNamedQuery("xxxxxxx"); rubros = q.getResultList(); return rubros; } } 

defina bean con el ámbito de bean Aplication, para obtener el objeto EJB

 @ManagedBean(name="cuentaPresService", eager = true) @ApplicationScoped public class CuentaPresService { @EJB private RubroEJB cfgCuentaEJB; public RubroEJB getCfgCuentaEJB() { return cfgCuentaEJB; } public void setCfgCuentaEJB(RubroEJB cfgCuentaEJB) { this.cfgCuentaEJB = cfgCuentaEJB; } } 

Acceso final al objeto Ejb del convertidor:

 @FacesConverter("cuentaPresConverter") public class CuentaPresConverter implements Converter { @EJB RubroEJB rubroEJB; public Object getAsObject(FacesContext fc, UIComponent uic, String value) { if(value != null && value.trim().length() > 0) { try { CuentaPresService service = (CuentaPresService) fc.getExternalContext().getApplicationMap().get("cuentaPresService"); List listCuentas=service.getCfgCuentaEJB().getAllCfgCuentaPres(); ................