web-dev-qa-db-fra.com

Comment ajouter un type à la liste blanche de stratégie de sérialisation de GWT?

Le sérialiseur de GWT a un support Java.io.Serializable limité, mais pour des raisons de sécurité, il existe une liste blanche des types qu'il prend en charge. La documentation que j'ai trouvée, par exemple cette FAQ entrée indique que tous les types que vous souhaitez sérialiser "doivent être inclus dans la liste blanche de règles de sérialisation" et que la liste est générée au moment de la compilation. , mais n'explique pas comment le compilateur décide ce qui se passe sur la liste blanche.

La liste générée contient un certain nombre de types faisant partie de la bibliothèque standard, tels que Java.lang.String et Java.util.HashMap. Je reçois une erreur en essayant de sérialiser Java.sql.Date, qui implémente l'interface Serializable, mais ne figure pas dans la liste blanche. Comment puis-je ajouter ce type à la liste?

35
user3562

Tous les types spécifiques que vous incluez dans votre interface de service et tous les types auxquels ils font référence seront automatiquement ajoutés à la liste blanche, à condition qu'ils implémentent Java.io.Serializable, par exemple:

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

Les éléments ArrayList et Date figureront tous deux sur la liste blanche.

Cela devient plus compliqué si vous essayez d'utiliser Java.lang.Object au lieu de types spécifiques:

public Object getObjectForString(String str);

Parce que le compilateur ne sait pas quoi ajouter à la liste blanche. Dans ce cas, si les objets ne sont référencés nulle part dans votre interface de service, vous devez les marquer explicitement avec l'interface IsSerializable, sinon cela ne vous permettra pas de les transmettre via le mécanisme RPC.

11
rustyshelf

Il existe une solution de contournement: définissez une nouvelle classe Dummy avec des champs membres de tous les types à inclure dans la sérialisation. Ajoutez ensuite une méthode à votre interface RPC:

Dummy dummy(Dummy d);

L'implémentation est juste ceci:

Dummy dummy(Dummy d) { return d; }

Et l'interface asynchrone aura ceci:

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

Le compilateur GWT le détectera et, comme la classe Dummy fait référence à ces types, il les inclura dans la liste blanche.

Exemple Dummy class:

public class Dummy implements IsSerializable {
    private Java.sql.Date d;
}
30
Andrej

La liste blanche est générée par le compilateur GWT et contient toutes les entrées désignées par l'interface de marqueur IsSerializable. 

Pour ajouter un type à la liste, vous devez simplement vous assurer que la classe implémente l'interface IsSerializable.

De plus, pour que la sérialisation fonctionne correctement, la classe doit avoir un constructeur sans argument par défaut (le constructeur peut être privé si nécessaire). De plus, si la classe est une classe interne, elle doit être marquée comme statique.

7
pfranza

IMHO le moyen le plus simple d'accéder par programme à la liste blanche est de créer une classe similaire à celle-ci:

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

Ensuite, incluez-le dans le package .client et dans la référence du service RPC (afin qu’il soit analysé par le compilateur).

Je ne pouvais pas trouver un meilleur moyen d'activer le transfert de cartes non paramétrées, ce qui est évidemment ce dont vous avez parfois besoin pour créer des services plus génériques ...

2
petr

pour assurer le résultat souhaité supprimer tout war/<app>/gwt/*.gwt.rpc

1
user185891

La liste blanche est générée par le compilateur gwt et contient toutes les entrées désignées par l'interface de marqueur IsSerializable. 

Pour ajouter un type à la liste, vous devez simplement vous assurer que la classe implémente l'interface IsSerializable.

- Andrej

C’est probablement la solution la plus simple. La seule chose à retenir est que toutes les classes que vous souhaitez sérialiser doivent avoir un constructeur "public, sans argument" et des méthodes de définition (selon les besoins) champs membres.

1
Asif Sheikh

À quiconque aura la même question et ne trouvera pas les réponses précédentes satisfaisantes ...

J'utilise GWT avec GWTController, car j'utilise Spring, que j'ai modifié comme décrit dans ce message . Le message explique comment modifier GrailsRemoteServiceServlet, mais GWTController appelle RPC.decodeRequest () et RPC.encodeResponseForSuccess () de la même manière.

Ceci est la version finale de GWTController que j'utilise:

/**
 * 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;
 }
}
0
Domchi

J'ai eu ce problème, mais j'ai fini par le remonter jusqu'à une ligne de code dans mon objet Serializable:

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

Il n'y a pas eu d'autres plaintes avant que l'exception ne soit prise au piège:

 @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);
  }

Et la fin commerciale de la trace de pile est la suivante:

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)
0
Dominic Tracey

J'ai constaté que le simple fait de l'insérer dans le package client ou de l'utiliser dans une interface de service factice n'était pas suffisant, car il semblait que le système l'avait optimisé.

J'ai trouvé plus facile de créer une classe dérivée de l'un des types déjà utilisés dans l'interface de service et de la coller dans le package client. Rien d'autre nécessaire.

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