Considerare una classe immutabile Foo (un POJO costituito da un ID e un nome), che deve essere serializzata in modo che i dati vengano inviati dal server al client.Edizione di serializzazione campo personalizzata GWT
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.
. . .
}
di istanze di un oggetto Foo avviene attraverso la funzione di fabbrica statica e poiché non v'è alcun costruttore zero args immutabile dell'oggetto.
Considera anche una barra di classe immutabile che contiene un membro dati Foo e implementa il modello Builder per la sua creazione di istanze (omesso dallo snippet poiché è irrilevante per il problema).
public final class Bar
{
private final Foo m_foo;
. . .
private Bar(final Builder builder)
{
. . .
}
public static Builder createBuilder()
{
return new Builder();
}
}
Dopo aver valutato le mie scelte per quanto riguarda il modo in cui devono serializzare l'oggetto senza rimuovere la sua immutabilità aggiungendo o togliendo le zero-args costruttori per il bene di serializzazione ho concluso al fatto che avevo bisogno di implementare un CustomFieldSerializer (per entrambi il client e il server).
Ho seguito le linee guida scritte nell'articolo Server Communication di GWT e ho implementato il mio CustomFieldSerializer come illustrato di seguito.
// 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);
}
}
Dal momento che la barra di classe contiene un oggetto Foo che deve essere serializzato sono andato su e realizzato un altro set di CustomFieldSerializers, questa volta per la classe Foo seguendo lo stesso schema, sia per il client e il server.
Il problema sorge quando si verifica la serializzazione per la classe bar e, in particolare, a questo punto:
public static void serialize(final SerializationStreamWriter streamWriter, final Bar instance)
throws SerializationException
{
// . . .
streamWriter.writeObject(instance.getFoo());
}
Il messaggio di eccezione che ottengo è il seguente:
[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.
Sembra che writeObject() non può serializzare l'oggetto di tipo Foo perché la classe Foo non appartiene agli elementi autorizzati, anche se sono stati forniti serializzatori personalizzati sia per il client che per il server.
ho sempre potuto saltare il writeObject() invocazione e chiamare writeInt() & WriteString() per i membri di dati di ogni Foo (che sta lavorando bene), ma io preferirei di gran lunga avere writeObject() lavorare. La soluzione che ho proposto è altamente soggetta a errori di manutenzione poiché qualsiasi modifica nella classe Foo in futuro deve riflettersi sia sui serializzatori di Foo (ovvio) che sui serializzatori di Bar (non così ovvio).
ho provato praticamente tutto quello che ho trovato in rete, di attuare il interfaccia IsSerializable su entrambi i Foo e Bar (non ha fatto alcuna differenza e non dovrebbe fare alcuna differenza in quanto le classi AFAIK che forniscono la loro i propri serializzatori personalizzati non devono rispettare questa regola) e persino fornire un costruttore privato di zero-arg (che non dovrebbe fare alcuna differenza in quanto le funzioni di istanziazione del serializzatore del campo personalizzato dovrebbero occuparsene attraverso le fabbriche statiche).
Perché la classe Foo non è autorizzata? Ho perso qualcosa di ovvio o ho interpretato male qualcosa?
Grazie per il vostro tempo in anticipo.
Punto di risposta. Sono assolutamente d'accordo con te sul fatto che l'intero scenario sia completamente confuso. Qualsiasi classe che fornisca classi di serializzazione del campo personalizzate dovrebbe essere aggiunta automaticamente agli oggetti autorizzati; l'attuale implementazione impone agli sviluppatori di hackerare facilmente il problema o aggiungere un ulteriore livello di complessità al proprio sistema. –
Penso che la verità sia leggermente più semplice di questa risposta suggerisce. Innanzitutto, i campi 'final' vengono ignorati (archiviati come http://code.google.com/p/google-web-toolkit/issues/detail?id=1054), e quindi non possono essere inviati sul filo quando il suo tipo di proprietario viene inviato, indipendentemente dal serializzatore personalizzato, dal momento che in teoria potrebbe chiamare qualsiasi codice (cioè è un problema di blocco difficile per risolvere i possibili tipi). Di conseguenza, aggiungere un nuovo metodo riferito a quel tipo è sufficiente per contrassegnarlo per l'inclusione. Rimuovi il 'final' (o ottieni 1054 riparato) e questo metodo non è necessario. –
@ColinAlworth in realtà hai ragione al 100% – jusio