VRaptor3 json personalizado

9 respostas
joander.vieira

Bom Dia galera,

Estou utilizando o serialize json do VRaptor da seguinte forma:

result.use(json())
          .from(minhaLista)
	  .serialize();

Tem como eu personalizar esse json serializer para fazer assim?:

result.use(json())
          .from(minhaLista)
          .msg("Mensagem de retorno")
          .total(10)
	  .serialize();

O objetivo é mandar outros atributos junto com o json, neste caso o msg e o total.

9 Respostas

Rafael_Guerreiro

É só você criar uma classe que recebe a lista, a mensagem e o total:

public class ListJsonWrapper {
   private List<?> list;
   private String msg;
   private double total;

   public ListJsonWrapper(List<?> list; String msg, double total){
      // Passe para os atributos.
   }

   // Não há necessidade de getters e setters.
}
joander.vieira

Então, mas o que eu não quero é ter que criar uma classe dessa para cada tipo de objeto.
Tentei fazer uma classe dessa genérica mas não deu muito certo:
http://www.guj.com.br/java/264321-vraptor-34—json—serializando-lista-generic#1382992

Por isso eu queria personalizar o serializer json do VRaptor.

Rafael_Guerreiro

Para todos os jsons formatados você quer adicionar esse atributo? Cria um converter do XStream e anota ele com @Component e @ApplicationScoped

joander.vieira

Exatamente !.

Mas como fazer esse converter ? me desculpe a ignorância, mas pode me enviar um exemplo.

Rafael_Guerreiro

:oops:
Não vai funcionar com converter, pois você precisa passar essas informações de algum jeito. Acho que a forma mais fácil de fazer isso é vc criando as seguintes classes:

public class Message {
   private String msg;
   private double total;

  // Construtor e essas coisas
}

public class JsonWrapper extends Message {
   private Object obj;

  // Construtor e essas coisas
}

Assim toda vez que você for mandar qualquer, vc usa o JsonWrapper. De alguma forma você tem que passar esses valores. Crie um Wrapper mais específico caso vc precise.

Eu uso esses wrappers, eles funcionam como converters também, assim eu consigo selecionar quais atributos de determinado objeto eu quero que vá para a requisição.

joander.vieira

Mas se eu usar com uma lista genérica não funciona os includes e excludes, ja tentei.

public class Message {  
   private String msg;  
   private double total;  
  
  // Construtor e essas coisas  
}  
  
public class JsonWrapper extends Message {  
   private List<Object> minhaLista;  
  
  // Construtor e essas coisas  
}
Rafael_Guerreiro

Ai você usa o recursive().

Faça algo assim (exemplo real meu):

public interface DataTables {
	public List<String> toListString(ResourceBundle bundle);
}

public class User implements DataTables {
   // Atributos
	// aqui eu só transformo o que eu quero.
	@Override
	public List<String> toListString(ResourceBundle bundle) {
		List<String> list = new ArrayList<String>();

		list.add(id.toString());
		list.add(name);
		list.add(bundle.getString(status.getLabel()));

		return list;
	}
}
public class DataTablesResult {

	@SuppressWarnings("unused")
	private String sEcho;
	private List<List><String>> aaData = new ArrayList<List><String>>();
	private long iTotalRecords = 0;
	private long iTotalDisplayRecords = 0;

	public DataTablesResult(ResourceBundle bundle, String sEcho,
			List<DataTables> list, long iTotalRecords, long iTotalDisplayRecords) {
		this.sEcho = sEcho;
		this.setAaData(list, bundle);
		this.setiTotalRecords(iTotalRecords);
		this.setiTotalDisplayRecords(iTotalDisplayRecords);
	}

	@Override
	public String toString() {
		return "{'iTotalRecords':" + iTotalRecords
				+ ", 'iTotalDisplayRecords':" + iTotalDisplayRecords
				+ ", 'aaData':" + aaData.toString() + "}";
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;

		return this.hashCode() == obj.hashCode();
	}

	@Override
	public int hashCode() {
		return this.toString().hashCode();
	}

	private void setAaData(List<DataTables> list, ResourceBundle bundle) {
		if (list == null)
			list = new ArrayList<DataTables>();

		for (DataTables item : list)
			this.aaData.add(item.toListString(bundle));
	}

	private void setiTotalRecords(long iTotalRecords) {
		if (iTotalRecords > 0)
			this.iTotalRecords = iTotalRecords;
	}

	private void setiTotalDisplayRecords(long iTotalDisplayRecords) {
		if (iTotalDisplayRecords > 0)
			this.iTotalDisplayRecords = iTotalDisplayRecords;
	}
}
// Uso dessa forma:
@Get("/data/tables/{strategy}")
	public void list(DataTablesCriteriaBuilder strategy, List<DataTablesFilter> filters, String sEcho,
			int iDisplayStart, int iDisplayLength, List<Sort> sorts) {
		try {
			if (strategy == null)
				throw new IllegalArgumentException(
						"The strategy cannot be null.");

			DataTablesResult dataTablesResult = this.buildResult(strategy,
					filters, sEcho, iDisplayStart, iDisplayLength, sorts);

			this.result.use(Results.json()).withoutRoot()
					.from(dataTablesResult).recursive().serialize();
		} catch (Exception e) {
			this.logger.error("Unable to list this data tables.", e);
			this.result.use(Results.status()).badRequest(
					"Unable to list this data tables.");
		}
	}

	private DataTablesResult buildResult(DataTablesCriteriaBuilder strategy,
			List<DataTablesFilter> filters, String sEcho, int iDisplayStart,
			int iDisplayLength, List<Sort> sorts) {

		long iTotalRecords = dao.count(strategy);
		long iTotalDisplayRecords = dao.count(filters, strategy);
		List<DataTables> list = dao.list(filters, iDisplayStart,
				iDisplayLength, sorts, strategy);

		return new DataTablesResult(bundle, sEcho, list, iTotalRecords,
				iTotalDisplayRecords);
	}
Lucas_Cavalcanti

o jeito mais fácil de adicionar propriedades no json é criando uma classe wrapper mesmo… o xstream não te deixa fazer isso de um jeito fácil…

vc sempre pode usar uma biblioteca tipo Gson ou Jackson para gerar um JSON arbitrário, e escrever direto no response com:

result.use(Results.http()).body(oJson);
joander.vieira

Valeu pela ajuda de vocês :slight_smile: só para deixar registrado segue a minha implementação com o Google GSON que funcionou muito bem.

public class AtributosExtraJson {

    public int total;

    public String msg;

    public boolean success;
    ...
}
public class JsonReturn<T> extends AtributosExtraJson {

    private List<T> elementos;
    ...
public interface IJsonUtil<T> {

    public String toJson(JsonReturn<T> jsonReturn);

}
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

import org.joda.time.DateTime;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class JsonUtilImpl<T> implements IJsonUtil<T> {

    @Override
    public String toJson(JsonReturn<T> jsonReturn) {

        //codigo opcional. Aqui estou definindo para nao serializar atributos com modificadores transiente e para serializar atributos nulos
	GsonBuilder gsonBuilder = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).serializeNulls();
        //codigo opcional. Aqui estou definindo um conversor para data no formato JodaTime.
	gsonBuilder.registerTypeAdapter(DateTime.class, new ConvertJodaTimeToJson());

         
       // utilizar este codigo se tiver problema com referencia circular. Necessario incluir a classe GraphAdapterBuilder manualmente, ela nao vem o o Gson.
        //new GraphAdapterBuilder().addType(Usuario.class).registerOn(gsonBuilder);

	Gson gson = gsonBuilder.create();
	return gson.toJson(jsonReturn);
    }
     
    // Converter e formatar data no formato JodaTime para json
    private class ConvertJodaTimeToJson implements JsonSerializer<DateTime> {
	@Override
	public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
	    return new JsonPrimitive(src.toString("dd/MM/yy"));
	}
    }
}
JsonReturn<Pessoa> jsonReturn = new JsonReturn<Pessoa>();
	jsonReturn.setElementos(minhaListaDePessoa);
	jsonReturn.setMsg("Carregado com sucesso!.");
	jsonReturn.setSuccess(true);
	jsonReturn.setTotal(10);

	IJsonUtil<Pessoa> jsonUtil = new JsonUtilImpl<Pessoa>();

	response.setHeader("Content-Type", "application/json");
	result.use(Results.http()).body(jsonUtil.toJson(jsonReturn));

Qualquer dúvida estou a disposição.

Criado 25 de janeiro de 2013
Ultima resposta 26 de jan. de 2013
Respostas 9
Participantes 3