Pregunta

El serializador de GWT tiene soporte limitado para java.io.Serializable , pero por razones de seguridad hay una lista blanca de tipos que admite. La documentación que he encontrado, por ejemplo, esta entrada de Preguntas frecuentes dice que cualquier tipo que desee serializar " debe incluirse en la lista blanca de políticas de serialización " ;, y que la lista se genera en el momento de la compilación, pero no explica cómo el compilador decide lo que va en la lista blanca.

La lista generada contiene varios tipos que forman parte de la biblioteca estándar, como java.lang.String y java.util.HashMap . Recibo un error al intentar serializar java.sql.Date , que implementa la interfaz Serializable , pero no está en la lista blanca. ¿Cómo puedo agregar este tipo a la lista?

¿Fue útil?

Solución

Cualquier tipo específico que incluya en su interfaz de servicio y cualquier tipo al que hagan referencia se incluirá automáticamente en la lista blanca, siempre que implementen java.io.Serializable, por ejemplo:

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

Resultará en que ArrayList y Date se incluyan en la lista blanca.

Se vuelve más complicado si intentas y usas java.lang.Object en lugar de tipos específicos:

public Object getObjectForString(String str);

Porque el compilador no sabe qué hacer en la lista blanca. En ese caso, si no se hace referencia a los objetos en ninguna parte de su interfaz de servicio, debe marcarlos explícitamente con la interfaz IsSerializable, de lo contrario no le permitirá pasarlos a través del mecanismo RPC.

Otros consejos

Hay una solución alternativa: defina una nueva clase Dummy con campos miembro de todos los tipos que desee incluir en la serialización. Luego agregue un método a su interfaz RPC:

Dummy dummy(Dummy d);

La implementación es solo esto:

Dummy dummy(Dummy d) { return d; }

Y la interfaz asíncrona tendrá esto:

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

El compilador GWT lo recogerá y, como la clase Dummy hace referencia a esos tipos, los incluirá en la lista blanca.

Ejemplo Dummy class:

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

La lista blanca es generada por el compilador GWT y contiene todas las entradas designadas por la interfaz del marcador IsSerializable.

Para agregar un tipo a la lista, solo debes asegurarte de que la clase implementa la interfaz IsSerializable.

Además, para que la serialización funcione correctamente, la clase debe tener un constructor no arg predeterminado (el constructor puede ser privado si es necesario). Además, si la clase es interna, se debe marcar como estática.

En mi humilde opinión, la forma más sencilla de acceder a la lista blanca mediante programación es crear una clase similar a esta:

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

Luego inclúyalo en el paquete .client y la referencia del servicio RPC (para que el compilador lo analice).

No pude encontrar una mejor manera de habilitar la transferencia de mapas sin parámetros, que obviamente es lo que a veces se necesita para crear más servicios genéricos ...

  

La lista blanca es generada por el compilador gwt y contiene todas las entradas designadas por la interfaz del marcador IsSerializable.

     

Para agregar un tipo a la lista, solo debes asegurarte de que la clase implementa la interfaz IsSerializable.

     

- Andrej

Esta es probablemente la solución más fácil. Lo único que debe recordar con esto es que todas las clases que desea serializar deberían tener " public, no-argument " constructor y (según los requisitos) métodos de establecimiento para los campos de miembros.

para garantizar el resultado deseado, elimine todos war/<app>/gwt/*.gwt.rpc

A cualquiera que tenga la misma pregunta y que no encuentre satisfactorias las respuestas anteriores ...

Estoy usando GWT con GWTController, ya que estoy usando Spring, que modifiqué como se describe en en este mensaje . El mensaje explica cómo modificar GrailsRemoteServiceServlet, pero GWTController llama RPC.decodeRequest () y RPC.encodeResponseForSuccess () de la misma manera.

Esta es la versión final de GWTController que estoy 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;
 }
}

Descubrí que simplemente ponerlo en el paquete del cliente o usarlo en una interfaz de servicio ficticia no era suficiente, ya que parecía que el sistema lo había optimizado.

Me resultó más fácil crear una clase derivada de uno de los tipos ya utilizados en la interfaz de servicio y pegarla en el paquete del cliente. Nada más se necesita.

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

Tuve este problema pero terminé rastreando el problema de nuevo a una línea de código en mi objeto Serializable:

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

No hubo otras quejas antes de que se detectara la excepción:

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

Y el final del negocio del seguimiento de la pila es:

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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top