Tengo dos clases de Java que quiero serializar a 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;
}
}
Quiero serializar un artículo en este JSON:
{"id":7, "itemNr":"TEST", "createdBy":3}
con User serializado para incluir solo el id
. También podré serilizar todos los objetos de usuario a JSON como:
{"id":3, "name": "Jonas", "email": "[email protected]"}
Así que supongo que necesito escribir un serializador personalizado Item
y probé con esto:
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();
}
}
Serializo el JSON con 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();
}
Pero me sale este error:
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)
¿Cómo puedo usar un serializador personalizado con Jackson?
Así es como lo haría con 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);
Pero necesito hacerlo con Jackson ahora, ya que Gson no tiene soporte para interfaces.
java
json
serialization
jackson
Jonas
fuente
fuente
Item
? Tengo un problema en el que mi método de controlador devuelve un objeto serializado estándarTypeA
, pero para otro método de controlador específico, quiero serializarlo de manera diferente. Como se veria eso?Respuestas:
Como se mencionó, @JsonValue es una buena manera. Pero si no le importa un serializador personalizado, no es necesario escribir uno para el elemento, sino uno para el usuario; si es así, sería tan simple como:
Otra posibilidad más es implementar
JsonSerializable
, en cuyo caso no es necesario registrarse.En cuanto al error; eso es extraño, probablemente quieras actualizar a una versión posterior. Pero también es más seguro extenderlo,
org.codehaus.jackson.map.ser.SerializerBase
ya que tendrá implementaciones estándar de métodos no esenciales (es decir, todo menos la llamada de serialización real).fuente
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)
Puede colocar
@JsonSerialize(using = CustomDateSerializer.class)
cualquier campo de fecha del objeto a serializar.fuente
@JsonSerialize(contentUsing= ...)
al anotar colecciones (por ejemplo@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)Intenté hacer esto también, y hay un error en el código de ejemplo en la página web de Jackson que no incluye el tipo (
.class
) en la llamada aladdSerializer()
método, que debería leerse así:En otras palabras, estas son las líneas que instancian
simpleModule
y agregan el serializador (con la línea incorrecta anterior comentada):FYI: Aquí está la referencia del código de ejemplo correcto: http://wiki.fasterxml.com/JacksonFeatureModules
fuente
Utilice @JsonValue:
@JsonValue solo funciona en métodos, por lo que debe agregar el método getId. Debería poder omitir su serializador personalizado por completo.
fuente
Escribí un ejemplo para una
Timestamp.class
serialización / deserialización personalizada, pero puede usarlo para lo que quiera.Al crear el mapeador de objetos, haga algo como esto:
por ejemplo
java ee
, podría inicializarlo con esto:donde el serializador debería ser algo como esto:
y deserializador algo como esto:
fuente
Estos son patrones de comportamiento que he notado al intentar comprender la serialización de Jackson.
1) Suponga que hay un objeto Aula y una clase Estudiante. He hecho todo público y definitivo para mayor facilidad.
2) Suponga que estos son los serializadores que usamos para serializar los objetos en JSON. WriteObjectField usa el propio serializador del objeto si está registrado con el asignador de objetos; si no, lo serializa como POJO. WriteNumberField acepta exclusivamente primitivas como argumentos.
3) Registre solo un DoubleSerializer con patrón de salida DecimalFormat
###,##0.000
, en SimpleModule y la salida es:Puede ver que la serialización POJO diferencia entre double y Double, usando DoubleSerialzer para Dobles y usando un formato de Cadena regular para dobles.
4) Registre DoubleSerializer y ClassroomSerializer, sin StudentSerializer. Esperamos que la salida sea tal que si escribimos un doble como un objeto, se comportará como un Doble, y si escribimos un Doble como un número, se comportará como un doble. La variable de instancia Student debe escribirse como POJO y seguir el patrón anterior, ya que no se registra.
5) Registre todos los serializadores. La salida es:
exactamente como se esperaba.
Otra nota importante: si tiene varios serializadores para la misma clase registrados con el mismo módulo, entonces el módulo seleccionará el serializador para esa clase que se agregó más recientemente a la lista. Esto no debe usarse, es confuso y no estoy seguro de cuán consistente es esto
Moraleja: si desea personalizar la serialización de primitivas en su objeto, debe escribir su propio serializador para el objeto. No puede confiar en la serialización de POJO Jackson.
fuente
Las vistas JSON de Jackson pueden ser una forma más sencilla de lograr sus requisitos, especialmente si tiene cierta flexibilidad en su formato JSON.
Si
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
es una representación aceptable, será muy fácil de lograr con muy poco código.Simplemente anotaría el campo de nombre de Usuario como parte de una vista y especificaría una vista diferente en su solicitud de serialización (los campos sin anotaciones se incluirían de forma predeterminada)
Por ejemplo: Defina las vistas:
Anotar al usuario:
Y serialice solicitando una vista que no contenga el campo que desea ocultar (los campos no anotados se serializan por defecto):
fuente
createdBy
un valor en lugar de un objeto?setSerializationView()
parece estar en desuso, así que usé en sumapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
lugar.En mi caso (Spring 3.2.4 y Jackson 2.3.1), configuración XML para serializador personalizado:
se sobrescribió de forma inexplicable de nuevo al valor predeterminado por algo.
Esto funcionó para mí:
CustomObject.java
CustomObjectSerializer.java
No
<mvc:message-converters>(...)</mvc:message-converters>
se necesita ninguna configuración XML ( ) en mi solución.fuente
Si su único requisito en su serializador personalizado es omitir la serialización del
name
campo deUser
, márquelo como transitorio . Jackson no serializará ni deserializará transitorio campos .[ver también: ¿Por qué Java tiene campos transitorios? ]
fuente
User
clase? Pero también serializaré todos los objetos de usuario. Por ejemplo, primero solo serialice todoitems
(con solouserId
como referencia al objeto de usuario) y luego serialice todousers
. En este caso, no puedo marcar los campos en laUser
clase.handledType()
método en la documentación a la que me vinculé y cuando Eclipse genera los métodos para implementar nohandledType()
se genera, así que estoy confundido.Tienes que anular el método handleType y todo funcionará
fuente
El problema en su caso es que al ItemSerializer le falta el método handleType () que debe anularse desde JsonSerializer
Por lo tanto, está obteniendo el error explícito de que no está definido handleType ()
Espero que ayude a alguien. Gracias por leer mi respuesta.
fuente