Como popular lista imutavel com VRaptor?

20 respostas
renatoargh

Bom dia,

tenho a seguinte situacao; tenho uma classe chamada Contato que guarda por exemplo o atributo List enderecos
Porem ao inves de disponibilizar esta lista com um getter normal eu a disponibilizo de maneira imutavel, ou seja:

public List<Endereco> getEnderecos() {
    return Collections.unmodifiableList(enderecos);
}

e ao inves de setter eu tenho metodos como

public void adicionarEndereco(Endereco endereco) {
    ValidadorDeObject.eNulo(endereco, "Endereco a ser adicionado nao pode ser nulo");
		
    this.enderecos.add(endereco);
}

porem na minha tela quando tento popular usando VRaptor desta forma: eu recebo a seguinte execao:

java.lang.NullPointerException br.com.caelum.vraptor.http.ognl.ListNullHandler.getListType(ListNullHandler.java:75) br.com.caelum.vraptor.http.ognl.ReflectionBasedNullHandler.nullPropertyValue(ReflectionBasedNullHandler.java:70) ognl.ASTProperty.getValueBody(ASTProperty.java:118) ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ognl.SimpleNode.getValue(SimpleNode.java:236)

Na minha controladora estou recebendo um Contato contato,

PS.: Quando exibo a lista normalmente, de maneira mutavel tudo funciona perfeitamente.

Existe uma maneira re continuar trabalhando desta maneira??? Sem ter que expor a minha lista de maneira mutavel???
Obrigado!!!

20 Respostas

Lucas_Cavalcanti

tente mudar para usar o iogi.

adicione esse jar no projeto:
https://github.com/caelum/vraptor/tree/master/vraptor-core/lib/optional/iogi

e coloque o pacote do iogi no web.xml:

<context-param>
    <param-name>br.com.caelum.vraptor.packages</param-name>
    <param-value>br.com.caelum.vraptor.http.iogi</param-value>
</context-param>

se já tiver um packages, separe o value por vírgula

renatoargh

Oi Lucas, primeiramente obrigado, segundamente; o uso do IOGI altera alguma coisa nos meus converters??? Porque estou usando este codigo aqui:

@ApplicationScoped
@Convert(Pessoa.class) 
public class PessoaConverter implements Converter<Pessoa> {

	@Override
	public Pessoa convert(String valor, Class<? extends Pessoa> arg1, ResourceBundle arg2) {
		if("PessoaFisica".equals(valor))
			return new Fisica();
		
		if("PessoaJuridica".equals(valor))
			return new Juridica();
			
		throw new RuntimeException("Tipo nao pode ser diferente de PessoaFisica ou PessoaJuridica");
	}

}

E na verdade, a Pessoa tem um contato que tem a lista de enderecos.

Passei a ter a seguinte excecao:

Caused by: br.com.caelum.vraptor.VRaptorException: Unable to find converter for br.com.meupacote.dominio.Contato

O engracado e que Contato e uma classe concreta.

Lucas_Cavalcanti

tem algum parâmetro na requisição que termine num contato?

tipo:

<input name="blah.blah.contato" value="alguma coisa"/>
renatoargh

Nao, pior que nao. Existe alguma ordem especifica em que as configuracoes do web.xml devem ficar? Por exemplo, o meu esta assim:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>prv3</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
	<context-param>
    	<param-name>br.com.caelum.vraptor.packages</param-name>
    	<param-value>br.com.caelum.vraptor.http.iogi</param-value>
 	</context-param>
  
  <filter>
	<filter-name>vraptor</filter-name>
	<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
  </filter>
  <filter-mapping>
	<filter-name>vraptor</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>FORWARD</dispatcher>
	<dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  
  <listener>
   <listener-class>br.com.meupacote.utilitarios.InicializacaoEFinalizacaoDeContexto</listener-class>
  </listener>
</web-app>
Lucas_Cavalcanti

não… isso deveria funcionar…

vc consegue ver os parâmetros da requisição que deu o problema? (por ex usando o firebug, ou o developer tools do seu browser)

renatoargh

Cara, os parametros sao esses

?
pessoa=PessoaFisica&
pessoa.nome=Renato&
pessoa.dataDeNascimento=21%2F04%2F1987&
pessoa.registroNacional=[CPF removido]&
pessoa.registroEstadual=&
pessoa.ufDeRegistro=&
pessoa.inscricaoMunicipal=&
pessoa.observacoes=&

template_pessoa.contato.enderecos%5B%5D.cep=&
template_pessoa.contato.enderecos%5B%5D.logradouro=&
template_pessoa.contato.enderecos%5B%5D.bairro=&
template_pessoa.contato.enderecos%5B%5D.cidade=&
template_pessoa.contato.enderecos%5B%5D.municipio=&
template_pessoa.contato.enderecos%5B%5D.estado=&
template_pessoa.contato.enderecos%5B%5D.tipo=&

pessoa.contato.enderecos%5B%5D.cep=&
pessoa.contato.enderecos%5B%5D.logradouro=log&
pessoa.contato.enderecos%5B%5D.bairro=&
pessoa.contato.enderecos%5B%5D.cidade=cid&
pessoa.contato.enderecos%5B%5D.municipio=&
pessoa.contato.enderecos%5B%5D.estado=0&
pessoa.contato.enderecos%5B%5D.tipo=Comercial&

template_pessoa.contato.telefones%5B%5D.numero=&
template_pessoa.contato.telefones%5B%5D.tipo=&
template_pessoa.contato.emails%5B%5D.endereco=&

btnNovo=SALVAR&
btnNovo=SALVAR

Acabei de perceber que talvez os que comecam com "template_" possam estar causando problemas, vou verificar e posto amanha os resultados! Agradeco se tiver outra ideia que possa ajudar!!! EDIT: Mesmo removendo esses parametros (que estavam no request erradamente, nao funcionou)

Lucas_Cavalcanti

a diferença do iogi pro padrão é que ele tenta usar os construtores para popular os campos… então se tem algum construtor que recebe contato por exemplo, ele vai ver se consegue popular esse contato e passar direto no construtor… tem algo assim?

vc tá com a última versão do vraptor?

renatoargh

Olha, contato tem um construtor sem parametros e Pessoa tambem. Contato e um atributo de Pessoa. Eu fiz um converter para Pessoa, pois no controller tem um interface e o converter baseado no tipo instancia Fisica() ou Juridica(). Estou usando a versao 3.4, a ultima, certo?

Sera que o fato de ter m converter na jogada nao esta atrapalhando as coisas?

Lucas_Cavalcanti

habilita o log de debug do VRaptor pra poder saber qual é o parâmetro que ele tá tentando popular quando dá pau:

trocando o vraptor pra DEBUG, e colocando um br.com.caelum.iogi pra DEBUG tb.

renatoargh

Consegui setar o VRaptor para DEBUG, porem o IOGI eu nao sei como faz.
Apenas com o VRaptor em DEBUG nao chega a mostrar nenhum log entre a execucao do post pelo browser e a excecao no console.

Eu tentei inclusive receber na controladora da seguinte forma:

@Post("/cliente/novo") public void novo(Pessoa pessoa, Contato contato){ pessoa.setContato(contato); }

Dessa maneira a excecao parou porem o contato sempre vinha com nenhum email/endereco (que sao as entidades que estou tentando setar pelo IOGI), por mais que eu tivesse mudado na tela de pessoa.contato.emails[].valor para contato.emails[].valor - nao entendi, porque assim era para funcionar de qualquer jeito. Nao creio que haaj alguma limitacao em receber dois parametros na controladora certo? - embora esta solucao seja menos elegante neh

Lucas_Cavalcanti

popular qqer outro atributo de contato funciona?

renatoargh

Na verdade os outros atributos de Contato sao tambem listas imutaveis. Estava lendo um post seu sobre IOGI, que voce fala da classe Carro, e eu estou chegando a conclusao que o IOGI nao me atende nesse caso. Atenderia se eu precisasse instanciar a lista passando os parametros do request no construtor dela mas na verdade eu estou precisando chamar o metodo adicionarEndereco() {na verdade nem precisava chamar este metodo especifico apenas ir parar dentro da lista mutaveis que esta no atributo private List endereco}, ja que o getEnderecos retorna para o VRaptor uma lista imutavel que nao contem o metodo add.

renatoargh

Resolvido Lucas, eu que tava vacilando mesmo. Muito obrigado pelas respostas!!! Valeu mesmo!!!
O IOGI funcionou direitinho no fim das contas…

renatoargh

Lucas, me tira mais so mais uma duvida por favor...

para o IOGI funcionar perfeitamente eu precisei fazer este construtor:

public Contato(List<Endereco> enderecos, List<Email> emails, List<Telefone> telefones, List<Referencia> referencias){
		ValidadorDeObject.eNulo(enderecos, "Lista de enderecos nao pode ser nula");
		ValidadorDeList.contemNulo(enderecos, "Lista de enderecos contem objetos nulos");
		
		ValidadorDeObject.eNulo(emails, "Lista de emails nao pode ser nulo");
		ValidadorDeList.contemNulo(emails, "Lista de emails contem objetos nulos");
		
		ValidadorDeObject.eNulo(telefones, "Lista de telefones nao pode ser nula");
		ValidadorDeList.contemNulo(telefones, "Lista de telefones contem objetos nulos");
		
		ValidadorDeObject.eNulo(referencias, "Lista de referencias nao pode ser nula");
		ValidadorDeList.contemNulo(referencias, "Lista de referencias contem referencias nulas");
		
		this.enderecos = enderecos;
		this.telefones = telefones;
		this.referencias = referencias;
		this.emails = emails;
	}

Porem quando um dos objetos vem nulo ele nao instancia o objeto, existe alguma saida que nao seja escrever todas as combinacoes de construtores?

Lucas_Cavalcanti

não funciona se tiver o setter? achei que ele só setasse no final…

se vc coloca o construtor completo, precisa passar valores pra todas as listas… pelo menos do jeito que tá agora…

PS: Já deu uma olhada no Guava (que é dependência do VRaptor) pra fazer essas validações?
http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/base/Preconditions.html

renatoargh

Entendi!!! Talvez pudesse haver uma maneira, por exemplo, metodos setter privados (com uma anotacao especifica) para este tipo de caso, porque haverao ocasioes em que, no meu caso, o usuario vai informar 1 endereco e nenhum email, nenhum telefone e nenhuma referencia, ou seja, existem varias ocasioes e que para tratalas todas precisaria escrever todas as combinacoes possiveis de construtores somente para manter as listas imutaveis. Poderia ser por exemplo uma anotacao no parametro do contrutor, tipo “@AcceptNull” nao sei, apenas uma sugestao.

Sobre o guava, valeu pela sugestao vou dar uma analisadinha aqui!!! novamente valeu!!!

Lucas_Cavalcanti

a gente pode usar a anotação @Nullable, que nem o Guice:

não deve ser muito difícil de implementar no IOGI, o código dele está aqui:

vamos implementar? daí é só gerar um jar e vai funcionar normal no vraptor =)

renatoargh

Opa, legal, vou baixar o projeto aqui e dar uma olhada!!! Eu quero demais comecar a contribuir com projetos open source! Depois te mando uma mensagem, combinado!? Bacana que se o guice implementa e porque pode ser uma necessidade da galera que usa VRaptor mesmo, talvez mais cedo ou mais tarde alguem solicitasse essa feature!

Lucas_Cavalcanti

=D qqer coisa dá um toque =)

Lucas_Cavalcanti

O Rafael (dono do iogi) implementou a feature de poder receber lista vazia:

se quiser dar uma olhada

Criado 4 de abril de 2012
Ultima resposta 3 de mai. de 2012
Respostas 20
Participantes 2