Erro ao obter collection com vRaptor2 a partir de formulário [RESOLVIDO]

9 respostas
eulen

Salve pessoal, temos um projeto legado aqui com vRaptor2. Infelizmente não há como migrar para o vRaptor3 agora. Tentei buscar documentação, mas não está mais disponível.
Tenho uma lista de notícias de onde queremos enviar uma newsletter, escolhendo apenas algumas.
No HTML estou inserindo um campo checkbox que será selecionado caso o usuário queira enviar esta notícia. Segue abaixo o html.

<form action="newsletter.enviar.tjac" method="post">
      <input type="submit" value="Enviar" style="width:100px;height:30px;"/> 
      <display:table id="noticiaa" name="${noticias}" requestURI="newsletter.formulario.tjac" pagesize="20" cellpadding="5" cellspacing="1" style="width:100%">
		<display:column title="CATEGORIA"> ${noticiaa.categoria.nome} </display:column>
		<display:column title="DATA" style="width:70px">
			<fmt:formatDate value="${noticiaa.data}" pattern="dd/MM/yyyy" />
		        <fmt:formatDate value="${noticiaa.data}" pattern="HH:mm" />
		</display:column>
		<display:column title="TÍTULO"> ${noticiaa.titulo} </display:column>
		<display:column title="USUÁRIO"> ${noticiaa.usuario.nome} </display:column>
						
	       <display:column title="ENVIAR"><input type="checkbox" name="noticias[${noticiaa.id}]"/></display:column>
       </display:table>
</form>

Entretanto no método enviar estou recebendo uma lista vazia.

@Logic(parameters={"noticias[]"})
public void enviar(List<Noticia> noticias){
      System.out.println("Tamanho: "+noticias.size());
      try {
          List<DestinatarioNewsletter> destinatarios = daoFactory.getNewsletterEmailDAO().listaTudo();
          for(DestinatarioNewsletter destinatario:destinatarios){
               MensagemNewsletter mensagem= new MensagemNewsletter(noticias,destinatario);
	       NewsletterSender sender = new NewsletterSender(mensagem);
   	       sender.enviar();
	   }
	} catch (AddressException e) {
		System.out.println("Erro com algum endereço de email");
		e.printStackTrace();
	} catch (UnsupportedEncodingException e) {
		System.out.println("Erro de enconding");
		e.printStackTrace();
	} catch (MessagingException e) {
		System.out.println("Erro na construção da mensagem");
		e.printStackTrace();
	}
}

Como disse o tamanho da lista está vindo 0. Tentei seguir exemplos que localizei aqui mesmo no forum e blogs na net, mas não está funcionando. Por favor quem souber a localização da documentação do vRaptor2 também seria de grande utilidade.

Obrigado pela atenção.

9 Respostas

Lucas_Cavalcanti

tenta trocar para @Logic(parameters={“noticias”})

eulen
Lucas Cavalcanti:
tenta trocar para @Logic(parameters={"noticias"})

Eu tentei desta forma Lucas, mas obtive um redirecionamento para a view enviar.invalid.jsp

HTTP Status 404 - /novosite/admin/newsletter/enviar.invalid.jsp

type Status report

message /novosite/admin/newsletter/enviar.invalid.jsp

description The requested resource (/novosite/admin/newsletter/enviar.invalid.jsp) is not available.

Aproveitando isto, posso utilizar vRaptor 2 e 3 ao mesmo tempo nesse projeto? Essa nova implementação seria feita com a V3 que já tenho alguma familiaridade.
Obrigado.

Lucas_Cavalcanti

é possível misturar os dois sim:

http://vraptor.caelum.com.br/documentacao/migrando-do-vraptor2-para-o-vraptor3/

talvez não funcione com a última versão do vraptor, mas pelo menos até o vraptor 3.2 funciona.

quanto ao invalid, será que não deu algum erro de conversão ou validação?

eulen

Lucas Cavalcanti:
é possível misturar os dois sim:

http://vraptor.caelum.com.br/documentacao/migrando-do-vraptor2-para-o-vraptor3/

talvez não funcione com a última versão do vraptor, mas pelo menos até o vraptor 3.2 funciona.

quanto ao invalid, será que não deu algum erro de conversão ou validação?

Lucas obrigado pela sua atenção, vejo que você é sempre prestativo a todos que pedem ajuda. Ainda não consegui resolver.

Crei uma classe DTO para receber o id e se a noticia foi selecionada

public class NewsletterDTO {
	private Long id;
	private boolean selecionado;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public boolean isSelecionado() {
		return selecionado;
	}
	public void setSelecionado(boolean selecionado) {
		this.selecionado = selecionado;
	}
}

No form inseri os campos:

<input type="checkbox" name="selecao[${noticiaa.id}].selecionado"/> <input type="hidden" name="selecao[${noticiaa.id}].id" value="${noticiaa.id}"/>

@Logic(parameters={"selecao"}) public void enviar(List<NewsletterDTO> selecao){ System.out.println("Tamanho: "+selecao.size()); }

Mas estou recebendo a seguinte exceção a partir do controller. Obviamente está relacionado ao índice do array.

25/04/2012 10:26:28 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet vraptor2 threw exception
org.vraptor.reflection.SettingException: Invalid array index - probably missed one object in between: 14338
	at org.vraptor.reflection.CollectionDealer.resizeAndSet(CollectionDealer.java:30)
	at org.vraptor.reflection.JPathExecutor.set(JPathExecutor.java:87)
	at org.vraptor.introspector.BasicIntrospector.readParameters(BasicIntrospector.java:81)
	at org.vraptor.interceptor.SettingAndValidationInterceptor.intercept(SettingAndValidationInterceptor.java:98)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.InjectionInterceptor.intercept(InjectionInterceptor.java:41)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.ComponentLookupInterceptor.intercept(ComponentLookupInterceptor.java:58)

Alguma sugestão?

eulen

Ufaaaa! Pessoal finalmente conseguí resolver. O problema era realmente o índice do array. Usei um objeto implicito da displayTag para obter o número da linha na tabela.

<display:column title="ENVIAR" >
    <input type="checkbox" name="selecao[${noticiaa_rowNum - 1}].id" value="${noticiaa.id}"/>
</display:column>
E no controller coloquei normalente a coleção. Agora sim está redondinho.
@Logic(parameters={"selecao"})
public void enviar(List<Noticia> selecao){
	List<Noticia> noticias=new ArrayList<Noticia>();
	for(Noticia n:selecao){
		noticias.add(daoFactory.getNoticiaDao().procura(n.getId()));
	}
	try {
		List<DestinatarioNewsletter> destinatarios = daoFactory.getNewsletterEmailDAO().listaTudo();
		for(DestinatarioNewsletter destinatario:destinatarios){
			MensagemNewsletter mensagem= new MensagemNewsletter(noticias,destinatario);
			NewsletterSender sender = new NewsletterSender(mensagem);
			sender.enviar();
		}
	} catch (AddressException e) {
		System.out.println("Erro com algum endereço de email");
		e.printStackTrace();
	} catch (UnsupportedEncodingException e) {
		System.out.println("Erro com enconding");
		e.printStackTrace();
	} catch (MessagingException e) {
		System.out.println("Erro na formação da mensagem");
		e.printStackTrace();
	}
		
}

Novamente o meu muito obrigado ao Lucas, sempre prestativo nas dúvidas do vRaptorm, excelente framework.

eulen

Pensei que o problema havia se resolvido, mas pelo visto só fiz mascará-lo. Quando o usuário seleciona as notícias em sequencia não ocorre erro algum, já que o vRaptor consegue popular corretamente a coleção. Entretanto se for selecionada uma noticia fora da sequencia, exemplo noticias 2, 7 e 8. Obtenho a seguinte exception:

org.vraptor.reflection.SettingException: Invalid array index - probably missed one object in between: 4
	at org.vraptor.reflection.CollectionDealer.resizeAndSet(CollectionDealer.java:30)
	at org.vraptor.reflection.JPathExecutor.set(JPathExecutor.java:87)
	at org.vraptor.introspector.BasicIntrospector.readParameters(BasicIntrospector.java:81)
	at org.vraptor.interceptor.SettingAndValidationInterceptor.intercept(SettingAndValidationInterceptor.java:98)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.InjectionInterceptor.intercept(InjectionInterceptor.java:41)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.ComponentLookupInterceptor.intercept(ComponentLookupInterceptor.java:58)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.MultipartRequestInterceptor.intercept(MultipartRequestInterceptor.java:41)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at br.jus.tjac.sitetj.logic.AutorizadorInterceptor.intercept(AutorizadorInterceptor.java:40)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at br.jus.tjac.sitetj.logic.DaoInterceptor.intercept(DaoInterceptor.java:18)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.FlashScopeInterceptor.intercept(FlashScopeInterceptor.java:22)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.RegisterAttributesInteceptor.intercept(RegisterAttributesInteceptor.java:38)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.core.VRaptorExecution.execute(VRaptorExecution.java:98)
	at org.vraptor.core.DefaultController.execute(DefaultController.java:46)
	at org.vraptor.VRaptorServlet.service(VRaptorServlet.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Unknown Source)

Analisando o código do método resizeAndSet percebi que ele realmente previne isso, obviamente se um array tem 3 elementos ele não pode ter um indice 7 ou 8.

Alguem pode me ajudar a implementar algum interceptor para resolver este problema?

Lucas_Cavalcanti

no vraptor 2 vc precisa obrigatoriamente mandar os índices começando do zero e sem pular nenhum… ou seja, não pode ter

objeto[0], objeto[1], objeto[3]

se não tiver o objeto[2] dá pau.

eulen

Lucas Cavalcanti:
no vraptor 2 vc precisa obrigatoriamente mandar os índices começando do zero e sem pular nenhum… ou seja, não pode ter

objeto[0], objeto[1], objeto[3]

se não tiver o objeto[2] dá pau.

Realmente é bem complicado trabalhar com uma versão descontinuada. Tentei ainda migrar o projeto, mas obtive várias exceções e erros no deploy.

A alternativa menos traumática, não se se foi a mais correta, foi adotar o uso de javascript para criar elementos dinâmicos no evento submit do formulário. Finalmente está funcionando. Este é um daqueles casos em que precisamos implementar um pouco de XGH.
Para quem estiver precisando de algo parecido e tiver alguma urgência para botar no ar, vai aqui minha solução.

Criei inicialmente o formulário vazio, apenas com um botão submit.

<form action="newsletter.enviar.tjac" method="post" id="form" style="display: none">
	<input type="submit" value="Enviar" /> 
</form>
<display:table id="noticiaa" name="${noticias}" requestURI="newsletter.formulario.tjac" pagesize="20" cellpadding="5" cellspacing="1" style="width:100%">
	<display:column title="CATEGORIA"> ${noticiaa.categoria.nome} </display:column>
	<display:column title="DATA" style="width:70px">
		<fmt:formatDate value="${noticiaa.data}" pattern="dd/MM/yyyy" />
		<fmt:formatDate value="${noticiaa.data}" pattern="HH:mm" />
	</display:column>
	<display:column title="TÍTULO"> ${noticiaa.titulo} </display:column>
	<display:column title="USUÁRIO"> ${noticiaa.usuario.nome} </display:column>
	<display:column title="ENVIAR" >
		<input type="checkbox" value="${noticiaa.id}"/>
	</display:column>
</display:table>

JS com ajuda do jQuery para selecionar apenas os elementos que estão marcados e definir no atributo name, o valor sequencial da lista, corrigindo assim o problema dos índices sobressaltados que geram a exceção no vRaptor

$(document).ready(function(){
	form=$('#form');
	form.submit(function(){
		var lista=$(':checked');
		$(lista).css('display','none');
		for(i=0;i<lista.length;i++){
			elemento=lista[i];
			elemento.setAttribute("name","selecao["+i+"].id");
			form.append(elemento);
		}
	});
});

No controller ficou como estava antes:

@Logic(parameters={"selecao"})
	public void enviar(List<Noticia> selecao){

Agora basta otimizar um pouco este código javaScript. Como disse não sei se é a melhor solução. O ideal seria que o vRaptor fizesse tudo pra mim, mas código legado é realmente muito complicado e não existe tempo pra migrar tudo pra versão 3.

Abraço a todos.

Lucas_Cavalcanti

uma das primeiras coisas que a gente fez no vraptor 3 é exatamente isso :wink:

Criado 24 de abril de 2012
Ultima resposta 27 de abr. de 2012
Respostas 9
Participantes 2