Tenho duas classes Java que desejo serializar para JSON usando Jackson:
public class User {
public final int id;
public final String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
public class Item {
public final int id;
public final String itemNr;
public final User createdBy;
public Item(int id, String itemNr, User createdBy) {
this.id = id;
this.itemNr = itemNr;
this.createdBy = createdBy;
}
}
Quero serializar um item para este JSON:
{"id":7, "itemNr":"TEST", "createdBy":3}
com o usuário serializado para incluir apenas o id
. Também poderei serilizar todos os objetos de usuário para JSON como:
{"id":3, "name": "Jonas", "email": "[email protected]"}
Então, acho que preciso escrever um serializador personalizado Item
e tentei com isso:
public class ItemSerializer extends JsonSerializer<Item> {
@Override
public void serialize(Item value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.id);
jgen.writeNumberField("itemNr", value.itemNr);
jgen.writeNumberField("createdBy", value.user.id);
jgen.writeEndObject();
}
}
Eu serializo o JSON com este código de Jackson How-to: Custom Serializers :
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule",
new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Mas recebo este erro:
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
at com.example.JsonTest.main(JsonTest.java:54)
Como posso usar um serializador personalizado com Jackson?
É assim que eu faria com Gson:
public class UserAdapter implements JsonSerializer<User> {
@Override
public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.id);
}
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(User.class, new UserAdapter());
Gson gson = builder.create();
String json = gson.toJson(myItem);
System.out.println("JSON: "+json);
Mas preciso fazer isso com Jackson agora, já que Gson não tem suporte para interfaces.
java
json
serialization
jackson
Jonas
fonte
fonte
Item
? Estou tendo um problema em que meu método de controlador retorna um objeto serializado padrãoTypeA
, mas para outro método de controlador específico, quero serializá-lo de maneira diferente. Qual seria a aparência disso?Respostas:
Como mencionado, @JsonValue é uma boa maneira. Mas se você não se importa com um serializador personalizado, não há necessidade de escrever um para o Item, mas sim um para o Usuário - em caso afirmativo, seria tão simples como:
Ainda outra possibilidade é implementar
JsonSerializable
, caso em que nenhum registro é necessário.Quanto ao erro; isso é estranho - você provavelmente deseja atualizar para uma versão posterior. Mas também é mais seguro estender
org.codehaus.jackson.map.ser.SerializerBase
, pois terá implementações padrão de métodos não essenciais (ou seja, tudo, exceto a chamada de serialização real).fonte
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.JsonTest$UserSerilizer does not define valid handledType() (use alternative registration method?) at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62) at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54) at com.example.JsonTest.<init>(JsonTest.java:27) at com.exampple.JsonTest.main(JsonTest.java:102)
Você pode colocar
@JsonSerialize(using = CustomDateSerializer.class)
qualquer campo de data do objeto a ser serializado.fonte
@JsonSerialize(contentUsing= ...)
ao anotar Coleções (por exemplo@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)Eu tentei fazer isso também, e há um erro no código de exemplo na página da Web de Jackson que falha ao incluir o type (
.class
) na chamada doaddSerializer()
método, que deveria ser assim:Em outras palavras, estas são as linhas que instanciam o
simpleModule
e adicionam o serializador (com a linha incorreta anterior comentada):Para sua informação: aqui está a referência para o código de exemplo correto: http://wiki.fasterxml.com/JacksonFeatureModules
fonte
Use @JsonValue:
@JsonValue funciona apenas em métodos, portanto, você deve adicionar o método getId. Você deve ser capaz de ignorar o serializador personalizado completamente.
fonte
Escrevi um exemplo de
Timestamp.class
serialização / desserialização customizada , mas você pode usá-lo para o que quiser.Ao criar o mapeador de objetos, faça algo assim:
por exemplo,
java ee
você poderia inicializá-lo com este:onde o serializador deve ser algo assim:
e desserializador algo assim:
fonte
Esses são padrões de comportamento que observei ao tentar entender a serialização de Jackson.
1) Suponha que haja um objeto Sala de Aula e uma classe Aluno. Tornei tudo público e definitivo para facilitar.
2) Suponha que esses sejam os serializadores que usamos para serializar os objetos em JSON. O writeObjectField usa o próprio serializador do objeto se ele estiver registrado com o mapeador de objeto; caso contrário, ele o serializa como um POJO. O writeNumberField aceita exclusivamente primitivos como argumentos.
3) Registre apenas um DoubleSerializer com o padrão de saída DecimalFormat
###,##0.000
, em SimpleModule e a saída será:Você pode ver que a serialização POJO diferencia entre double e Double, usando o DoubleSerialzer para Doubles e usando um formato de String regular para doubles.
4) Registre DoubleSerializer e ClassroomSerializer, sem o StudentSerializer. Esperamos que a saída seja tal que, se escrevermos um duplo como um objeto, ele se comporte como um duplo, e se escrevermos um duplo como um número, ele se comportará como um duplo. A variável de instância Student deve ser escrita como um POJO e seguir o padrão acima, uma vez que não é registrada.
5) Registre todos os serializadores. O resultado é:
exatamente como esperado.
Outra observação importante: se você tiver vários serializadores para a mesma classe registrados com o mesmo Módulo, o Módulo selecionará o serializador para essa classe que foi adicionado mais recentemente à lista. Isso não deve ser usado - é confuso e não tenho certeza de quão consistente é
Moral: se você deseja personalizar a serialização de primitivas em seu objeto, deve escrever seu próprio serializador para o objeto. Você não pode confiar na serialização do POJO Jackson.
fonte
As visualizações JSON de Jackson podem ser uma maneira mais simples de atingir seus requisitos, especialmente se você tiver alguma flexibilidade em seu formato JSON.
Se
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
for uma representação aceitável, isso será muito fácil de conseguir com muito pouco código.Você apenas anota o campo de nome do usuário como sendo parte de uma visualização e especifica uma visualização diferente em sua solicitação de serialização (os campos não anotados seriam incluídos por padrão)
Por exemplo: Defina as visualizações:
Anote o usuário:
E serializar solicitando uma visualização que não contenha o campo que você deseja ocultar (campos não anotados são serializados por padrão):
fonte
createdBy
um valor em vez de um objeto?setSerializationView()
parece estar obsoleto, então useimapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
.No meu caso (Spring 3.2.4 e Jackson 2.3.1), configuração XML para serializador personalizado:
foi de forma inexplicável substituída de volta ao padrão por algo.
Isso funcionou para mim:
CustomObject.java
CustomObjectSerializer.java
Nenhuma configuração XML (
<mvc:message-converters>(...)</mvc:message-converters>
) é necessária em minha solução.fonte
Se o seu único requisito em seu serializador personalizado é ignorar a serialização do
name
campo deUser
, marque-o como temporário . Jackson não serializará ou desserializará campos transientes .[veja também: Por que o Java possui campos transitórios? ]
fonte
User
-classe? Mas vou serializar todos os objetos do usuário também. Por exemplo, primeiro apenas serializar todositems
(apenasuserId
como uma referência ao objeto de usuário) e, em seguida, serializar todosusers
. Neste caso, não posso marcar os campos naUser
classe -class.handledType()
método na documentação que vinculei e quando o Eclipse gera os métodos para implementar nãohandledType()
é gerado, então estou confuso.Você tem que substituir o método handledType e tudo funcionará
fonte
O problema no seu caso é que o ItemSerializer está sem o método handledType () que precisa ser substituído pelo JsonSerializer
Portanto, você está recebendo o erro explícito de que handledType () não está definido
Espero que ajude alguém. Obrigado por ler minha resposta.
fonte