Cómo escribir un convertidor personalizado para

¿Cómo puedo escribir un convertidor personalizado cuando trabajo con componentes de PrimeFaces que usan una lista de POJO? Mi problema particular es con

 

Sin un convertidor obtengo java.lang.ClassCastException porque JSF establece los valores enviados con los valores enviados java.lang.String no convertidos.

Es posible, sin acceso a otra base de datos, pero no sé la mejor manera. Utilizo un convertidor muy específico, funciona solo para la lista de selección. Prueba esto:

 @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; } 

y lista de selección:

  

El trabajo es para mí, las mejoras son necesarias.

Después de investigar cómo escribir un convertidor personalizado, esta es la solución.
1. crea una clase Java que 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. Registre su convertidor personalizado en faces-config.xml

  projectConverter org.xdrawing.converter.ProjectConverter  

3. Ahora, dentro del componente Primefaces, simplemente haz converter="projectConverter" . Tenga en cuenta que projectConverter es la que acabo de crear. Entonces, para resolver mi problema anterior, hago esto:

  

Sí, puede escribir un convertidor que serialice / deserialice los objetos en la lista de selección de esta manera:

 @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 ""; } } } 

A continuación, aplique este convertidor en su lista de selección de esta manera:

  

y asegúrese de que sus objetos sean serializables.

Este problema no está relacionado con la prima, solo está relacionado con JSF.

¿Por qué debería golpear la base de datos otra vez? Su bean ya contiene la lista de Objetos que desea mostrar en un componente, o es un ámbito de solicitud?

  • Cree una Superclase para su Hibernate Pojo que contenga un campo de identificación. Si no quieres crear una súper clase simplemente utiliza la clase pojo, pero necesitas más clases de conversión.
  • Con esa Superclase, puede crear un convertidor genérico para todas las Clases de Pojo que contengan una lista de Pojo pasados ​​en el constructor.
  • Agregue el convertidor como una propiedad en su bean de sesión y use ese convertidor en su componente JSF.

Si accede a la lista final a través de una propiedad get en su bean o la anidada en el convertidor es de su elección.

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

¿Hay alguna manera de implementar eso sin 2 hits en la base de datos?

Quiero decir, cuando tienes

 #{bean.projects} 

esto es un hit de base de datos.

y cuando el convertidor pone

 sBean.getProjectById(value); 

es un hit innecesario de la base de datos, ya que bean.projects ya tiene el id y el valor de los objetos

Si es posible:

 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; } }; } 
 h: mensajes no muestra mensajes cuando se presiona p: commandButton
  • Validación de correo electrónico con expresión regular en JSF 2 / PrimeFaces
  • La entrada Unicode recuperada a través de los componentes de entrada de PrimeFaces se corrompe
  • ¿Cómo seleccionar componentes JSF usando jQuery?
  • PrimeFaces validador no activado
  • Orden de ejecución de eventos al presionar PrimeFaces p: commandButton
  • ¿Cómo anulo el PrimeFaces CSS predeterminado con estilos personalizados?
  • Mostrar los resultados de Hibernate / JPA en las tablas de datos JSF provoca: java.lang.NumberFormatException: para la cadena de entrada: ""
  • Mantenga p: cuadro de diálogo abierto cuando se produce un error de validación después de enviar
  • JSF + PrimeFaces: el atributo `update` no actualiza el componente
  • UISelectMany en una lista causa java.lang.ClassCastException: java.lang.String no se puede convertir a T
  • Cómo deshacerse de WARNING: PWC4011: no se puede establecer la encoding de caracteres de solicitud en UTF-8
  • La carga de archivos no funciona con AJAX en PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: el tipo de contenido de la solicitud no es multipart / form-data