VRaptor + json + ExtJS

Blza pessoal,
Estou tentando utilizar o ExtJS com json no VRaptor.
O json está sendo gerado corretamente, mas quando tento fazer a chamada no extjs o controller não é acionado.
Segue meu código:

Controller:

import java.util.GregorianCalendar;

import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.view.Results;
import br.com.k2studio.condominio.pojo.Contato;

@Resource
public class JsonController {

	private final Result result;
	
	public JsonController(Result result) {
		this.result = result;
	}
	
	@Path("/json")
	public void json() {
		Contato contato = new Contato("Maria","11-12345678","maria@provedor.com", new GregorianCalendar(1984, 02, 01).getTime());
		result.use(Results.json()).from(contato).serialize();
	}
	
}

A chamada que faço para teste é: localhost:8080/vraptor/json -> Assim ele chama o controller e faz o download do json

E assim faço no ExtJS:

        <script>
	Ext.onReady(function(){

		   //data store que le os dados vindos do json
		   //experimente substituir contatojson.jsp por contatos.json - tera o mesmo efeito
		    var store = new Ext.data.Store({
				proxy: new Ext.data.HttpProxy(
					new Ext.data.Connection({
						url:'/json'
					})
				),
				reader:new Ext.data.JsonReader({
					totalProperty:'total',
					root:'rows',
					fields: [
					          'nome',
					          'telefone',
					          'email',
					          {name: 'aniversario', type: 'date', dateFormat: 'd/m/Y'}           
					        ]
				})
			});


		    // cria o grid
		    var grid = new Ext.grid.GridPanel({
		        store: store,
		        columns: [
		            {header: "NOME", width: 170, sortable: true, dataIndex: 'nome'},
		            {header: "TELEFONE", width: 150, sortable: true, dataIndex: 'telefone'},
		            {header: "EMAIL", width: 150, sortable: true, dataIndex: 'email'},
		            {header: "DATA NASC.", width: 100, sortable: true, dataIndex: 'aniversario',
		            	renderer: Ext.util.Format.dateRenderer('d/m/Y')}
		        ],
		        title: 'Grid com Json - Extjs',
		        height:230,
		        width:590,
				renderTo: document.body,
				frame:true
		    });
		    
		   //le os dados
		    store.load();

		    //div do grid
		    grid.render('grid-json');
		});
	
	</script>

Só que desse forma não funciona…ele rederiza o grid sem os dados.
Acredito que seja alguma coisa com a URL, pois se estivesse correta, o controller seria acionado.

Alguém tem uma dica?

Vlww

[]'s

Daniel

Eu já fiz esses testes com a grid do EXT + VRaptor, verifique algumas coisas:

1- O JSON gerado é exatamente igual ao do exemplo da grid adaptado aos seus campos?

O Problema não esta na url, de acordo com que vc disse se colcar a url no browser ele faz o download do JSON, compare com o do exemplo

É alguma configuração no EXT que está errada, mode palpite.

Mas se fosse o problema dos campos, ele teria que ao menos passar pelo método json() do controller.
Como isso não está acontecendo, eu ainda acredito que seja a chamada da URL.

Essa chamada ali é feita na pág index.jsp que vem no vraptor-blank-project.
Já testei também passando a URL completa (url:‘http://localhost:8080/vraptor/json’) e também não deu certo.

Faça o seguinte teste, jogue o conteudo JSON em um arquivo txt a passe o caminho do arquivo na url e veja o que acontece.

Pelo o que me lembro vc precisa passar a url completa sim, vc chegou a baixar os demos?

Se sim, olhe como ele passa a url na grid, é um caminho completo http://site/xpto.php?acao=xx algo assim.

Meu palpite é aqui:

var store = new Ext.data.Store({   
          proxy: new Ext.data.HttpProxy(   
                new Ext.data.Connection({   
                url:'/json'   
          })   
),  

Vc deve usar outra propriedade para funcionar

Se seu contexto é /vraptor, essa chamada está errada

var store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy( new Ext.data.Connection({ url:'/json' }) ),

O correto deveria ser /vraptor/json

Opa, consegui fazer entrar no controller.
Mas agora aconteceu o que o Pedrosa comentou.
O padrão que o VRaptor gera é diferente do padrão do ExtJS.

Esse é o padrão que o Grid aceita:

{total:1,
 rows:[
        {"telefone":"11-12345678","email":"maria@provedor.com","nome":"Maria","aniversario":"01/03/1984"}
        ]
}

E é assim que o Vraptor está gerando:

{"contato": {
  "nome": "Pedro",
  "telefone": "12-55698745",
  "email": "pedro@provedor.com",
  "aniversario": {"1983-05-12 00:00:00.0 GMT-03:00"}
}}

Tem como mudar isso?

Vlww

acho que no extjs dá pra mudar o formato de entrada, é o jeito mais fácil…

no vraptor ainda é um pouco difícil personalizar nesse nível o json, mas se vc conhece o XStream fica mais fácil…

outra opção é vc gerar o json num jsp:

url: /contato/mostra?_format=json
jsp: /WEB-INF/contato/mostra.json.jsp

e vc gera usando as ferramentas do jsp…

Se o ExtJS sempre exige total e rows pra facilitar, voce pode criar um wrapper:

class ExtWrapper {
   private int total;
   private List<?> rows;
   public ExtWrapper(List<?> rows) {
    this.rows = rows;
    this.total = rows.size();
  }
}

Ai voce mudaria seu metodo do controller para:

    
     @Path("/json")  
     public void json() {  
         Contato contato = new Contato("Maria","11-12345678","maria@provedor.com", new GregorianCalendar(1984, 02, 01).getTime());  
         ExtWrapper ext = new ExtWrapper(Arrays.asList(contato));
         result.use(Results.json()).from(ext).serialize();  
     }  
       

Pronto! So isso, sem precisar mudar nada no extjs. (ficaria mais elegante sem rpecisar do wrapper, com certeza). Da ainda pra criar um construtor no ExtWrapper que receba Object e faca o Arrays.asList(), poupando trabalho no caso de devolver apenas um unico objeto.

Melhor ainda! Da para encapsular isso que eu fiz do ExtWrapper de tal forma a fazer que o use() receba um ExtRenderer() e que delegassse pro JSON apos fazer o wrap. Ai o Lucas sabe bem melhor que eu.

seguindo essa sugestão do Paulo, crie as classes:

import static br.com.caelum.vraptor.view.Results.*;
@Component
public class ExtJSRenderer implements View {
     public ExtJSRenderer(Result result) {
         this.result = result;
     }
     public static class ExtWrapper {  
        private int total;  
        private List<?> rows;  
        public ExtWrapper(Object... objects) {  
            this.rows = new ArrayList(Arrays.asList(objects)); 
            this.total = objects.length;
        }  
     }  
     public Serializer from(Object... objects) {
          return this.result.use(json()).from(new ExtJSWrapper(objects));
     }
     //para fazer import statico
     public static Class<ExtJSRenderer> extJs() {
          return ExtJSRenderer.class;
     }
}

No seu controller é só usar:

import static ....ExtJSRenderer.*;
@Resource
public class MeuController {
    public void geraOJSonDoExtJS() {
        result.use(extJs()).from(contato).serialize();
    }
}

mais nesse caso não funcionaria em uma grid certo?

se eu passar uma list para ser transformado em json não daria certo estou correto?

acho que funciona sim… a versão mais nova do VRaptor já vem com uma ExtJSView pronta, no formato que o extjs espera

a 3.4? ou a 3.3???

3.3