データをサーバーからクライアントに送信するためにシリアル化する必要がある不変クラス Foo (ID と名前で構成される POJO) を考えてみましょう。
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.
. . .
}
Foo オブジェクトのインスタンス化は静的ファクトリ関数によって行われ、オブジェクトは不変であるため、引数がゼロのコンストラクターはありません。
データ メンバー Foo を含み、そのインスタンス化のために Builder パターンを実装する不変クラス Bar も検討してください (問題とは無関係であるため、スニペットから省略されています)。
public final class Bar
{
private final Foo m_foo;
. . .
private Bar(final Builder builder)
{
. . .
}
public static Builder createBuilder()
{
return new Builder();
}
}
不変性を削除したり、シリアル化のためにゼロ引数のコンストラクターを追加したりせずに、このオブジェクトをシリアル化する方法に関する私の選択を評価した後、CustomFieldSerializer を実装する必要があるという事実に結論付けました (クライアントとサーバーの両方)。
GWT のサーバー通信の記事に書かれているガイドラインに従い、以下に示すように独自の CustomFieldSerializer を実装しました。
// 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);
}
}
クラス bar にはシリアライズが必要な Foo オブジェクトが含まれているため、別の一連の CustomFieldSerializers を実装しました。今回は、クライアントとサーバーの両方で同じパターンに従うクラス Foo 用です。
この問題は、クラス Bar のシリアル化が発生したときに、具体的にはこの時点で発生します。
public static void serialize(final SerializationStreamWriter streamWriter, final Bar instance)
throws SerializationException
{
// . . .
streamWriter.writeObject(instance.getFoo());
}
私が受け取る例外メッセージは次のとおりです。
[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.
カスタムシリアライザーがクライアントとサーバーの両方に提供されているにもかかわらず、 Foo クラスがホワイトリストに登録されたアイテムに属していないため、 writeObject()はタイプ Foo のオブジェクトをシリアライズできないようです。
いつでもwriteObject()の呼び出しをスキップして、Foo のデータ メンバーごとにwriteInt( )とwriteString() を呼び出すことができますが (これはうまく機能しています)、むしろwriteObject()を機能させたいと思います。私が提案した解決策は、Foo クラスの将来の変更が Foo のシリアライザー (明らか) と Bar のシリアライザー (それほど明白ではない) の両方に反映されなければならないため、メンテナンスの間違いが非常に起こりやすいです。
Foo と Bar の両方にisSerializableインターフェースを実装することから、ネット上で見つけることができるほとんどすべてを試しました(違いはありませんでしたし、独自のカスタムシリアライザーを提供する AFAIK クラスは必要ないため、違いはありません)このルールを順守する必要があります)、プライベートなゼロ引数コンストラクターを提供することさえあります (カスタム フィールド シリアライザーのインスタンス化関数が静的ファクトリを介してそれを処理する必要があるため、これも違いはありません)。
Foo クラスがホワイトリストに登録されていないのはなぜですか? 明らかな何かを見逃したり、何かを誤解したりしましたか?
よろしくお願いいたします。