jsf - Cómo inyectar @EJB, @PersistenceContext, @Inject, @Autowired, etc. en @FacesConverter?
dependency-injection (5)
¿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 inyección de dependencia 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:
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
<h:inputXxx converter="#{yourConverter}">
lugar de<h:inputXxx converter="yourConverter">
, o como<f:converter binding="#{yourConverter}">
lugar de<f:converter converterId="yourConverter">
. ¡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.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 e.g. either YourEntity yourEntity = yourBean.getService().findByStringId(value); // Or YourEntity yourEntity = yourBean.findEntityByStringId(value);
De esta manera puedes seguir usando
@FacesConverter
.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 programación .
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<f:selectItem(s)>
, entonces la alternativa es usarSelectItemsConverter
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.<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
Consulte también el valor de configuración del error de conversión para ''convertidor nulo'' .
Ver también:
@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();
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
https://.com/a/33017416/5626568
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.
Por Luis Chacon, Sv
Funciona bien, probado
definición EJB:
@Stateless
@LocalBean
public class RubroEJB {
@PersistenceContext(unitName = "xxxxx")
private EntityManager em;
public List<CfgRubroPres> getAllCfgRubroPres(){
List<CfgRubroPres> 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<CfgCuentaPres> listCuentas=service.getCfgCuentaEJB().getAllCfgCuentaPres();
................
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 alcance 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));
}
...