Come scrivere un convertitore personalizzato per

Come posso scrivere un convertitore personalizzato quando si lavora con componenti PrimeFaces che utilizzano un elenco di POJO? Il mio problema particolare è con

 

Senza un convertitore ricevo java.lang.ClassCastException perché JSF imposta i valori inviati con valori java.lang.String non convertiti inviati.

È ansible, senza altro accesso al database, ma non conosco il modo migliore. Io uso un convertitore molto specifico, funziona solo per picklist. Prova questo:

 @FacesConverter(value = "primeFacesPickListConverter")public class PrimeFacesPickListConverter implements Converter { @Override public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) { Object ret = null; if (arg1 instanceof PickList) { Object dualList = ((PickList) arg1).getValue(); DualListModel dl = (DualListModel) dualList; for (Object o : dl.getSource()) { String id = "" + ((Project) o).getId(); if (arg2.equals(id)) { ret = o; break; } } if (ret == null) for (Object o : dl.getTarget()) { String id = "" + ((Project) o).getId(); if (arg2.equals(id)) { ret = o; break; } } } return ret; } @Override public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) { String str = ""; if (arg2 instanceof Project) { str = "" + ((Project) arg2).getId(); } return str; } 

e lista di selezione:

  

Il lavoro è per me, i miglioramenti sono necessari.

Dopo una ricerca su come scrivere un convertitore personalizzato, ecco la soluzione.
1. creare una class Java che implementa javax.faces.convert.Converter;

 public class ProjectConverter implements Converter{ @EJB DocumentSBean sBean; public ProjectConverter(){ } public Object getAsObject(FacesContext context, UIComponent component, String value){ return sBean.getProjectById(value); //If u look below, I convert the object into a unique string, which is its id. //Therefore, I just need to write a method that query the object back from the //database if given a id. getProjectById, is a method inside my Session Bean that //does what I just described } public String getAsString(FacesContext context, UIComponent component, Object value) { return ((Project) value).getId().toString(); //--> convert to a unique string. } } 

2. Registrare il convertitore personalizzato in faces-config.xml

  projectConverter org.xdrawing.converter.ProjectConverter  

3. Quindi ora all’interno del componente Primefaces, devi solo converter="projectConverter" . Nota che projectConverter è il ho appena creato. Quindi per risolvere il mio problema sopra, lo faccio:

  

Sì, puoi scrivere un convertitore che serializza / deserializza gli oggetti nel picklist in questo modo:

 @FacesConverter(value="PositionMetricConverter") public class PositionMetricConverter implements Converter { private static final Logger log = Logger.getLogger(PositionMetricConverter.class.getName()); @Override public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value) { try { byte[] data = Base64.decodeBase64(value); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)); Object o = ois.readObject(); ois.close(); return o; } catch (Exception e) { log.log(Level.SEVERE, "Unable to decode PositionMetric!", e); return null; } } @Override public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(value); oos.close(); return Base64.encodeBase64String(baos.toByteArray()); } catch (IOException e) { log.log(Level.SEVERE, "Unable to encode PositionMetric!", e); return ""; } } } 

Quindi applica questo convertitore sul tuo elenco di selezione come questo:

  

e assicurati che i tuoi oggetti siano serializzabili.

Questo problema non è relativo alle primefaces, ma solo al JSF generale correlato.

Perché dovresti colpire nuovamente il database? Il tuo bean contiene già l’elenco di oggetti che vuoi mostrare in un componente o è richiesto per ambito?

  • Crea una Superclass per il tuo Hibernate Pojo contenente un campo id. Se non vuoi creare una super class usa semplicemente la class pojo, ma hai bisogno di più classi di convertitori.
  • Con quella Superclass puoi creare un convertitore generico per tutte le Classi Pojo contenente una lista di Pojo passati nel costruttore.
  • Aggiungi il convertitore come proprietà nel bean di sessione e utilizza quel convertitore nel tuo componente JSF.

Se si accede all’elenco finale tramite una proprietà get nel proprio bean o uno nidificato nel convertitore è di vostra scelta.

 public class SuperPojo { protected Integer id; //constructor & getter } public class PojoTest extends SuperPojo { private String label = null; //constructor & getter } public class SuperPojoConverter implements Converter { private Collection superPojos; public IdEntityConverter(Collection superPojos) { this.superPojos = superPojos; } @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { //catch exceptions and empty or null value! final int intValue = Integer.parseInt(value); for(SuperPojo superPojo : this.superPojos) if(superPojo.getId().intValue() == intValue) return superPojo; return null; } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { //catch null and instanceof return String.valueOf(((SuperPojo)value).getId().intValue()); } public Collection getSuperPojos() { return this.superPojos; } } public class Bean { private SuperPojoConverter pojoTestConverter = null; public Bean() { final List pojoTests = //get list from hibernate this.pojoTestConverter = new SuperPojoConverter(pojoTests); } public SuperPojoConverter getPojoTestConverter() { return this.pojoTestConverter; } }    

c’è un modo per implementarlo senza 2 colpi al database?

Voglio dire, quando lo hai

 #{bean.projects} 

questo è un successo di database.

e quando il convertitore mette

 sBean.getProjectById(value); 

è un hit di database non necessario, poiché bean.projects ha già id e valore degli oggetti

Si è ansible:

 public class DocumentSBean sBean implements Serializable{ private List projects; // projects methods... // ... public Converter getDocumentConverter(){ return docConverter; } private Converter docConverter = new Converter() { @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { return projects.stream().filter(p -> p.getName().equals(value)).findFirst().orElse(null); } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { return (value != null) ? ((Document) value).toString() : null; } }; } 
 Comprensione processo / aggiornamento e JSF f: ajax esegue / rende attributi
  • Come sovrascrivo CSS PrimeFaces predefinito con stili personalizzati?
  • Baccello @ViewScoped ricreato su ogni richiesta di postback quando si utilizza JSF 2.2
  • L'aggiunta di jQuery a PrimeFaces determina l'errore Uncaught TypeError su tutto il luogo
  • Una o più risorse hanno l'objective di 'testa' ma non è stato definito il componente 'testa' all'interno della vista
  • Creazione della tabella dei dettagli master e della finestra di dialogo, come riutilizzare la stessa finestra di dialogo per creare e modificare
  • Differenza tra gli attributi resi e visibili di
  • h: i messaggi non visualizzano i messaggi quando viene premuto p: commandButton