VRaptor + renderizando JSON igual o GSON

6 respostas
dondiego

Galera,

boa tarde! Seguinte, estou precisando renderizar um JSON usando VRaptor, mas a renderização em String tá cheia de nodes e alias indesejáveis.

Pesquisando com a equipe que trabalho, descobrimos que o VRaptor utiliza o motor JsonHierarchicalStreamDriver e XStream para renderização JSON. Primeira coisa, estamos corretos?

Nossa segunda dúvida é se há como integrar o GSon com o VRaptor reimplementando a classe XStreamJSONSerialization do VRaptor, não usando XStream mais, já que o GSon renderiza como precisamos.

Segue o nosso teste:

package br.com.mbs.hosting.test.json;

import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import br.com.mbs.hosting.service.AddressDTO;
import br.com.mbs.hosting.util.JSONResponse;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;

/**
 * Testing the JSON rendering with GSon and VRaptor.
 * 
 * @author Diego Martins, MBS Tecnologia - <a href="mailto:[email removido]">[email removido]</a>
 * @version 1.0
 * @date 25/05/2010 12:05:37
 */
public class JSONRenderComparision {

    /**
     * @param args
     */
    public static void main( String[] args ) {

        List&lt; AddressDTO &gt; pojosToRender = new ArrayList&lt; AddressDTO &gt;();

        pojosToRender.add( new AddressDTO( &quot;MG&quot;, &quot;Uberlandia&quot;, &quot;Brasil&quot;, 1L, 10L, &quot;Afonso Pena&quot;, &quot;38408-555&quot;, &quot;&quot;, &quot;&quot;, &quot;1000&quot;, null ) );
        pojosToRender.add( new AddressDTO( &quot;MG&quot;, &quot;Uberlandia&quot;, &quot;Centro&quot;, 1L, 10L, &quot;João Pinheiro&quot;, &quot;38409-555&quot;, &quot;&quot;, &quot;&quot;, &quot;2000&quot;, null ) );
        pojosToRender.add( new AddressDTO( &quot;MG&quot;, &quot;Uberaba&quot;, &quot;Centro&quot;, 5L, 85L, &quot;Graham Bell&quot;, &quot;38407-555&quot;, &quot;&quot;, &quot;&quot;, &quot;3000&quot;, null ) );

        // google
        Gson gsonRender = new Gson();
        System.out.println( &quot;Google JSON render: \n&quot; + gsonRender.toJson( pojosToRender ) );

        // vraptor
        XStream vraptorJSONRender = new XStream( new JsonHierarchicalStreamDriver() {

            public HierarchicalStreamWriter createWriter( Writer writer ) {

                return new JsonWriter( writer, JsonWriter.DROP_ROOT_MODE ) {
                    @Override
                    public void addAttribute(String key, String value) {
                        if(!&quot;class&quot;.equals(key)){
                            super.addAttribute(key, value);
                        }
                    }
                };
            }
        } );
        vraptorJSONRender.setMode( XStream.NO_REFERENCES );
        vraptorJSONRender.alias( &quot;root&quot;, AddressDTO.class );
        System.out.println( &quot;\n\nVRaptor JSON render: \n&quot; + vraptorJSONRender.toXML( pojosToRender ) );

        JSONResponse&lt; List&lt; AddressDTO &gt; &gt; testResponse = new JSONResponse&lt; List&lt; AddressDTO &gt; &gt;( &quot;teste1&quot;, pojosToRender );
        vraptorJSONRender = null;
        vraptorJSONRender = new XStream( new JsonHierarchicalStreamDriver() {

            public HierarchicalStreamWriter createWriter( Writer writer ) {

                return new JsonWriter( writer, JsonWriter.DROP_ROOT_MODE ) {
                    @Override
                    public void addAttribute(String key, String value) {
                        if(!&quot;class&quot;.equals(key)){
                            super.addAttribute(key, value);
                        }
                    }
                };
            }
        } );
        //vraptorJSONRender.alias( &quot;root&quot;, List.class );
        System.out.println( &quot;\n\nVRaptor JSONResponse (hosting) render: \n&quot; + vraptorJSONRender.toXML( testResponse ) );

        System.out.println( &quot;\n\nGoogle JSON (JSONResponse) render: \n&quot;
                + gsonRender.toJson( testResponse, new TypeToken&lt; JSONResponse&lt; List&lt; AddressDTO &gt; &gt; &gt;() {
                }.getType() ) );

    }
}

Sendo que JSONResponse é uma classe mais complexa para renderização de JSON. Segue abaixo:

package br.com.mbs.hosting.util;

public class JSONResponse&lt;T&gt; {

	private String message;
	private T data;

	public JSONResponse(String message, T data) {
		this.message = message;
		this.data = data;
	}

	public String getMessage() {
		return message;
	}

	public T getData() {
		return data;
	}

}

E a classe AddressDTO é um pojo com campos para representação de endereço. Segue:

package br.com.mbs.hosting.service;

import java.io.Serializable;

/**
 * DTO for the Address entity. Copy from middleware-sin.
 * 
 * @author Diego Martins, MBS Tecnologia - <a href="mailto:[email removido]">[email removido]</a>
 * @version 1.0
 * @date 20/05/2010 15:26:05
 */
public class AddressDTO implements Serializable {

    private static final long serialVersionUID = -1438246671646795240L;

    private Long id;

    private Long idUf;

    private Long idCity;

    private Long idNeighborhood;

    private Long idType;

    private Long idTitle;

    private String uf;

    private String descUf;

    private String city;

    private String neighborhood = "";

    private String type;

    private String title;

    private String address = "";

    private String cep;

    private Long idAddress;

    private String addressComplementType;

    private String addressComplement;

    private String number;

    private String typeDescription;

    private String streetType;

    public AddressDTO() {
    }

    public AddressDTO( String uf, String city, String neighborhood, Long idType, Long idTitle, String address, String cep,
            String addressComplementType, String addressComplement, String number, StreetTypeDTO streetType ) {

        super();

        this.uf = uf;

        this.city = city;

        this.neighborhood = neighborhood;

        this.idType = idType;

        this.idTitle = idTitle;

        this.address = address;

        this.cep = cep;

        this.addressComplementType = addressComplementType;

        this.addressComplement = addressComplement;

        this.number = number;

        this.streetType = streetType;

    }

    // getters and setters.
}

O retorno do teste é:

Google JSON render: [{"idType":1,"idTitle":10,"uf":"MG","city":"Uberlandia","neighborhood":"Brasil","address":"Afonso Pena","cep":"38408-555","addressComplementType":"","addressComplement":"","number":"1000"},{"idType":1,"idTitle":10,"uf":"MG","city":"Uberlandia","neighborhood":"Centro","address":"João Pinheiro","cep":"38409-555","addressComplementType":"","addressComplement":"","number":"2000"},{"idType":5,"idTitle":85,"uf":"MG","city":"Uberaba","neighborhood":"Centro","address":"Graham Bell","cep":"38407-555","addressComplementType":"","addressComplement":"","number":"3000"}]

VRaptor JSON render:
[
{
"idType": 1,
"idTitle": 10,
"uf": "MG",
"city": "Uberlandia",
"neighborhood": "Brasil",
"address": "Afonso Pena",
"cep": "38408-555",
"addressComplementType": "",
"addressComplement": "",
"number": "1000"
},
{
"idType": 1,
"idTitle": 10,
"uf": "MG",
"city": "Uberlandia",
"neighborhood": "Centro",
"address": "João Pinheiro",
"cep": "38409-555",
"addressComplementType": "",
"addressComplement": "",
"number": "2000"
},
{
"idType": 5,
"idTitle": 85,
"uf": "MG",
"city": "Uberaba",
"neighborhood": "Centro",
"address": "Graham Bell",
"cep": "38407-555",
"addressComplementType": "",
"addressComplement": "",
"number": "3000"
}
]

VRaptor JSONResponse (hosting) render:
{
"message": "teste1",
"data": {
"br.com.azzu.hosting.service.AddressDTO": {
"idType": 1,
"idTitle": 10,
"uf": "MG",
"city": "Uberlandia",
"neighborhood": "Brasil",
"address": "Afonso Pena",
"cep": "38408-555",
"addressComplementType": "",
"addressComplement": "",
"number": "1000"
},
"br.com.azzu.hosting.service.AddressDTO": {
"idType": 1,
"idTitle": 10,
"uf": "MG",
"city": "Uberlandia",
"neighborhood": "Centro",
"address": "João Pinheiro",
"cep": "38409-555",
"addressComplementType": "",
"addressComplement": "",
"number": "2000"
},
"br.com.azzu.hosting.service.AddressDTO": {
"idType": 5,
"idTitle": 85,
"uf": "MG",
"city": "Uberaba",
"neighborhood": "Centro",
"address": "Graham Bell",
"cep": "38407-555",
"addressComplementType": "",
"addressComplement": "",
"number": "3000"
}
}
}

Google JSON (JSONResponse) render:
{"message":"teste1","data":[{"idType":1,"idTitle":10,"uf":"MG","city":"Uberlandia","neighborhood":"Brasil","address":"Afonso Pena","cep":"38408-555","addressComplementType":"","addressComplement":"","number":"1000"},{"idType":1,"idTitle":10,"uf":"MG","city":"Uberlandia","neighborhood":"Centro","address":"João Pinheiro","cep":"38409-555","addressComplementType":"","addressComplement":"","number":"2000"},{"idType":5,"idTitle":85,"uf":"MG","city":"Uberaba","neighborhood":"Centro","address":"Graham Bell","cep":"38407-555","addressComplementType":"","addressComplement":"","number":"3000"}]}

Alguma idéia de como deixar a renderização do JSON do VRaptor igual a do GSon, mesmo que seja alterando métodos e parâmetros para os Writer, já olhamos as documentações existentes e chegamos num beco sem saída.

Ou senão há como integrar o GSon no VRaptor ou invés de usar o XStream?

Abraços e agradeço por atencedência.

6 Respostas

G

Sim, você está certo. Vraptor usa XStream como backend para gerar XML/JSON.

Qualquer componente no Vraptor pode ser substituido bastando extendê-lo ou implementado. Conforme o Lavieri postou nesse tópico você pode sobrescrever os seguintes componentes:

XStreamJSONSerialization para Json
XStreamXMLSerialization para xml
XStreamXMLDeserializer para deserializar xml

Lucas_Cavalcanti

a única diferença entre o do VRaptor e o do GSON são os espaços… eh isso mesmo?

o do vraptor com result.use(json()).withoutRoot().from(objeto) já faz mais ou menos o que vc implementou…

qto a fazer a implementação baseada em GSon, crie a(s) seguinte(s) classe(s):

@Component
public class GSonJSONSerialization implements JSONSerialization {

    public <T> Serializer from(T object) {
         return new GSonSerializer(object); //ou algo parecido
    }
}

public class GSonSerializer implements Serializer {
    // implementação dos métodos, baseando-se no GSon
}

tanto Serialization quanto Serializer são de br.com.caelum.vraptor.serialization

se vc quiser/puder fazer essa implementação e precisar de ajuda é só falar, e se quiser disponibilizar pra todo mundo, a gente pode incluir no vraptor =)

[]'s

i99mhz

Opa, fiz uma implementação para serializar usando a API do Gson

package br.com.seudominio.vraptor.serialization;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.serialization.JSONSerialization;
import br.com.caelum.vraptor.serialization.NoRootSerialization;
import br.com.caelum.vraptor.serialization.Serializer;
import br.com.caelum.vraptor.view.ResultException;

import com.google.gson.Gson;

@Component
public class GsonSerialization implements JSONSerialization {

	private final HttpServletResponse response;

	public GsonSerialization(HttpServletResponse response) {
		this.response = response;
	}

	@Override
	public boolean accepts(String format) {
		return "json".equals(format);
	}

	@Override
	public <T> Serializer from(T object) {
		response.setContentType("application/json");
		return serializeWidthGsonAPI(object);
	}

	@Override
	public <T> Serializer from(T object, String alias) {
		return from(object);
	}

	@Override
	public <T> NoRootSerialization withoutRoot() {
		return this;
	}

	private <T> Serializer serializeWidthGsonAPI(final T object) {
		return new Serializer() {

			@Override
			public void serialize() {
				try {
					response.getWriter().write(new Gson().toJson(object));
				} catch (IOException e) {
					throw new ResultException("Unable to serialize data width Gson API", e);
				}
			}

			@Override
			public Serializer recursive() {
				return this;
			}

			@Override
			public Serializer include(String... arg0) {
				return this;
			}

			@Override
			public Serializer exclude(String... arg0) {
				return this;
			}
		};

	}

}

Ficou legal. :slight_smile:

dondiego

Galera,

valeu pelas dicas. O i99mhz que implementou acima é meu chefe. Quem dera eu pudesse ter visto o post do Lucas antes do que ele. :smiley:

Abraços.

Lucas_Cavalcanti

criei uma issue no vraptor pra incluir esse seu código (com os devidos créditos, claro)

Obrigado =)

G

E com essas iniciativas o vraptor vai ficando cada vez melhor. :thumbup:

Criado 25 de maio de 2010
Ultima resposta 26 de mai. de 2010
Respostas 6
Participantes 4