Depois de ter encontrado a solução SimpleEntityConverter em http://www.rponte.com.br/tag/entity-converter/, resolvi melhorá-la, deixando-a ainda mais genérica. O próprio autor diz: "(…) É possível estende-las e até melhora-las, você é livre para isso, e dependendo da tua necessidade provavelmente será o melhor caminho, só não deixe de contribuir com o código para a comunidade (…).
1 - Não há necessidade de implementar a interface BaseEntity
2 - O id da classe pode ser String, Integer, etc. e não apenas Long como em SimpleEntityConverter, pois a classe identifica o retorno pela anotação @Id. Essa foi uma das motivações que me levaram a melhorar SimpleEntityConverter, pois algumas entidades de nossos sistemas não possuem id do tipo Long, mas String.
package net.metha.jsf.converter;
import java.lang.reflect.Field;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.persistence.Id;
/**
* Converter para entidades JPA.
* Baseia-se na anotação @Id para identificar o atributo que representa a identidade da entidade.
* @author Flávio Henrique
* @version 1.0
* @since 05/10/2010
*/
public class EntityConverter implements Converter {
public Object getAsObject(FacesContext ctx, UIComponent component,
String value) {
if (value != null) {
return component.getAttributes().get(value);
}
return null;
}
public String getAsString(FacesContext ctx, UIComponent component,
Object obj) {
if (obj != null && !"".equals(obj)) {
String id;
try {
id = this.getId(getClazz(ctx, component), obj);
if (id == null){
id = "";
}
id = id.trim();
component.getAttributes().put(id,
getClazz(ctx, component).cast(obj));
return id;
} catch (SecurityException e) {
e.printStackTrace(); // seu log aqui
} catch (IllegalArgumentException e) {
e.printStackTrace(); // seu log aqui
} catch (NoSuchFieldException e) {
e.printStackTrace(); // seu log aqui
} catch (IllegalAccessException e) {
e.printStackTrace(); // seu log aqui
}
}
return null;
}
private Class<?> getClazz(FacesContext facesContext, UIComponent component) {
return component.getValueExpression("value").getType(
facesContext.getELContext());
}
public String getId(Class<?> clazz, Object obj) throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
for (Field field : clazz.getDeclaredFields()) {
if ((field.getAnnotation(Id.class)) != null) {
Field privateField = clazz.getDeclaredField(field.getName());
privateField.setAccessible(true);
if (privateField.get(clazz.cast(obj)) != null) {
return (String)field.getType()
.cast(privateField.get(clazz.cast(obj))).toString();
} else {
return null;
}
}
}
return null;
}
}
Registre o converter em faces-config.xml:
entityConverter
net.metha.jsf.converter.EntityConverter
Use e abuse:
<h:selectOneMenu id=“comboRestaurantes"
value=”#{consumoMB.restauranteOperacao}" required="true"
label=“Restaurante” converter=“entityConverter”>
10/02/2011 -> RETIFICANDO: O CÓDIGO ACIMA NÃO É THREADSAFE, USAR DESTA FORMA:
<h:selectOneMenu id="comboRestaurantes"
value="#{consumoMB.restauranteOperacao}" required="true"
label="Restaurante">
<f:converter converterId="entityConverter"/>
</selectOneMenu>
Esta solução está sendo usada em ambiente de produção.
Atenciosamente,
Flávio Henrique de Souza Almeida