@Inject para pasar los parámetros a un CDI @Named Bean a través de URL

Si no puedo usar la anotación @ManagedProperty con @Named, porque @ManagedProperty no funciona en CDI (?), ¿Cómo transfiere los parámetros en la URL al cliente de facelets? En mi código, quiero pasar javax.mail.getMessageNumber () a details.xhtml a través de los botones “atrás” y “reenviar”.

Entiendo que se debe usar @Inject, pero ¿qué se está inyectando y cómo, por favor?

De los registros Glassfish, ID siempre es 0, lo cual es bastante extraño. Incluso cuando se hace clic en “avanzar”, el ID nunca pasa de 1, no importa cuántas veces se haga clic en el botón. Por supuesto, eso es simplemente un síntoma del problema. El resultado deseado, por supuesto, es avanzar al siguiente mensaje.

Tal vez poner el mensaje, o al menos el int, en la sesión?

El cliente como tal:

                       

y el frijol como tal:

 package net.bounceme.dur.nntp; import java.util.logging.Level; import java.util.logging.Logger; import javax.enterprise.context.RequestScoped; import javax.faces.bean.ManagedProperty; import javax.inject.Named; import javax.mail.Message; @Named @RequestScoped public class Detail { private static final Logger logger = Logger.getLogger(Detail.class.getName()); private static final Level level = Level.INFO; @ManagedProperty(value = "#{param.id}") private Integer id = 0; private Message message = null; private SingletonNNTP nntp = SingletonNNTP.INSTANCE; public Detail() { message = nntp.getMessage(id); } public int forward() { logger.log(level, "Detail.forward.." + id); id = id + 1; logger.log(level, "..Detail.forward " + id); return id; } public int back() { logger.log(level, "Detail.back.." + id); id = id - 1; logger.log(level, "..Detail.back " + id); return id; } public Message getMessage() { return message; } public String getContent() throws Exception { return message.getContent().toString(); } } 

La anotación JSF @ManagedProperty solo funciona en clases JSF @ManagedBean . Es decir, en instancias que son administradas por JSF. No funciona en instancias administradas por CDI @Named . Además, cometió otro error: está tratando de preparar el Message función de la propiedad administrada en el constructor. Si fuera un @ManagedBean real, tampoco habría funcionado. La propiedad administrada no está disponible durante la construcción, simplemente porque no es posible llamar al método setter antes de llamar al constructor. Habría utilizado un método @PostConstruct para esto. Pero esta no es la solución ya que @ManagedProperty no funciona en un @Named todos modos.

Para tener un reemplazo real para @ManagedProperty , necesitaría crear una anotación CDI personalizada. Un ejemplo concreto se publica en este blog . Aquí hay un extracto de relevancia:

La anotación personalizada de @HttpParam :

 @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface HttpParam { @NonBinding public String value() default ""; } 

El productor de valor de anotación:

 public class HttpParamProducer { @Inject FacesContext facesContext; @Produces @HttpParam String getHttpParameter(InjectionPoint ip) { String name = ip.getAnnotated().getAnnotation(HttpParam.class).value(); if ("".equals(name)) name = ip.getMember().getName(); return facesContext.getExternalContext() .getRequestParameterMap() .get(name); } } 

Un ejemplo de uso:

 @Inject @HttpParam private String id; 

La biblioteca de utilidades JSF OmniFaces tiene un @Param para este propósito, con soporte incorporado para la conversión y validación de JSF.


Alternativamente, también puede tomar manualmente el parámetro de solicitud del contexto externo en el bean gestionado Detail . La forma recomendada de hacer la inicialización de bean administrada es usar un método @PostConstruct , no el constructor, ya que el constructor se puede usar para propósitos completamente diferentes que la creación de @PostConstruct administrados:

 @PostConstruct public void init() { String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id"); // ... } 

Otra forma, IMO también más adecuada para este caso particular, es usar que también le permite convertir la ID a Message directamente mediante un convertidor personalizado.

    

con solo

 @Named public class Detail { private Message message; // Getter+setter } 

y un

 @FacesConverter("messageConverter") public class MessageConverter implements Converter { // Convert string id to Message object in getAsObject(). // Convert Message object to string id in getAsString(). } 

Ver también

  • ViewParam vs @ManagedProperty (value = “# {param.id}”)
  • Comunicación en JSF 2.0 – procesamiento de los parámetros de solicitud GET

Primero, para explicar la parte extraterrestre: Glassfish utiliza JBoss Weld como su implementación de CDI, Oracle no desarrolla una implementación propia.

Y sobre el significado del mensaje de error: FacesContext simplemente no es inyectable a través de @Inject . Hay una solicitud de función bastante antigua para eso, y creo que Seam o Solder proporcionan un productor. Pero no es necesario integrar ninguna de las bibliotecas solo para eso. Access enfrenta el contexto como lo haría en el bean administrado normal, a través de FacesContext.getCurrentInstance() .

Estaba preguntando una forma compleja de hacer algo simple. En CDI, para pasar parámetros a su alrededor no puede usar @ManagedProperty, como se explicó anteriormente por BalusC. En cambio, simplemente configura sus archivos xhtml de la siguiente manera:

                                       #{messages.getUrl(m)}     

a:

                            

Solo estoy incluyendo esto para cualquiera que venga, para aclarar que, para este simple ejemplo, no necesita un convertidor, que el valor predeterminado funciona bien.

La pregunta original está más que un poco destrozada, también. Al mirar otras preguntas sobre esto, creo que otros podrían beneficiarse de un ejemplo simple como este. Muchos ejemplos son demasiado complejos o involucran a EJB, etc.