Convertitore di entity framework JSF generico

Sto scrivendo la mia prima app web Java EE 6 come esercizio di apprendimento. Non sto usando un framework, solo JPA 2.0, EJB 3.1 e JSF 2.0.

Ho un convertitore personalizzato per convertire un’entity framework JPA memorizzata in un componente SelectOne in un’ quadro. Sto usando un InitialContext.lookup per ottenere un riferimento a un Session Bean per trovare l’ quadro rilevante.

Mi piacerebbe creare un convertitore di quadro generico in modo da non dover creare un convertitore per quadro. Ho pensato di creare un’ quadro astratta e farla estendere a tutte le quadro. Quindi creare un convertitore personalizzato per l’ quadro astratta e utilizzarlo come convertitore per tutte le quadro.

Suona ragionevole e / o praticabile?

Avrebbe più senso non avere un’ quadro astratta, solo un convertitore che converte qualsiasi entity framework? In tal caso non sono sicuro di come ottenere un riferimento al Session Bean appropriato.

Ho incluso il mio convertitore corrente perché non sono sicuro di ottenere un riferimento al mio Session Bean nel modo più efficiente.

package com.mycom.rentalstore.converters; import com.mycom.rentalstore.ejbs.ClassificationEJB; import com.mycom.rentalstore.entities.Classification; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; import javax.faces.convert.FacesConverter; import javax.naming.InitialContext; import javax.naming.NamingException; @FacesConverter(forClass = Classification.class) public class ClassificationConverter implements Converter { private InitialContext ic; private ClassificationEJB classificationEJB; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { try { ic = new InitialContext(); classificationEJB = (ClassificationEJB) ic.lookup("java:global/com.mycom.rentalstore_RentalStore_war_1.0-SNAPSHOT/ClassificationEJB"); } catch (NamingException e) { throw new ConverterException(new FacesMessage(String.format("Cannot obtain InitialContext - %s", e)), e); } try { return classificationEJB.getClassificationById(Long.valueOf(value)); } catch (Exception e) { throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Classification - %s", value, e)), e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { return String.valueOf(((Classification) value).getId()); } } 

Bene, oggi ho avuto lo stesso problema e l’ho risolto creando un ConversionHelper generico e utilizzandolo nel convertitore. Per questo scopo ho un EntityService che è un SLSB generico che uso per eseguire semplici operazioni CRUD per qualsiasi tipo di entity framework. Anche le mie entity framework implementano un’interfaccia PersistentEntity, che ha metodi getId e setId e li tengo con semplici chiavi primarie. Questo è tutto.

Alla fine il mio convertitore assomiglia a questo:

@FacesConverter(value = "userConverter", forClass = User.class) public class UserConverter implements Converter { @Override public Object getAsObject(FacesContext ctx, UIComponent component, java.lang.String value) { return ConversionHelper.getAsObject(User.class, value); } @Override public String getAsString(FacesContext ctx, UIComponent component, Object value) { return ConversionHelper.getAsString(value); } }
@FacesConverter(value = "userConverter", forClass = User.class) public class UserConverter implements Converter { @Override public Object getAsObject(FacesContext ctx, UIComponent component, java.lang.String value) { return ConversionHelper.getAsObject(User.class, value); } @Override public String getAsString(FacesContext ctx, UIComponent component, Object value) { return ConversionHelper.getAsString(value); } } 

E il mio helper di conversione ha questo aspetto:

public final class ConversionHelper { private ConversionHelper() { } public static  T getAsObject(Class returnType, String value) { if (returnType== null) { throw new NullPointerException("Trying to getAsObject with a null return type."); } if (value == null) { throw new NullPointerException("Trying to getAsObject with a null value."); } Long id = null; try { id = Long.parseLong(value); } catch (NumberFormatException e) { throw new ConverterException("Trying to getAsObject with a wrong id format."); } try { Context initialContext = new InitialContext(); EntityService entityService = (EntityService) initialContext.lookup("java:global/myapp/EntityService"); T result = (T) entityService.find(returnType, id); return result; } catch (NamingException e) { throw new ConverterException("EntityService not found."); } } public static String getAsString(Object value) { if (value instanceof PersistentEntity) { PersistentEntity result = (PersistentEntity) value; return String.valueOf(result.getId()); } return null; } }
public final class ConversionHelper { private ConversionHelper() { } public static  T getAsObject(Class returnType, String value) { if (returnType== null) { throw new NullPointerException("Trying to getAsObject with a null return type."); } if (value == null) { throw new NullPointerException("Trying to getAsObject with a null value."); } Long id = null; try { id = Long.parseLong(value); } catch (NumberFormatException e) { throw new ConverterException("Trying to getAsObject with a wrong id format."); } try { Context initialContext = new InitialContext(); EntityService entityService = (EntityService) initialContext.lookup("java:global/myapp/EntityService"); T result = (T) entityService.find(returnType, id); return result; } catch (NamingException e) { throw new ConverterException("EntityService not found."); } } public static String getAsString(Object value) { if (value instanceof PersistentEntity) { PersistentEntity result = (PersistentEntity) value; return String.valueOf(result.getId()); } return null; } } 

Ora creare convertitori per semplici quadro JPA è questione di duplicare un convertitore e modificare 3 parametri.

Funziona bene per me, ma non so se sia l’approccio migliore in termini di stile e prestazioni. Qualsiasi consiglio sarebbe apprezzato.

Sto usando la mappa di visualizzazione JSF 2.0:

 @FacesConverter("entityConverter") public class EntityConverter implements Converter { private static final String key = "com.example.jsf.EntityConverter"; private static final String empty = ""; private Map getViewMap(FacesContext context) { Map viewMap = context.getViewRoot().getViewMap(); @SuppressWarnings({ "unchecked", "rawtypes" }) Map idMap = (Map) viewMap.get(key); if (idMap == null) { idMap = new HashMap(); viewMap.put(key, idMap); } return idMap; } @Override public Object getAsObject(FacesContext context, UIComponent c, String value) { if (value.isEmpty()) { return null; } return getViewMap(context).get(value); } @Override public String getAsString(FacesContext context, UIComponent c, Object value) { if (value == null) { return empty; } String id = ((Persistent) value).getId().toString(); getViewMap(context).put(id, value); return id; } } 

la mia soluzione è la seguente:

 @ManagedBean @SessionScoped public class EntityConverterBuilderBean { private static Logger logger = LoggerFactory.getLogger(EntityConverterBuilderBean.class); @EJB private GenericDao dao; public GenericConverter createConverter(String entityClass) { return new GenericConverter(entityClass, dao); } } public class GenericConverter implements Converter { private Class clazz; private GenericDao dao; public GenericConverter(String clazz, Generic dao) { try { this.clazz = Class.forName(clazz); this.dao = dao; } catch (Exception e) { logger.error("cannot get class: " + clazz, e); throw new RuntimeException(e); } } public Object getAsObject(javax.faces.context.FacesContext facesContext, javax.faces.component.UIComponent uiComponent, java.lang.String s) { Object ret = null; if (!"".equals(s)) { Long id = new Long(s); ret = dao.findById(clazz, id); } return ret; } public String getAsString(javax.faces.context.FacesContext facesContext, javax.faces.component.UIComponent uiComponent, java.lang.Object o) { if (o != null) { return ((SimpleEntity) o).getId() + ""; } else { return ""; } } } 

e nelle pagine:

   

Utilizza Seam Faces, fornisce una class Converter che fa ciò che vuoi.

org.jboss.seam.faces.conversion.Converter

Mentre è un progetto JBoss, Seam 3 funziona perfettamente con Glassfish 3.1 e successivi.

http://seamframework.org/Seam3/FacesModule

Nella versione 3.1 ha un paio di dipendenze aggiuntive; vedi http://blog.ringerc.id.au/2011/05/using-seam-3-with-glassfish-31.html

Prova questo usando Seam Faces di Seam 3.

 @Named("DocTypeConverter") public class DocumentTypeConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; @Inject private DocumentTypeSessionEJB proDocTypeSb; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { DocumentType result = null; if (value != null && !value.trim().equals("")) { try { result = (DocumentType) proDocTypeSb.findById(DocumentType.class, value); } catch(Exception exception) { throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid value")); } } return result; } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { String result = null; if (value != null && value instanceof DocumentType){ DocumentType docType = (DocumentType) value; result = docType.getId(); } return result; } } 

Sto usando qualcosa del genere:

 @Named public class EntityConverter implements Converter { @Inject private EntityManager entityManager; @Inject private ConversionService conversionService; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { Class entityType = component.getValueExpression("value").getType(context.getELContext()); Class idType = this.entityManager.getMetamodel().entity(entityType).getIdType().getJavaType(); Object id = this.conversionService.convert(idType, value); return this.entityManager.getReference(entityType, id); // find() is possible too } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { Object id = this.entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(value); return this.conversionService.convert(String.class, id); } } 

ConversionService è definito in questo modo (l’implementazione è fuori ambito qui):

 public interface ConversionService {  T convert(Class targetType, Object source); } 

nel modello, usa .

Per completare la risposta di Craig Ringer, puoi utilizzare il generico org.jboss.seam.faces.conversion.ObjectConverter di Seam 3 FacesModule .

Puoi prendere il codice qui: https://github.com/seam/faces/blob/develop/impl/src/main/java/org/jboss/seam/faces/conversion/ObjectConverter.java

Usa 2 HashMap s (uno è usato all’inverso) e conserva i suoi oggetti nella Conversation .