Files
spring-integration/src/reference/asciidoc/codec.adoc
Artem Bilan 9ac0b65c77 Fix some typos and language in docs
* Mostly driver by suggestions from IDEA language plugin
* Add Maven-Gradle code switch for dependency in the modules
2022-02-15 13:00:24 -05:00

143 lines
6.0 KiB
Plaintext

[[codec]]
=== Codec
Version 4.2 of Spring Integration introduced the `Codec` abstraction.
Codecs encode and decode objects to and from `byte[]`.
They offer an alternative to Java serialization.
One advantage is that, typically, objects need not implement `Serializable`.
We provide one implementation that uses https://github.com/EsotericSoftware/kryo[Kryo] for serialization, but you can provide your own implementation for use in any of the following components:
* `EncodingPayloadTransformer`
* `DecodingTransformer`
* `CodecMessageConverter`
==== `EncodingPayloadTransformer`
This transformer encodes the payload to a `byte[]` by using the codec.
It does not affect message headers.
See the https://docs.spring.io/spring-integration/api/org/springframework/integration/transformer/EncodingPayloadTransformer.html[Javadoc] for more information.
==== `DecodingTransformer`
This transformer decodes a `byte[]` by using the codec.
It needs to be configured with the `Class` to which the object should be decoded (or an expression that resolves to a `Class`).
If the resulting object is a `Message<?>`, inbound headers are not retained.
See the https://docs.spring.io/spring-integration/api/org/springframework/integration/transformer/DecodingTransformer.html[Javadoc] for more information.
==== `CodecMessageConverter`
Certain endpoints (such as TCP and Redis) have no concept of message headers.
They support the use of a `MessageConverter`, and the `CodecMessageConverter` can be used to convert a message to or from a `byte[]` for transmission.
See the https://docs.spring.io/spring-integration/api/org/springframework/integration/codec/CodecMessageConverter.html[Javadoc] for more information.
==== Kryo
Currently, this is the only implementation of `Codec`, and it provides two kinds of `Codec`:
* `PojoCodec`: Used in the transformers
* `MessageCodec`: Used in the `CodecMessageConverter`
The framework provides several custom serializers:
* `FileSerializer`
* `MessageHeadersSerializer`
* `MutableMessageHeadersSerializer`
The first can be used with the `PojoCodec` by initializing it with the `FileKryoRegistrar`.
The second and third are used with the `MessageCodec`, which is initialized with the `MessageKryoRegistrar`.
===== Customizing Kryo
By default, Kryo delegates unknown Java types to its `FieldSerializer`.
Kryo also registers default serializers for each primitive type, along with `String`, `Collection`, and `Map`.
`FieldSerializer` uses reflection to navigate the object graph.
A more efficient approach is to implement a custom serializer that is aware of the object's structure and can directly serialize selected primitive fields.
The following example shows such a serializer:
====
[source,java]
----
public class AddressSerializer extends Serializer<Address> {
@Override
public void write(Kryo kryo, Output output, Address address) {
output.writeString(address.getStreet());
output.writeString(address.getCity());
output.writeString(address.getCountry());
}
@Override
public Address read(Kryo kryo, Input input, Class<Address> type) {
return new Address(input.readString(), input.readString(), input.readString());
}
}
----
====
The `Serializer` interface exposes `Kryo`, `Input`, and `Output`, which provide complete control over which fields are included and other internal settings, as described in the https://github.com/EsotericSoftware/kryo[Kryo documentation].
NOTE: When registering your custom serializer, you need a registration ID.
The registration IDs are arbitrary.
However, in our case, the IDs must be explicitly defined, because each Kryo instance across the distributed application must use the same IDs.
Kryo recommends small positive integers and reserves a few ids (value < 10).
Spring Integration currently defaults to using 40, 41, and 42 (for the file and message header serializers mentioned earlier).
We recommend you start at 60, to allow for expansion in the framework.
You can override these framework defaults by configuring the registrars mentioned earlier.
====== Using a Custom Kryo Serializer
If you need custom serialization, see the https://github.com/EsotericSoftware/kryo[Kryo] documentation, because you need to use the native API to do the customization.
For an example, see the https://github.com/spring-projects/spring-integration/blob/main/spring-integration-core/src/main/java/org/springframework/integration/codec/kryo/MessageCodec.java[`MessageCodec`] implementation.
====== Implementing KryoSerializable
If you have `write` access to the domain object source code, you can implement `KryoSerializable` as described https://github.com/EsotericSoftware/kryo#kryoserializable[here].
In this case, the class provides the serialization methods itself and no further configuration is required.
However, benchmarks have shown this is not quite as efficient as registering a custom serializer explicitly.
The following example shows a custom Kryo serializer:
====
[source,java]
----
public class Address implements KryoSerializable {
...
@Override
public void write(Kryo kryo, Output output) {
output.writeString(this.street);
output.writeString(this.city);
output.writeString(this.country);
}
@Override
public void read(Kryo kryo, Input input) {
this.street = input.readString();
this.city = input.readString();
this.country = input.readString();
}
}
----
====
You can also use this technique to wrap a serialization library other than Kryo.
====== Using the `@DefaultSerializer` Annotation
Kryo also provides a `@DefaultSerializer` annotation, as described https://github.com/EsotericSoftware/kryo#default-serializers[here].
====
[source,java]
----
@DefaultSerializer(SomeClassSerializer.class)
public class SomeClass {
// ...
}
----
====
If you have `write` access to the domain object, this may be a simpler way to specify a custom serializer.
Note that this does not register the class with an ID, which may make the technique unhelpful for certain situations.