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.
É 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.
}
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.
Para todos os jsons formatados você quer adicionar esse atributo? Cria um converter do XStream e anota ele com @Component e @ApplicationScoped…
Exatamente !.
Mas como fazer esse converter ? me desculpe a ignorância, mas pode me enviar um exemplo.
: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.
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
}
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);
}
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);
Valeu pela ajuda de vocês
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.