java - ¿Cómo agrego un tipo a la lista blanca de políticas de serialización de GWT?
serialization whitelist (9)
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 necesita asegurarse de que la clase implemente 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 deben tener un constructor "público, sin argumento" y (dependiendo de los requisitos) métodos de establecimiento para los campos miembros.
El serializador de GWT tiene soporte limitado de java.io.Serializable
, pero por razones de seguridad hay una lista blanca de tipos compatibles. La documentación que encontré, por ejemplo esta entrada de Preguntas frecuentes, dice que los tipos que desea serializar "deben estar incluidos en la lista blanca de política de serialización" y que la lista se genera en tiempo de compilación, pero no explica cómo decide el compilador lo que está 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
. Me sale un error al tratar de 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?
A cualquiera que tenga la misma pregunta y no encuentre respuestas previas satisfactorias ...
Estoy usando GWT con GWTController, ya que estoy usando Spring, que modifiqué como se describe en este mensaje . El mensaje explica cómo modificar GrailsRemoteServiceServlet, pero GWTController llama a 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 colocarlo en el paquete del cliente o usarlo en una interfaz de servicio simulada no era suficiente, ya que parecía que el sistema lo optimizaba.
Me pareció más fácil crear una clase que se deriva de uno de los tipos que ya se utilizan en la interfaz de servicio y pegarlo en el paquete del cliente. Nada más necesario.
public class GWTSerializableTypes extends SomeTypeInServiceInterface implements IsSerializable {
Long l;
Double d;
private GWTSerializableTypes() {}
}
En mi humilde opinión, la forma más sencilla de acceder a la lista blanca programáticamente es crear una clase similar a esta:
public class SerializableWhitelist implements IsSerializable {
String[] dummy1;
SomeOtherThingsIWishToSerialize dummy2;
}
Luego, .client
en el paquete .client
y haga referencia al servicio RPC (para que el compilador lo analice).
No pude encontrar una forma mejor de habilitar la transferencia de mapas sin parametrizar, que obviamente es lo que a veces necesita para crear servicios más genéricos ...
Hay una solución alternativa: defina una nueva clase Dummy
con campos de miembros de todos los tipos que desee que se incluyan en la serialización. A continuación, 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 async tendrá esto:
void dummy(Dummy d, AsyncCallback< Dummy> callback);
El compilador GWT recogerá esto, y como la clase Dummy
referencia a esos tipos, los incluirá en la lista blanca.
Ejemplo de clase Dummy
:
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 necesita asegurarse de que la clase implemente 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, debe marcarse como estática.
Todos los tipos específicos que incluya en su interfaz de servicio y cualquier tipo al que hagan referencia se incluirán automáticamente en la lista blanca, siempre que implementen java.io.Serializable, por ejemplo:
public String getStringForDates(ArrayList<java.util.Date> dates);
Hará que ArrayList y Date se incluyan en la lista blanca.
Se vuelve más complicado si intentas usar java.lang.Object en lugar de tipos específicos:
public Object getObjectForString(String str);
Porque el compilador no sabe qué incluir en la lista blanca. En ese caso, si los objetos no están referenciados 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.
Tuve este problema pero terminé rastreando el problema hasta 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 la excepción quede atrapada en:
@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 extremo comercial 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)
para garantizar el resultado deseado, elimine todos war/<app>/gwt/*.gwt.rpc