Boa tarde,
Tentei e pesquisei muito antes de estar aqui novamente trazendo mais problemas mas… não consegui mesmo.
Estou tentando popular um h:selectOneMenu com objetos do meu projeto. Para tal estou utilizando um conversor genérico que foi modificado e publicado por um membro aqui do GUJ, o Sr. Flavio Almeida.
Consigo popular normalmente, mas quando seleciono e submeto página, aparece o erro:
Erro de validação: o valor não é válido
Meus métodos equals e hashCode estão sobrescritos (gerado automaticamente pelo eclipse).
Códigos:
View:
<h:selectOneMenu value="#{bean.pessoaSelecionada}" converter="entityConverter">
<f:selectItems value="#{bean.pessoas}" var="pessoa"
itemLabel="#{pessoa.nome}" itemValue="#{pessoa}" />
</h:selectOneMenu>
Bean:
[code]
…
private Pessoa pessoaSelecionada;
private List pessoas;
…
// populando a list
PessoaDao pesDao = new PessoaDao();
List lista = (List) pesDao.getAll();
pessoas = new ArrayList();
pessoas.add(new SelectItem(null, “”));
for (Pessoa pessoa : lista) {
pessoas.add(new SelectItem(pessoa, pessoa.getNome()));
}[/code]
Alguém tem alguma sugestão?
Obrigado!
Bom, não deve fazer diferença, mas vc usando uma lista de SelectItem, vc não precisa definir o var, o itemValue e o itemLabel no seu componente no seu XHTML. Basta ter a referência para a lista.
Cola aqui o código do converter que o Flávio fez.
[quote=Arthur F. Ferreira]Bom, não deve fazer diferença, mas vc usando uma lista de SelectItem, vc não precisa definir o var, o itemValue e o itemLabel no seu componente no seu XHTML. Basta ter a referência para a lista.
Cola aqui o código do converter que o Flávio fez.[/quote]
Obrigado por responder Arthur.
Removi o que me passou, mas obtive o mesmo resultado.
Segue o converter:
package utils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
/**
* Converter para entidades JPA. Baseia-se nas anotações @Id e @EmbeddedId para
* identificar o atributo que representa a identidade da entidade. Capaz de
* detectar as anotações nas classes superiores.
*
* @author Flávio Henrique
* @version 1.0.3
* @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;
}
/**
* Obtém, via expression language, a classe do objeto.
*
* @param FacesContext
* facesContext
*
* @param UICompoment
* compoment
*
* @return Class<?>
*/
private Class<?> getClazz(FacesContext facesContext, UIComponent component) {
return component.getValueExpression("value").getType(
facesContext.getELContext());
}
/**
* Retorna a representação em String do retorno do método anotado com @Id ou @EmbeddedId
* do objeto.
*
* @param Class
* <?> clazz
*
* @return String
*/
public String getId(Class<?> clazz, Object obj) throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
List<Class<?>> hierarquiaDeClasses = this.getHierarquiaDeClasses(clazz);
for (Class<?> classeDaHierarquia : hierarquiaDeClasses) {
for (Field field : classeDaHierarquia.getDeclaredFields()) {
if ((field.getAnnotation(Id.class)) != null
|| field.getAnnotation(EmbeddedId.class) != null) {
Field privateField = classeDaHierarquia
.getDeclaredField(field.getName());
privateField.setAccessible(true);
if (privateField.get(clazz.cast(obj)) != null) {
return (String) field.getType()
.cast(privateField.get(clazz.cast(obj)))
.toString();
}
}
}
}
return null;
}
/**
* Retorna uma lista com a hierarquia de classes, sem considerar a classe
* Object.class
*
* @param Class
* <?> clazz
*
* @return List<Class<?>> clazz
*/
public List<Class<?>> getHierarquiaDeClasses(Class<?> clazz) {
List<Class<?>> hierarquiaDeClasses = new ArrayList<Class<?>>();
Class<?> classeNaHierarquia = clazz;
while (classeNaHierarquia != Object.class) {
hierarquiaDeClasses.add(classeNaHierarquia);
classeNaHierarquia = classeNaHierarquia.getSuperclass();
}
return hierarquiaDeClasses;
}
}
Não olhei para ver o que esse código faz… mas… você olhou se o código do converter está sendo chamado?
Sim… já debuguei pra ver se estava sendo chamado… e está sim…
Sim… já debuguei pra ver se estava sendo chamado… e está sim…[/quote]E ele está retornando um valor válido?
Sim… já debuguei pra ver se estava sendo chamado… e está sim…[/quote]E ele está retornando um valor válido?[/quote]
Sim… debugando o método getAsString funciona normalmente, e também quando seleciondo (método getAsObject), o value retorna o ID do objeto selecionado sim:
public Object getAsObject(FacesContext ctx, UIComponent component,
String value) {
if (value != null) {
return component.getAttributes().get(value);
}
return null;
}
Mas o meu objeto Pessoa na Bean não recebe o objeto, e tenho esse retorno ai… =/
Esse seu bean Pessoa é uma entidade com anotações JPA? Mais especificamente com @Id ou @EmbeddedId? Pq esse converter para funcionar tem que ser uma entidade com essas anotações JPA.
Outra coisa: vc disse que ele retorna o ID corretamente, mas ele executa essa linha daqui sem erro?
return component.getAttributes().get(value);
[quote=Arthur F. Ferreira]Outra coisa: vc disse que ele retorna o ID corretamente, mas ele executa essa linha daqui sem erro?
return component.getAttributes().get(value);
[/quote]
O erro dá justamente neste return…
A entidade em questão foi um teste que fiz bem simples, pra excluir a possibilidade de ser alguma outra coisa “externa”, pra isto, criei essa entidade simples pra ver o que estava acontecendo:
[code]
…
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Index;
@Entity
public class Pessoa {
@Id
@GeneratedValue(generator = "gen_pessoa")
@GenericGenerator(name = "gen_pessoa", strategy = "increment")
@Column(name = "id", nullable = false)
private Integer id;
@Index(name = "idx_nome_pessoa")
@Column(name = "nome", nullable = false, unique = true, length = 100)
private String nome;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pessoa other = (Pessoa) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
/// Getters e Setters
…
}[/code]
Qual é o valor exato que vem no value?
E quando vc seleciona esse código (sem o return) e usa o CTRL+SHIFT+I, qual é a mensagem de erro detalhada que aparece para vc?
[quote=Arthur F. Ferreira]Qual é o valor exato que vem no value?
E quando vc seleciona esse código (sem o return) e usa o CTRL+SHIFT+I, qual é a mensagem de erro detalhada que aparece para vc?[/quote]
O Value vem o id da pessoa corretamente, já me certifiquei disso.
Não conhecia o CTRL+SHIFT+I… Já me ensinou mais uma =D
Resultado:
ID = NULL
NOME = NULL
É…já dá para ver que tem algo de errado e provavelmente é a maneira com que o EntityConverter faz para recuperar um registro.
O converter que eu uso é diferente. Eu sigo o exemplo do Rafael Ponte:
http://www.rponte.com.br/2008/07/26/entity-converters-pra-da-e-vender/
Hoje mesmo no trabalho um colega estava tendo problemas com o converter que usava. Ele usou a implementação do SimpleIndexConverter que é a mais simples e, no seu caso, acho que será a melhor.
[quote=Arthur F. Ferreira]É…já dá para ver que tem algo de errado e provavelmente é a maneira com que o EntityConverter faz para recuperar um registro.
O converter que eu uso é diferente. Eu sigo o exemplo do Rafael Ponte:
http://www.rponte.com.br/2008/07/26/entity-converters-pra-da-e-vender/
Hoje mesmo no trabalho um colega estava tendo problemas com o converter que usava. Ele usou a implementação do SimpleIndexConverter que é a mais simples e, no seu caso, acho que será a melhor.[/quote]
Maravilha Arthur! Utilizei o SimpleIndexConverter da mesma maneira que estava usando o EntityConverter e funcionou de primeira!
Muito obrigado pela prestatividade!
Um abraço…