考虑一个不可变类 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 对象的实例化通过静态工厂函数发生,并且由于对象是不可变的,因此没有零参数构造函数。
考虑一个不可变的类 Bar ,它包含一个数据成员 Foo 并为其实例化实现了 Builder 模式(从代码片段中省略,因为它与问题无关)。
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.
似乎writeObject()无法序列化 Foo 类型的对象,因为 Foo 类不属于白名单项,即使客户端和服务器都提供了自定义序列化程序。
我总是可以跳过writeObject()调用并为每个 Foo 的数据成员调用writeInt()和writeString()(运行良好),但我更愿意让writeObject()工作。我提出的解决方案很容易出现维护错误,因为将来 Foo 类的任何更改都必须反映在 Foo 的序列化程序(显而易见)和 Bar 的序列化程序(不太明显)上。
我已经尝试了几乎可以在网上找到的任何东西,从在 Foo 和 Bar 上实现isSerializable接口(没有任何区别,也不应该有任何区别,因为提供自己的自定义序列化程序的 AFAIK 类不需要遵守这条规则),甚至提供一个私有的零参数构造函数(这也不应该有任何区别,因为自定义字段序列化程序的实例化函数应该通过静态工厂处理这个问题)。
为什么 Foo 类没有列入白名单?我是否遗漏了一些明显的东西或误解了一些东西?
提前感谢您的时间。