title: GWT Custom Field Serialization Issue
body: <p>Consider an immutable class Foo (a POJO consisting of an ID and a name), that needs to be serialized in order for the data to be sent from the server to the client.</p>
  
  <pre><code>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)
      {
           // Some error checking occurs here.
           . . . 
  
           m_id = id;
           m_displayName = displayName;
      }
  
      // Getters etc.
      . . .
  }
  </code></pre>
  
  <p>Instantiation of a Foo object happens through the static factory function and since the object's immutable there is no zero-args constructor.</p>
  
  <p>Consider an immutable class Bar as well that contains a data member Foo and implements the Builder pattern for its instantiation (omitted from snippet as it is irrelevant to the problem).</p>
  
  <pre><code>public final class Bar
  {
      private final Foo m_foo;
      . . .
  
      private Bar(final Builder builder)
      {
          . . .
      }
  
      public static Builder createBuilder()
      {
          return new Builder();
      }
  }
  </code></pre>
  
  <p>After evaluating my choices regarding the way I should serialize this object without removing its immutability or adding any zero-args constructors for the sake of serialization I concluded to the fact that I needed to implement a CustomFieldSerializer (for both the client and the server).</p>
  
  <p>I followed the guidelines written in the <a href="https://developers.google.com/web-toolkit/doc/latest/DevGuideServerCommunication?hl=el#DevGuideSerializableTypes">Server Communication</a> article of GWT and implemented my own CustomFieldSerializer as depicted below.</p>
  
  <pre><code>// 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&lt;Bar&gt;
  {
      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&lt;Bar&gt;
  {
      public static void deserialize(ServerSerializationStreamReader streamReader, Bar instance,
          Type[] expectedParameterTypes, DequeMap&lt;TypeVariable&lt;?&gt;, Type&gt; 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&lt;TypeVariable&lt;?&gt;, Type&gt; 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);
      }
  }
  </code></pre>
  
  <p>Since the class bar contains a Foo object that needs to be serialized I went on and implemented another set of CustomFieldSerializers, this time for class Foo following the same pattern, for both the client and server.</p>
  
  <p>The issue arises when serialization occurs for the class Bar and specifically at this point:</p>
  
  <pre><code>public static void serialize(final SerializationStreamWriter streamWriter, final Bar instance)
          throws SerializationException
  {
     // . . .
     streamWriter.writeObject(instance.getFoo());
  }
  </code></pre>
  
  <p>The exception message I get is the following:</p>
  
  <pre><code>[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.
  </code></pre>
  
  <p>It seems that <em>writeObject()</em> cannot serialize the object of type Foo because the Foo class does not belong to the whitelisted items, even though custom serializers have been provided for both the client and the server.</p>
  
  <p>I could always skip the <em>writeObject()</em> invocation and call <em>writeInt()</em> &amp; <em>writeString()</em> for each Foo's data members (which is working well) but I would much rather get <em>writeObject()</em> to work. The solution that I proposed is <em>highly</em> prone to maintenance mistakes as any changes in the Foo class in the future have to be reflected on both the Foo's serializers (obvious) and Bar's serializers (not so obvious).</p>
  
  <p>I have tried pretty much anything I could find on the net, from implementing the <em>isSerializable</em> interface on both Foo and Bar (didn't make any difference and it shouldn't make any difference since AFAIK classes that supply their own custom serializers do not need to adhere to this rule) and even supplying a private zero-args constructors (which should also not make any difference as the instantiation functions of the custom field serializer should take care of that through the static factories).</p>
  
  <p>Why is the Foo class not whitelisted? Have I missed something obvious or have misinterpreted something?</p>
  
  <p>Thank you for your time in advance.</p>