Para você: EntityConverter para qualquer entidade e tipo de Id

Olá Kristiano, puxa vida, fico muito contente em saber que o código que compartilhei o ajudou. Se quiser melhorá-lo, vá em frente.

Abraço!

ow fiquei feliz demais que deu certo, so que apareceu outro problema…
ele lista os items, mas nao consigo selecionalos… alguem sabe a solução?

Flavio Almeida,
Cara parabéns pelo otimizada no EntityConverter, realmente ficou excelente, utilizei a versão do primeiro post, que ja resolveu o meu problema, agora irei verificar com mais calma, não cheguei a ler todo o tópico, mas tens o git-hub para que possamos contribuir? :slight_smile:

Parabens pelo trabalho!!! ficou bem bacana… testei aqui e funcionou perfeito.

Parabéns! FIcou muito bom mesmo!

Eu estava pesquisando bastante sobre converters e acabei testando essa solução e ficou muito bacana!

No fim das contas eu acabei utilizando a solução do Omnifaces http://showcase-omnifaces.rhcloud.com/showcase/converters/SelectItemsIndexConverter.xhtml. Ele não faz acesso ao banco! O único problema é colocar mais uma biblioteca na aplicação, mas se pesquisar tem um ou outra coisa válida tb no OmniFaces. To usando OmniFaces e Primefaces sem problemas!

Estava tentando entender este código aí… por que é necessário o método private Class<?> getClazz(FacesContext facesContext, UIComponent component) ???

Por que não podemos obter a classe direto do "obj" que vem como parâmetro no getAsString(FacesContext ctx, UIComponent component, Object obj) com obj.getClass()

Mesma coisa no component.getAttributes().put(id, getClazz(ctx, component).cast(obj));

Por que não podemos simplesmente fazer

component.getAttributes().put(id, obj); ???

Muito legal essa classe, vai me ajudar muito!!!

Fiz apenas um modificação, como uso a tag abaixo dentro de alguns selectOneMenus opcionais:

inclui esse teste no início do getAsString() para evitar ClassCastException:

if(obj instanceof String) { return obj.toString(); }

Valeu

Olá amigos, sou extremamente novato em programação, mas estudando muuuito e altas madrugadas!

Estou implementando envio de emails com picklist da biblioteca primefaces no jsf. E estou usando um converter para obter objetos do tipo Aluno, porém não estou conseguindo popular uma lista com os nomes dos alunos que estão no Banco de dados.
SEgue códigos:

//imports

@FacesConverter(value = "aluno")
@ManagedBean(name = "CommonsMail")
@SessionScoped
public class CommonsMail implements Converter {

    @EJB
    private  com.lopes.beans.AlunoFacade ejbFacade;
    private List<Aluno> nomes = new ArrayList();

//E aí tenho o metodo getAsObjetc - Meu problema

@Override
    public Object getAsObject(FacesContext facesContext, UIComponent component, String submittedValue) {
        if (submittedValue.trim().equals("")) {
            return null;
        } else {
            try {
                int number = Integer.parseInt(submittedValue);
                System.err.println("ID:" + number);

//Aqui preciso popular a List nomes com todos os nomes da tabela Aluno do BD. teoricamente a linha abaixo funcionaria, mas li em vários tópicos que não dá para usar EJB nesse método
            nomes = ejbFacade.findNomesComEmail();
                
              } catch (NumberFormatException exception) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid player"));
            }
        }
        return null;
    }  

O que dá para eu fazer?? O Entity Manager também descobri que não dá para usar. Tentei fazer injeção na classe, porém não obtive sucesso!

Muito grato!

Pessoal, estou resgatando esse tópico pois trombei com um empecilho ao usar a entityConverter do primeiro post:

  • ao usá-la dentro de componentes que permitem múltipla seleção (selectManyCheckBox, por exemplo), é gerado um ClassCastException, pois a classe do objeto resultante da expressão value do componente é do tipo List (ou Set, ou qualquer coleção que você esteja usando no seu value), e não do tipo da entidade.

Minha solução foi passar um atributo para o componente nesses casos, e alterar o converter para que, quando o atributo estiver presente, ele pegar a classe informada no atributo, ao invés de checar o tipo do value:

 <f:attribute name="classeParaEntityConverter" value="model.web.MinhaEntidade"/>

No converter:

	private Class<?> getClazz(FacesContext facesContext, UIComponent component) {
		String classeParaEntityConverter = (String) component.getAttributes().get("classeParaEntityConverter");
		
		if(classeParaEntityConverter == null ) {
			return component.getValueExpression("value").getType(facesContext.getELContext());	
		} else {
			try {
				return Class.forName(classeParaEntityConverter);
			} catch (ClassNotFoundException e) {
				throw new IllegalArgumentException("A classe '" + classeParaEntityConverter + "' passada como atributo do compoente não foi encontrada");
			}
		}
	}

Alguém topou com esse problema também e talvez possa postar uma solução mais inteligente?!

Abs!

Alguem achou a solução para componentes que permitem múltiplas seleções???
ou alguem pode indicar postando um exemplo de converter (genérico ou não) para componentes de multiplas seleções???

Que iniciativa boa, parabêns.

Porém aqui não consegui implementá-lo, alguém pode me ajudar?
Possuo uma classe Contato cujo um dos atributo é do tipo empresa. Ambos anotados com @Id. O salvamento ocorre sem problemas, mas com o converter não consigo mais editar um contato.

Erro: “Error Rendering View[/views/cadastros/contato/edit.xhtml]: javax.el.PropertyNotFoundException: /views/cadastros/contato/edit.xhtml @26,150 value=”#{contatoMB.contato.empresa.id}": Target Unreachable, ‘empresa’ returned null".

Como estou usando:

<h:selectOneMenu id="contatoCodEmpresa" value="#{contatoMB.contato.empresa.id}" required="true" requiredMessage="Codigo da empresa é obrigatório">
   <f:converter converterId="entityConverter"/>		
   <f:selectItems value="#{empresaMB.listarTodos}" var="empresa" itemLabel="#{empresa.nome}" itemValue="#{empresa.id}"/>			
</h:selectOneMenu>

EmpresaMB:

...
public List<Empresa> getListarTodos(){
	return empresaService.listarTodos();
}

ContatoMB:

@ManagedBean
@RequestScoped
public class ContatoMB {

	@EJB
	private ContatoService contatoService;
	
	@EJB
	private EmpresaService empresaService;
	
	private Contato contato;
	private Empresa empresa;
	private Long empresaId;
...

web.xml

  <welcome-file-list>
    <!--<welcome-file>/pages/protected/user/listAllDogs.xhtml</welcome-file>-->
    <welcome-file>/views/cadastros/contato/list.xhtml</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
    <url-pattern>*.jsf</url-pattern>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
  
      <context-param>  
      <param-name>facelets.BUILD_BEFORE_RESTORE</param-name>  
      <param-value>false</param-value>  
    </context-param>  

Estou usando em um projeto no padrão JEE. Deixei o converter no modulo web e anotei no web.xml. As outras classes estão no modulo ejb.
Alguma idéia?

Flavio,

Esse sua EntityConverter é muito bacana e me ajudou bastante aqui. So que eu precisei fazer uma pequena alteração no seu codigo para trabalhar com @viewscoped. segue a alteração.

public Object getAsObject(FacesContext context, UIComponent component, String value) {
		if (value != null) {
			Object objeto = JsfUtil.retornarObjetoSessao(value);
			JsfUtil.removerObjetoSessao(value);
			return objeto;
		}else{
			return null;
		}
	}

	public String getAsString(FacesContext context, UIComponent component, Object objeto) {
		try {
			if (objeto != null && !objeto.equals("")) {
				String id = getId(getClasse(context, component), objeto);
				if (id == null) {
					id = "";
				}
				
				JsfUtil.adicionarObjetoSessao(id.trim(), getClasse(context, component).cast(objeto));
				return id;
			}else{
				return null;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

vlw Flavio