* Mostly driver by suggestions from IDEA language plugin * Add Maven-Gradle code switch for dependency in the modules
143 lines
6.0 KiB
Plaintext
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.
|