Domanda

Il serializzatore di GWT ha un supporto java.io.Serializable limitato, ma per motivi di sicurezza esiste una lista bianca di tipi che supporta. La documentazione che ho trovato, ad esempio questa voce FAQ afferma che tutti i tipi che si desidera serializzare " devono essere inclusi nella whitelist dei criteri di serializzazione " ;, e che l'elenco viene generato in fase di compilazione, ma non spiega come il compilatore decide cosa succede nella whitelist.

L'elenco generato contiene un numero di tipi che fanno parte della libreria standard, come java.lang.String e java.util.HashMap . Ricevo un errore quando provo a serializzare java.sql.Date , che implementa l'interfaccia serializzabile , ma non è nella lista bianca. Come posso aggiungere questo tipo all'elenco?

È stato utile?

Soluzione

Qualsiasi tipo specifico che includi nell'interfaccia del servizio e qualsiasi tipo a cui fanno riferimento verrà automaticamente inserito nella whitelist, a condizione che implementino java.io.Serializable, ad esempio:

public String getStringForDates(ArrayList<java.util.Date> dates);

Ciò comporterà che ArrayList e Date siano entrambi inclusi nella whitelist.

Diventa più complicato se cerchi di usare java.lang.Object invece di tipi specifici:

public Object getObjectForString(String str);

Perché il compilatore non sa cosa inserire nella whitelist. In tal caso, se agli oggetti non viene fatto riferimento in nessun punto dell'interfaccia del servizio, è necessario contrassegnarli in modo esplicito con l'interfaccia IsSerializable, altrimenti non sarà possibile passarli attraverso il meccanismo RPC.

Altri suggerimenti

Esiste una soluzione alternativa: definire una nuova classe Dummy con campi membri di tutti i tipi che si desidera includere nella serializzazione. Quindi aggiungere un metodo all'interfaccia RPC:

Dummy dummy(Dummy d);

L'implementazione è proprio questa:

Dummy dummy(Dummy d) { return d; }

E l'interfaccia asincrona avrà questo:

void dummy(Dummy d, AsyncCallback< Dummy> callback);

Il compilatore GWT lo prenderà in considerazione e poiché la classe Dummy fa riferimento a quei tipi, li includerà nella lista bianca.

Esempio Dummy class:

public class Dummy implements IsSerializable {
    private java.sql.Date d;
}

La whitelist viene generata dal compilatore GWT e contiene tutte le voci designate dall'interfaccia del marker IsSerializable.

Per aggiungere un tipo all'elenco devi solo assicurarti che la classe implementi l'interfaccia IsSerializable.

Inoltre, affinché la serializzazione funzioni correttamente, la classe deve avere un costruttore no arg predefinito (il costruttore può essere privato se necessario). Inoltre, se la classe è interna, deve essere contrassegnata come statica.

IMHO il modo più semplice per accedere alla whitelist a livello di codice è creare una classe simile a questa:

public class SerializableWhitelist implements IsSerializable {
    String[] dummy1;
    SomeOtherThingsIWishToSerialize dummy2;
}

Quindi includilo nel pacchetto .client e riferimento dal servizio RPC (quindi viene analizzato dal compilatore).

Non sono riuscito a trovare un modo migliore per consentire il trasferimento di mappe non parametrizzate, che è ovviamente ciò di cui hai bisogno a volte per creare servizi più generici ...

  

La whitelist viene generata dal compilatore gwt e contiene tutte le voci designate dall'interfaccia del marker IsSerializable.

     

Per aggiungere un tipo all'elenco devi solo assicurarti che la classe implementi l'interfaccia IsSerializable.

     

- Andrej

Questa è probabilmente la soluzione più semplice. L'unica cosa da ricordare è che tutte le classi che si desidera serializzare dovrebbero avere "pubblico, nessun argomento" costruttore e (a seconda delle esigenze) metodi setter per i campi membro.

per garantire il risultato desiderato, eliminare tutto war/<app>/gwt/*.gwt.rpc

Per chiunque abbia la stessa domanda e non trovi soddisfacenti le risposte precedenti ...

Sto usando GWT con GWTController, poiché sto usando Spring, che ho modificato come descritto in questo messaggio . Il messaggio spiega come modificare GrailsRemoteServiceServlet, ma GWTController chiama RPC.decodeRequest () e RPC.encodeResponseForSuccess () allo stesso modo.

Questa è la versione finale di GWTController che sto usando:

/**
 * Used to instantiate GWT server in Spring context.
 *
 * Original version from <a href="http://docs.google.com/Doc?docid=dw2zgx2_25492p5qxfq&hl=en">this tutorial</a>.
 * 
 * ...fixed to work as explained <a href="http://blog.js-development.com/2009/09/gwt-meets-spring.html">in this tutorial</a>.
 * 
 * ...and then fixed to use StandardSerializationPolicy as explained in
 * <a href="http://markmail.org/message/k5j2vni6yzcokjsw">this message</a> to allow
 * using Serializable instead of IsSerializable in model.
 */
public class GWTController extends RemoteServiceServlet implements Controller, ServletContextAware {

 // Instance fields

 private RemoteService remoteService;

 private Class<? extends RemoteService> remoteServiceClass;

 private ServletContext servletContext;

 // Public methods

 /**
  * Call GWT's RemoteService doPost() method and return null.
  * 
  * @param request
  *            The current HTTP request
  * @param response
  *            The current HTTP response
  * @return A ModelAndView to render, or null if handled directly
  * @throws Exception
  *             In case of errors
  */
 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
  doPost(request, response);
  return null; // response handled by GWT RPC over XmlHttpRequest
 }

 /**
  * Process the RPC request encoded into the payload string and return a string that encodes either the method return
  * or an exception thrown by it.
  * 
  * @param payload
  *            The RPC payload
  */
 public String processCall(String payload) throws SerializationException {
  try {
   RPCRequest rpcRequest = RPC.decodeRequest(payload, this.remoteServiceClass, this);

   // delegate work to the spring injected service
   return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
  } catch (IncompatibleRemoteServiceException e) {
   return RPC.encodeResponseForFailure(null, e);
  }
 }

 /**
  * Setter for Spring injection of the GWT RemoteService object.
  * 
  * @param RemoteService
  *            The GWT RemoteService implementation that will be delegated to by the {@code GWTController}.
  */
 public void setRemoteService(RemoteService remoteService) {
  this.remoteService = remoteService;
  this.remoteServiceClass = this.remoteService.getClass();
 }

 @Override
 public ServletContext getServletContext() {
  return servletContext;
 }

 public void setServletContext(ServletContext servletContext) {
  this.servletContext = servletContext;
 }
}

Ho scoperto che inserirlo nel pacchetto client o utilizzarlo in un'interfaccia di servizio fittizia non era sufficiente in quanto sembrava che il sistema lo avesse ottimizzato.

Ho trovato più semplice creare una classe derivata da uno dei tipi già utilizzati nell'interfaccia del servizio e incollarla nel pacchetto client. Nient'altro necessario.

public class GWTSerializableTypes extends SomeTypeInServiceInterface implements IsSerializable {
    Long l;
    Double d;
    private GWTSerializableTypes() {}
}

Ho avuto questo problema, ma ho finito per rintracciarlo su una riga di codice nel mio oggetto serializzabile:

Logger.getLogger(this.getClass().getCanonicalName()).log(Level.INFO, "Foo");

Non ci sono stati altri reclami prima che l'eccezione venisse catturata:

 @Override
  protected void serialize(Object instance, String typeSignature)
      throws SerializationException {
    assert (instance != null);

    Class<?> clazz = getClassForSerialization(instance);

    try {
      serializationPolicy.validateSerialize(clazz);
    } catch (SerializationException e) {
      throw new SerializationException(e.getMessage() + ": instance = " + instance);
    }
    serializeImpl(instance, clazz);
  }

E la fine dell'attività della traccia dello stack è:

com.google.gwt.user.client.rpc.SerializationException: Type 'net.your.class' 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.: instance = net.your.class@9c7edce
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:619)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top