Generic JSF entity converter [duplikat]

To pytanie ma już odpowiedź tutaj:

[1]}piszę swoją pierwszą aplikację internetową Java EE 6 jako ćwiczenie do nauki. Nie używam frameworka, tylko JPA 2.0, EJB 3.1 i JSF 2.0.

Mam własny konwerter do konwersji encji JPA przechowywanej w komponencie SelectOne z powrotem na / Align = "left" / Używam InitialContext./ align = "left" /

Chciałbym utworzyć ogólny konwerter encji, więc nie muszę tworzyć konwertera dla każdego encji. Pomyślałem, że stworzę abstrakcyjny byt i każę wszystkim Bytom go rozszerzyć. Następnie Utwórz niestandardowy Konwerter dla elementu abstrakcyjnego i użyj go jako konwertera dla wszystkich elementów.

Czy to brzmi rozsądnie i / lub praktycznie?

Czy miałoby sens nie mieć abstrakcyjny byt, tylko konwerter, który konwertuje dowolny byt? W takim razie nie jestem pewien, w jaki sposób uzyskałbym odniesienie do odpowiedniej fasoli sesji.

Włączyłem mój konwerter, ponieważ nie jestem pewien, czy uzyskuję odniesienie do mojej sesji w najbardziej efektywny sposób.

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());
    }
}
Author: BalusC, 2010-11-24

7 answers

Cóż, dzisiaj miałem ten sam problem i rozwiązałem go, tworząc ogólny ConversionHelper i używając go w konwerterze. W tym celu mam EntityService, który jest ogólnym SLSB, którego używam do wykonywania prostych operacji CRUD dla dowolnego typu encji. Również moje encje implementują interfejs PersistentEntity, który ma metody getId i setId i trzymam je za pomocą prostych kluczy podstawowych. To wszystko.

W końcu mój konwerter wygląda tak:


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

I moje nawrócenie helper wygląda tak:

public final class ConversionHelper {

    private ConversionHelper() {
    }

    public static <T> T getAsObject(Class<T> 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;
    }
}

Teraz tworzenie konwerterów dla prostych encji JPA jest kwestią powielenia konwertera i zmiany 3 parametrów.

To działa dobrze dla mnie, ale nie wiem, czy jest to najlepsze podejście pod względem stylu i wydajności. Wszelkie wskazówki będą mile widziane.

 7
Author: rbento,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-18 14:40:20

Używam JSF 2.0 Zobacz mapę:

@FacesConverter("entityConverter")
public class EntityConverter implements Converter {

private static final String key = "com.example.jsf.EntityConverter";
private static final String empty = "";

private Map<String, Object> getViewMap(FacesContext context) {
    Map<String, Object> viewMap = context.getViewRoot().getViewMap();
    @SuppressWarnings({ "unchecked", "rawtypes" })
    Map<String, Object> idMap = (Map) viewMap.get(key);
    if (idMap == null) {
        idMap = new HashMap<String, Object>();
        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;
}
}
 7
Author: Ecmel Ercan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-26 12:41:47

Moje rozwiązanie jest następujące:

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

I na stronach:

 <h:selectOneMenu id="x" value="#{controller.x}" 
      converter="#{entityConverterBuilderBean.createConverter('com.test.model.TestEntity')}">
 2
Author: alexandrubarbat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-19 16:14:57

Użyj powierzchni Seam, zapewnia klasę konwertera, która robi to, co chcesz.

Org.jboss.seam.twarze.nawrócenie.Konwerter

Chociaż jest to projekt JBoss, Seam 3 działa dobrze z Glassfish 3.1 i nowsze.

Http://seamframework.org/Seam3/FacesModule

Na 3.1 ma kilka dodatkowych zależności; zobacz http://blog.ringerc.id.au/2011/05/using-seam-3-with-glassfish-31.html

 1
Author: Craig Ringer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-30 07:25:41

Spróbuj użyć powierzchni szwu z 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;
    }

}
 1
Author: ichalos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-06 07:31:39

Używam czegoś takiego:

@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 jest zdefiniowana w ten sposób (implementacja jest tutaj poza zakresem):

public interface ConversionService {

    <T> T convert(Class<T> targetType, Object source);
}

W szablonie użyj <f:converter binding="#{entityConverter}" />.

 1
Author: Xavier Dury,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 12:59:52

Aby uzupełnić odpowiedź Craiga Ringera, możesz użyć generycznego org.jboss.seam.faces.conversion.ObjectConverter z szwu 3 Fasesmodule .

Możesz pobrać kod tutaj : https://github.com/seam/faces/blob/develop/impl/src/main/java/org/jboss/seam/faces/conversion/ObjectConverter.java

Używa 2 HashMaps (jeden jest używany odwrotnie) i przechowuje swoje obiekty w Conversation.

 0
Author: Anthony O.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-12 10:12:44