@Inject per passare parametri a un bean @Name CDI tramite URL

Se non riesco a utilizzare l’annotazione @ManagedProperty con @Named, poiché @ManagedProperty non funziona in CDI (?), Come passi i parametri nell’URL al client facelets? Nel mio codice, voglio passare javax.mail.getMessageNumber () a details.xhtml tramite i pulsanti “indietro” e “avanti”.

Capisco che @Inject dovrebbe essere usato, ma cosa viene iniettato e come, per favore?

Dai log di glassfish, id è sempre 0, il che è piuttosto strano. Anche quando si fa clic su “avanti”, l’ID non viene mai sopra 1 indipendentemente dal numero di volte in cui si fa clic sul pulsante. Certo, questo è solo un sintomo del problema. L’output desiderato, ovviamente, è quello di passare al prossimo messaggio.

Forse inserire il messaggio, o almeno l’int, nella sessione?

Il cliente in questo modo:

                       

e il fagiolo in questo modo:

 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(); } } 

L’annotazione JSF @ManagedProperty funziona solo nelle classi JSF @ManagedBean . Ovvero in istanze gestite da JSF. Non funziona in istanze gestite da CDI @Named . Inoltre, hai fatto un altro errore: stai cercando di preparare il Message base alla proprietà gestita nel costruttore. Se fosse un vero @ManagedBean , anche questo non avrebbe funzionato. La proprietà gestita non è disponibile durante la costruzione, semplicemente perché non è ansible chiamare il metodo setter prima che il costruttore venga chiamato. Avresti usato un metodo @PostConstruct per questo. Ma questa non è la soluzione in quanto @ManagedProperty non funziona comunque in un @Named .

Per avere una sostituzione reale per @ManagedProperty , devi creare un’annotazione CDI personalizzata. Un esempio concreto è pubblicato in questo blog . Ecco un estratto di pertinenza:

L’annotazione personalizzata @HttpParam :

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

Il produttore del valore di annotazione:

 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 esempio di utilizzo:

 @Inject @HttpParam private String id; 

La libreria di utilità JSF OmniFaces ha un @Param per questo scopo, con supporto integrato per la conversione e la convalida JSF.


In alternativa, è anche ansible acquisire manualmente il parametro di richiesta dal contesto esterno nel bean gestito Detail . Il metodo consigliato per eseguire l’inizializzazione del bean gestito è utilizzare un metodo @PostConstruct , non il costruttore, poiché il costruttore potrebbe essere utilizzato per scopi completamente diversi rispetto alla creazione di bean gestiti:

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

Un altro modo, IMO anche più adatto per questo caso particolare, è utilizzare che consente anche di convertire l’ID in Message direttamente da un convertitore personalizzato.

    

con giusto

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

e a

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

Guarda anche

  • ViewParam vs @ManagedProperty (value = “# {param.id}”)
  • Comunicazione in JSF 2.0 – elaborazione dei parametri di richiesta GET

Innanzitutto, per spiegare la parte aliena – Glassfish utilizza JBoss Weld come implementazione del CDI, Oracle non sviluppa un’implementazione a sé stante.

E riguardo al significato del messaggio di errore: FacesContext semplicemente non è iniettabile tramite @Inject . C’è una richiesta piuttosto vecchia per questo, e penso che Seam o Solder forniscano un produttore. Ma non c’è bisogno di integrare nessuna delle librerie solo per quello. Accedere al contesto di facce come nel normale bean gestito, tramite FacesContext.getCurrentInstance() .

Stavo chiedendo un modo complesso di fare una cosa semplice. In CDI, per passare i parametri intorno a te non puoi usare @ManagedProperty, come spiegato sopra da BalusC. Invece, hai appena configurato i tuoi file xhtml in questo modo:

                                       #{messages.getUrl(m)}     

a:

                            

Sto solo includendo questo per chiunque arrivi, per chiarire che, per questo semplice esempio, non hai bisogno di un convertitore, che il default funzioni bene.

Anche la domanda originale è più che un po ‘mutilata. Guardando altre domande su questo, penso che altri potrebbero beneficiare di un semplice esempio come questo. Così tanti esempi sono eccessivamente complessi, o coinvolgono EJB, ecc.