+act #17576 Support serializer with string manifest
* useful when evolution is needed, e.g. Akka Persistence * docs, comments, cluster-metrics and cluster-tools serializers
This commit is contained in:
parent
aeb2302c2f
commit
740f006a38
21 changed files with 605 additions and 93 deletions
|
|
@ -3,9 +3,14 @@
|
|||
*/
|
||||
package docs.serialization;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import akka.testkit.JavaTestKit;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
//#imports
|
||||
import akka.actor.*;
|
||||
import akka.serialization.*;
|
||||
|
|
@ -49,6 +54,79 @@ public class SerializationDocTest {
|
|||
}
|
||||
//#my-own-serializer
|
||||
|
||||
static class Customer {
|
||||
public final String name;
|
||||
|
||||
Customer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
static class User {
|
||||
public final String name;
|
||||
|
||||
User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#my-own-serializer2
|
||||
public class MyOwnSerializer2 extends SerializerWithStringManifest {
|
||||
|
||||
private static final String CUSTOMER_MANIFEST = "customer";
|
||||
private static final String USER_MANIFEST = "user";
|
||||
private static final String UTF_8 = StandardCharsets.UTF_8.name();
|
||||
|
||||
// Pick a unique identifier for your Serializer,
|
||||
// you've got a couple of billions to choose from,
|
||||
// 0 - 16 is reserved by Akka itself
|
||||
@Override public int identifier() {
|
||||
return 1234567;
|
||||
}
|
||||
|
||||
@Override public String manifest(Object obj) {
|
||||
if (obj instanceof Customer)
|
||||
return CUSTOMER_MANIFEST;
|
||||
else if (obj instanceof User)
|
||||
return USER_MANIFEST;
|
||||
else
|
||||
throw new IllegalArgumentException("Unknow type: " + obj);
|
||||
}
|
||||
|
||||
// "toBinary" serializes the given object to an Array of Bytes
|
||||
@Override public byte[] toBinary(Object obj) {
|
||||
// Put the real code that serializes the object here
|
||||
try {
|
||||
if (obj instanceof Customer)
|
||||
return ((Customer) obj).name.getBytes(UTF_8);
|
||||
else if (obj instanceof User)
|
||||
return ((User) obj).name.getBytes(UTF_8);
|
||||
else
|
||||
throw new IllegalArgumentException("Unknow type: " + obj);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// "fromBinary" deserializes the given array,
|
||||
// using the type hint
|
||||
@Override public Object fromBinary(byte[] bytes, String manifest) {
|
||||
// Put the real code that deserializes here
|
||||
try {
|
||||
if (manifest.equals(CUSTOMER_MANIFEST))
|
||||
return new Customer(new String(bytes, UTF_8));
|
||||
else if (manifest.equals(USER_MANIFEST))
|
||||
return new User(new String(bytes, UTF_8));
|
||||
else
|
||||
throw new IllegalArgumentException("Unknow manifest: " + manifest);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#my-own-serializer2
|
||||
|
||||
@Test public void serializeActorRefs() {
|
||||
final ExtendedActorSystem extendedSystem = (ExtendedActorSystem)
|
||||
ActorSystem.create("whatever");
|
||||
|
|
|
|||
|
|
@ -103,9 +103,38 @@ which is done by extending ``akka.serialization.JSerializer``, like this:
|
|||
:include: my-own-serializer
|
||||
:exclude: ...
|
||||
|
||||
The manifest is a type hint so that the same serializer can be used for different
|
||||
classes. The manifest parameter in ``fromBinaryJava`` is the class of the object that
|
||||
was serialized. In ``fromBinary`` you can match on the class and deserialize the
|
||||
bytes to different objects.
|
||||
|
||||
Then you only need to fill in the blanks, bind it to a name in your :ref:`configuration` and then
|
||||
list which classes that should be serialized using it.
|
||||
|
||||
Serializer with String Manifest
|
||||
-------------------------------
|
||||
|
||||
The ``Serializer`` illustrated above supports a class based manifest (type hint).
|
||||
For serialization of data that need to evolve over time the `SerializerWithStringManifest`
|
||||
is recommended instead of ``Serializer`` because the manifest (type hint) is a ``String``
|
||||
instead of a ``Class``. That means that the class can be moved/removed and the serializer
|
||||
can still deserialize old data by matching on the ``String``. This is especially useful
|
||||
for :ref:`persistence-java`.
|
||||
|
||||
The manifest string can also encode a version number that can be used in ``fromBinary`` to
|
||||
deserialize in different ways to migrate old data to new domain objects.
|
||||
|
||||
If the data was originally serialized with ``Serializer`` and in a later version of the
|
||||
system you change to ``SerializerWithStringManifest`` the manifest string will be the full
|
||||
class name if you used ``includeManifest=true``, otherwise it will be the empty string.
|
||||
|
||||
This is how a ``SerializerWithStringManifest`` looks like:
|
||||
|
||||
.. includecode:: code/docs/serialization/SerializationDocTest.java#my-own-serializer2
|
||||
|
||||
You must also bind it to a name in your :ref:`configuration` and then list which classes
|
||||
that should be serialized using it.
|
||||
|
||||
Serializing ActorRefs
|
||||
---------------------
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue