+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:
Patrik Nordwall 2015-05-28 18:42:22 +02:00
parent aeb2302c2f
commit 740f006a38
21 changed files with 605 additions and 93 deletions

View file

@ -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");

View file

@ -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
---------------------