Consider the immutable class Foo (a POJO consisting of an identifier and a name) that must be serialized so that data can be sent from the server to the client.
public final class Foo { private final int m_id; private final String m_displayName; private Foo(final int id, final String displayName) { m_id = id; m_displayName = displayName; } public static Foo create(final int id, final String displayName) {
Activation of the Foo object occurs through the static factory function, and since the immutable object does not have a constructor with a null argument.
Consider also the immutable Bar class, which contains the Foo data element and implements the Builder template to create it (omitted from the fragment, since it is not related to the problem).
public final class Bar { private final Foo m_foo; . . . private Bar(final Builder builder) { . . . } public static Builder createBuilder() { return new Builder(); } }
After evaluating my options regarding how I should serialize this object without removing its immutability or adding zero-args constructors for serialization, I came to the conclusion that I need to implement CustomFieldSerializer (both for the client and the server).
I followed the recommendations written in the article Server Communication in GWT, and implemented my own CustomFieldSerializer, as shown below.
// Contains the serialization logic of the class Bar. public final class Bar_CustomFieldSerializerBase { public static Bar instantiate(final SerializationStreamReader streamReader) throws SerializationException { return Bar.createBuilder().forFoo((Foo) streamReader.readObject()).build(); } public static void serialize(final SerializationStreamWriter streamWriter, final Bar instance) throws SerializationException { // . . . streamWriter.writeObject(instance.getFoo()); } public static void deserialize(final SerializationStreamReader streamReader, final Bar instance) { /* * Empty as everything is handled on instantiateInstance(). */ } } // The CustomFieldSerializer for class Bar. public class Bar_CustomFieldSerializer extends CustomFieldSerializer<Bar> { public static void deserialize(final SerializationStreamReader streamReader, final Bar instance) throws SerializationException { Bar_CustomFieldSerializerBase.deserialize(streamReader, instance); } public static void serialize(final SerializationStreamWriter streamWriter, final Bar instance) throws SerializationException { Bar_CustomFieldSerializerBase.serialize(streamWriter, instance); } public static Bar instantiate(final SerializationStreamReader streamReader) throws SerializationException { return Bar_CustomFieldSerializerBase.instantiate(streamReader); } @Override public boolean hasCustomInstantiateInstance() { return true; } @Override public Bar instantiateInstance(final SerializationStreamReader streamReader) throws SerializationException { return instantiate(streamReader); } @Override public void deserializeInstance(final SerializationStreamReader streamReader, final Bar instance) throws SerializationException { deserialize(streamReader, instance); } @Override public void serializeInstance(final SerializationStreamWriter streamWriter, final Bar instance) throws SerializationException { serialize(streamWriter, instance); } // Server side CustomFieldSerializer for class Bar. public class Bar_ServerCustomFieldSerializer extends ServerCustomFieldSerializer<Bar> { public static void deserialize(ServerSerializationStreamReader streamReader, Bar instance, Type[] expectedParameterTypes, DequeMap<TypeVariable<?>, Type> resolvedTypes) throws SerializationException { /* * Empty as everything is handled on instantiateInstance(). */ } @Override public Bar instantiateInstance(ServerSerializationStreamReader streamReader) throws SerializationException { return Bar_CustomFieldSerializerBase.instantiate(streamReader); } @Override public void deserializeInstance(ServerSerializationStreamReader streamReader, Bar instance, Type[] expectedParameterTypes, DequeMap<TypeVariable<?>, Type> resolvedTypes) throws SerializationException { deserialize(streamReader, instance, expectedParameterTypes, resolvedTypes); } @Override public void deserializeInstance(SerializationStreamReader streamReader, Bar instance) throws SerializationException { Bar_CustomFieldSerializerBase.deserialize(streamReader, instance); } @Override public void serializeInstance(SerializationStreamWriter streamWriter, Bar instance) throws SerializationException { Bar_CustomFieldSerializerBase.serialize(streamWriter, instance); } }
Since the class panel contains a Foo object that needs to be serialized, I went on and implemented another set of CustomFieldSerializers, this time for the Foo class following the same template for both the client and server.
The problem occurs when serialization occurs for the Bar class, and specifically at this point:
public static void serialize(final SerializationStreamWriter streamWriter, final Bar instance) throws SerializationException {
The error message I get is the following:
[WARN] Exception while dispatching incoming RPC call com.google.gwt.user.client.rpc.SerializationException: Type 'ui.shared.models.fooItems.Foo' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.
It seems that writeObject () cannot serialize an object of type Foo because the class Foo does not belong to whitelist elements, even if custom serializers were provided for both the client and the server.
I could always skip the call to writeObject () and call writeInt () and writeString () for each Foo data item (which works well), but I'd rather write writeObject (). The solution I propose is highly susceptible to maintenance errors, since any changes to the Foo class in the future should affect both the Foo serializers (obvious) and the string serializers (not so obvious).
I tried almost everything I could find on the network, from the implementation of the isSerializable interface to Foo and Bar (it doesnβt make any difference, and it should not make any difference since AFAIK classes that supply their own serializers do not need to adhere to this rule ) and even supply private zero-args constructors (which should also not make any difference, since the functions of creating an instance of a custom field polarizer should take care of this through static factories).
Why is the Foo class not whitelisted? Am I missing something obvious or misinterpreting something?
Thanks for your time in advance.