Serialización
La serialización en IPF se realiza con Jackson, y su propia documentación cubrirá mucho más de lo que esta página pretende, y hay innumerables tutoriales y recursos en línea que pueden ayudar con la comprensión y el uso de Jackson. Un buen lugar para comenzar son los official docs.
El objetivo de esta página es proporcionar una breve introducción a la serialización dentro de IPF, incluyendo el comportamiento predeterminado y cómo se puede customised, y algunas advertencias y recomendaciones.
Conceptos
Esta sección tiene la intención de ser breve. Todos los conceptos enumerados aquí se tratan con mayor detalle en secciones posteriores.
SerializationHelper
SerializationHelper`es el punto de entrada principal para la serialización.
Proporciona métodos de conveniencia para serializar a y deserializar de JSON, y en última instancia delega a su *singleton*Jackson `com.fasterxml.jackson.databind. ObjectMapper instancia.
El subyacente singleton ObjectMapper la instancia se crea utilizando el ObjectMapperFactory.
Ejemplos
//Access the singleton ObjectMapper instance
ObjectMapper objectMapper = SerializationHelper.objectMapper();
//e.g. to convert between types
objectMapper.convertValue(object, SomeOtherType.class);
//Convenience methods to serialize to JSON using the singleton ObjectMapper
String json = SerializationHelper.objectToString(object);
//And to deserialize from JSON
MyObject deserialized = SerializationHelper.stringToObject(json, MyObject.class);
ObjectMapperFactory
com.iconsolutions.ipf.core.shared.api.serializer. ObjectMapperFactory`es el punto de entrada principal para crear nuevos `ObjectMapper instancias.
Si necesita una instancia diferente a la proporcionada por SerializationHelper.objectMapper(), usted utilizaría esta clase.SerializationHelper usos ObjectMapperFactory para crear el suyo propio singleton ObjectMapper instancia.
Ejemplos
//Create a new ObjectMapper instance that behaves the same as SerializationHelper.objectMapper()
ObjectMapper serializationHelperObjectMapper = ObjectMapperFactory.createObjectMapper();
//Create a new ObjectMapper instance with additional configured customisation
ObjectMapper customSerializationHelperObjectMapper = ObjectMapperFactory.createObjectMapper(config);
//Create a new named ObjectMapper instance that must be configured separately from serialization-helper
ObjectMapper customObjectMapper = ObjectMapperFactory.createObjectMapper("my-object-mapper", config);
Akka Jackson
El ObjectMapper las instancias se configuran utilizando Akka Jackson, lo que significa que el comportamiento de serialización puede ser customised con Hocon configuración.
La configuración predeterminada está incluida para un serializador llamado serialization-helper, y este serializador puede ser customised con configuración adicional.
akka.serialization.jackson.serialization-helper {
//Additional modules can be added to support custom serialization/deserialization behaviour
jackson-modules += "MyCustomModule"
}
También se pueden definir nuevos serializadores, lo cual es una buena manera de customise serialización sin cambiar el comportamiento del asistente de serialización.
akka.serialization.jackson.my-serializer = "akka.serialization.jackson. JacksonJsonSerializer"
//Custom serializer can inherit the default serialization-helper behaviour, and provide additional customisation
akka.serialization.jackson.my-serializer = ${akka.serialization.jackson.serialization-helper} {
jackson-modules += "MyCustomModule"
}
Introducción
Uso del SerializationHelper Predeterminado
En muchos casos Comportamiento de Serialización Predeterminado será suficiente, lo que significa que la serialización se puede realizar utilizando los métodos de conveniencia en SerializationHelper, o accediendo a la base subyacente ObjectMapper instancia.
String json = SerializationHelper.objectToString(object);
MyObject deserialized = SerializationHelper.stringToObject(json, MyObject.class);
Map<String, Object> b = SerializationHelper.objectMapper().convertValue(deserialized, new TypeReference<Map<String, Object>>() {
});
Customising SerializadorPorDefecto
Por supuesto, habrá casos en los que el comportamiento de serialización predeterminado no sea suficiente, por ejemplo, cuando los tipos deben ser serializados en un custom manera.
Customisation debería realizarse idealmente a través de la configuración, consulte el <<configuration-reference>> para el conjunto completo de opciones de configuración. Evite configurar/mutar programáticamente el valor predeterminado.`ObjectMapper` instancia.
Registrándose Custom Módulos
Dado lo siguiente custom módulo
public final class MyModule extends SimpleModule {
@Override
public void setupModule(final SetupContext context) {
super.setupModule(context);
final var serializers = new SimpleSerializers();
serializers.addSerializer(SomeType.class, new JsonSerializer<>() {
@Override
public void serialize(final SomeType value, final JsonGenerator gen, final SerializerProvider serializers) {
//Custom serialization behaviour for SomeType
}
});
context.addSerializers(serializers);
final var deserializers = new SimpleDeserializers();
deserializers.addDeserializer(SomeType.class, new JsonDeserializer<>() {
@Override
public SomeType deserialize(final JsonParser p, final DeserializationContext ctxt) {
//Custom deserialization behaviour for SomeType
}
});
context.addDeserializers(deserializers);
}
record SomeType(String name) {
}
}
El módulo puede ser añadido al serializador de ayuda de serialización con la siguiente configuración:
akka.serialization.jackson.serialization-helper.jackson-modules += "package.of.my.module. MyModule"
Advertencias
Cambiar el comportamiento de serialización predeterminado debe abordarse con precaución y probablemente sea mejor evitarlo. En la mayoría de los casos, agregar custom Los tipos soportados a través de módulos estarán bien, pero cambiar el comportamiento de serialización predeterminado impactará todo el otro código que utiliza la serialización predeterminada. Cuando se requiere una configuración adicional, considere en su lugar Creando Custom Serializadores.
Configuración programática, es decir, mutar el ObjectMapper La instancia debe evitarse porque depende de que se invoque esa ruta de código para que la configuración tenga efecto, por ejemplo, evite hacer lo siguiente
SerializationHelper.objectMapper().registerModule(new MyModule())
Uso de la serialización IPF en una aplicación Spring
Las aplicaciones web de Spring típicamente configuran su propio ObjectMapper.bean, y la primavera viene con sus propios mecanismos para customisation de la instancia de ObjectMapper.
Puede preferir utilizar el comportamiento de serialización IPF. Para hacerlo, dependa de ipf-serialization-autoconfigure.
<dependency>
<groupId>com.iconsolutions.ipf.core.platform</groupId>
<artifactId>ipf-serialization-autoconfigure</artifactId>
</dependency>
Este módulo de autoconfiguración de Spring se configura a sí mismo antes de cualquier Spring Jackson autoconfiguración, proporcionando el mismo ObjectMapper predeterminado (es una instancia diferente) utilizado por SerializationHelper.
Creando Custom Serializadores
La creación de nuevos serializadores, que será necesaria cuando el comportamiento de serialización predeterminado no sea suficiente, puede lograrse de varias maneras.
Típicamente, los proyectos aguas abajo crean su propio ObjectMapper instancia, configúrelo programáticamente y haga que esa instancia esté disponible en todos los lugares donde se necesite, pero también es posible definir y configurar custom serializadores a través de hocon.
El enfoque que elija puede depender de sus requisitos, por ejemplo, ¿necesita el comportamiento predeterminado con pequeños cambios, o necesita un ObjectMapper completamente nuevo sin ninguno de los valores predeterminados de IPF?
Cuando los valores predeterminados son casi suficientes, pero necesita cambiar la forma en que se serializan los valores nulos y vacíos, puede crear programáticamente una nueva instancia predeterminada y anular las inclusiones de serialización, por ejemplo.
//Creates a new instance of the default serialization ObjectMapper
var mapper ObjectMapperFactory.createObjectMapper();
//And overrides it to always write nulls and empty objects when serializing to JSON
mapper.setSerializationInclusion(JsonInclude. Include. ALWAYS);
Alternativamente, puede definir un custom mapper con sus propios módulos para customisation, p. ej.
akka {
serializers.my-custom-mapper = "akka.serialization.jackson. JacksonJsonSerializer"
//Inherits serialization-helper, but with customisations
serialization.jackson.my-custom-mapper = ${akka.serialization.jackson.serialization-helper} {
jackson-modules += "com.food.bar. MyCustomModule"
}
}
/**
* Overrides the default serialization inclusion configuration
*/
public final class MyCustomModule extends SimpleModule {
@Override
public void setupModule(final SetupContext context) {
super.setupModule(context);
final ObjectMapper objectMapper = context.getOwner();
objectMapper.setSerializationInclusion(JsonInclude. Include. ALWAYS);
}
}
var mapper = ObjectMapperFactory.createObjectMapper("my-custom-mapper", config);
Cuando se requiere un serializador completamente nuevo, omita el marcador de posición utilizado para heredar el ayudante de serialización, por ejemplo.
akka {
serializers.my-custom-mapper = "akka.serialization.jackson. JacksonJsonSerializer"
}
| Cuando la serialización va a ser compartida, por ejemplo, si usted produce una aplicación cliente y servidor, considere introducir un módulo de serialización compartido con su propia configuración/configuración programática y clases auxiliares, en lugar de duplicar la configuración y la inicialización del serializador. |
Comportamiento de Serialización Predeterminado
El ayudante de serialización predeterminado ObjectMapper la instancia es un customised instancia de lo que se define para Akka Jackson serialización, p. ej. configuración bajo akka.serialization.jackson, que en sí mismo es un customised instancia del predeterminado ObjectMapper, p. ej.new ObjectMapper().
| Todas las características y configuraciones no mencionadas aquí pueden asumirse como el Jackson predeterminados. |
Características de Serialización
| Característica | Habilitado/Deshabilitado | Descripción |
|---|---|---|
|
Habilitado |
La duración |
|
Habilitado |
Se lanzará una excepción al intentar serializar un objeto que no tiene propiedades serializables. |
Características de deserialización
| Característica | Habilitado/Deshabilitado | Descripción |
|---|---|---|
|
Habilitado |
Establece el tipo de dato utilizado al deserializar números de punto flotante, en este caso |
Módulos
Los siguientes módulos están incluidos en el serializador predeterminado.
| Módulo | Descripción |
|---|---|
A Jackson módulo que añade soporte para tipos de Scala |
|
A Jackson módulo que añade soporte para acceder a los nombres de los parámetros; una característica añadida en JDK 8. |
|
` Jdk8Module` |
A Jackson módulo que añade soporte para tipos de jdk8, por ejemplo. |
|
Un módulo IPF que añade soporte para java tipos de tiempo, p. ej. |
|
Un módulo IPF que compensa un problema con los tipos enum incompletos. |
|
Un módulo IPF que añade soporte para elementos DOM. |
|
Un módulo IPF que añade soporte para deserializar datos en bruto |
Referencia de Configuración
Akka Jackson se utiliza para configurar los serializadores, por lo que el mejor lugar para comenzar es el xref:https://doc.akka.io/libraries/akka-core/current/serialization-jackson.html[official docs]. Para opciones de configuración específicas, consulte el xref:https://doc.akka.io/libraries/akka-core/current/serialization-jackson.html#additional-features[Additional Características] sección.
Los detalles de configuración en la sección de Características Adicionales, por ejemplo, todo lo que se encuentra debajo de akka.serialization.jackson también puede aplicarse al ayudante de serialización predeterminado akka.serialization.jackson.serialization-helper, y para custom serializers, por ejemplo.akka.serialization.jackson.my-custom-serializer.
Akka Jackson no admite la configuración de las inclusiones de serialización para la instancia de ObjectMapper, y típicamente esto se realiza de manera programática, por ejemplo.`new ObjectMapper().setSerializationInclusion(JsonIncludes. NON_NUll)`, pero esto se puede lograr con un custom módulo que customises la instancia de ObjectMapper subyacente, por ejemplo.
public final class JsonIncludeOverrideModule extends SimpleModule {
@Override
public void setupModule(final SetupContext context) {
super.setupModule(context);
final ObjectMapper objectMapper = context.getOwner();
objectMapper.setSerializationInclusion(JsonInclude. Include. ALWAYS);
}
}
Hacer, No hacer, Sugerencias, Quejas
Apoyo Custom Tipos
Evite utilizar SerializationHelper, o cualquier otra instancia de ObjectMapper desde dentro de custom com.fasterxml.jackson.databind. JsonSerializer y com.fasterxml.jackson.databind. JsonDeserializer implementaciones, por ejemplo, no haga
final class SomeOtherObjectJsonSerializer extends JsonSerializer<SomeOtherObject> {
@Override
public void serialize(final SomeObject value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException {
//Use SerializationHelper
final var string = SerializationHelper.objectToString(value);
gen.writeString(string);
}
}
Esto custom JsonSerializer puede ser utilizado dentro de cualquier custom ObjectMapper instancia, pero se basa en el ayudante de serialización predeterminado ObjectMapper, que puede comportarse de manera diferente en tiempo de ejecución, dependiendo de la configuración.
Prefiera el mecanismo que se le proporciona, por ejemplo, en el serializador anterior probablemente puede lograr lo que necesita con el JsonGenerator y SerializerProvider argumentos. El JsonDeserializer proporciona instalaciones similares.
===
Compartir Custom Serialización
Si tiene requisitos de serialización específicos y el asistente de serialización predeterminado no es suficiente, considere crear su propio serializador nombrado y colocar su configuración y clases/métodos de ayuda, y por supuesto, pruebas, en un nuevo módulo. Este módulo puede ser utilizado por otros proyectos posteriores.