如何在GWT的序列化策略白名单中添加类型?

时间:2022-10-31 22:19:16

GWT's serializer has limited java.io.Serializable support, but for security reasons there is a whitelist of types it supports. The documentation I've found, for example this FAQ entry says that any types you want to serialize "must be included in the serialization policy whitelist", and that the list is generated at compile time, but doesn't explain how the compiler decides what goes on the whitelist.

GWT的序列化程序具有有限的java.io.Serializable支持,但出于安全原因,它支持的类型为白名单。我找到的文档,例如此FAQ条目表示您要序列化的任何类型“必须包含在序列化策略白名单中”,并且列表是在编译时生成的,但不解释编译器如何决定什么在白名单上。

The generated list contains a number of types that are part of the standard library, such as java.lang.String and java.util.HashMap. I get an error when trying to serialize java.sql.Date, which implements the Serializable interface, but is not on the whitelist. How can I add this type to the list?

生成的列表包含许多属于标准库的类型,例如java.lang.String和java.util.HashMap。尝试序列化java.sql.Date时出错,它实现了Serializable接口,但不在白名单中。如何将此类型添加到列表中?

9 个解决方案

#1


12  

Any specific types that you include in your service interface and any types that they reference will be automatically whitelisted, as long as they implement java.io.Serializable, eg:

您在服务界面中包含的任何特定类型以及它们引用的任何类型都将自动列入白名单,只要它们实现java.io.Serializable,例如:

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

Will result in ArrayList and Date both being included on the whitelist.

将导致ArrayList和Date都包含在白名单中。

It gets trickier if you try and use java.lang.Object instead of specific types:

如果您尝试使用java.lang.Object而不是特定类型,则会变得更加棘手:

public Object getObjectForString(String str);

Because the compiler doesn't know what to whitelist. In that case if the objects are not referenced anywhere in your service interface, you have to mark them explicitly with the IsSerializable interface, otherwise it won't let you pass them through the RPC mechanism.

因为编译器不知道白名单是什么。在这种情况下,如果对象未在服务接口中的任何位置引用,则必须使用IsSerializable接口显式标记它们,否则它将不允许您通过RPC机制传递它们。

#2


29  

There's a workaround: define a new Dummy class with member fields of all the types that you want to be included in serialization. Then add a method to your RPC interface:

有一种解决方法:使用您希望包含在序列化中的所有类型的成员字段定义一个新的Dummy类。然后在RPC接口中添加一个方法:

Dummy dummy(Dummy d);

The implementation is just this:

实现就是这样:

Dummy dummy(Dummy d) { return d; }

And the async interface will have this:

异步接口将具有以下内容:

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

The GWT compiler will pick this up, and because the Dummy class references those types, it will include them in the white list.

GWT编译器会选择它,因为Dummy类引用这些类型,它会将它们包含在白名单中。

Example Dummy class:

示例虚拟类:

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

#3


7  

The whitelist is generated by the GWT compiler and contains all the entries that are designated by the IsSerializable marker interface.

白名单由GWT编译器生成,包含IsSerializable标记接口指定的所有条目。

To add a type to the list you just need to make sure that the class implements the IsSerializable interface.

要向列表中添加类型,您只需确保该类实现IsSerializable接口。

Additionally for serialization to work correctly the class must have a default no arg constructor (constructor can be private if needed). Also if the class is an inner it must be marked as static.

此外,为了使序列化正常工作,类必须具有默认的无arg构造函数(如果需要,构造函数可以是私有的)。此外,如果类是内部,则必须将其标记为静态。

#4


2  

IMHO the simpliest way to access whitelist programmatically is to create a class similar to this:

恕我直言,以编程方式访问白名单的最简单方法是创建一个类似于这样的类:

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

Then include it in the .client package and reference from the RPC service (so it gets analyzed by the compiler).

然后将它包含在.client包中并从RPC服务引用(因此它将由编译器进行分析)。

I couldn't find a better way to enable tranfer of unparameterized maps, which is obviously what you sometimes need in order to create more generic services...

我找不到更好的方法来启用非参数化地图的转移,这显然是您有时需要创建更通用的服务...

#5


1  

The whitelist is generated by the gwt compiler and contains all the entries that are designated by the IsSerializable marker interface.

白名单由gwt编译器生成,包含IsSerializable标记接口指定的所有条目。

To add a type to the list you just need to make sure that the class implements the IsSerializable interface.

要向列表中添加类型,您只需确保该类实现IsSerializable接口。

-- Andrej

This is probably the easiest solution. The only thing to remember with this is that all the classes that you want to serialize should have "public, no-argument" constructor, and (depending upon requirements) setter methods for the member fields.

这可能是最简单的解决方案。唯一需要记住的是,您要序列化的所有类都应该具有“public,no-argument”构造函数,并且(根据需要)成员字段的setter方法。

#6


1  

to ensure the desired result delete all war/<app>/gwt/*.gwt.rpc

确保所需的结果删除所有war / / gwt / * .gwt.rpc

#7


0  

To anyone who will have the same question and doesn't find previous answers satisfactory...

对于任何会有同样问题且未找到满意答案的人来说......

I'm using GWT with GWTController, since I'm using Spring, which I modified as described in this message. The message explains how to modify GrailsRemoteServiceServlet, but GWTController calls RPC.decodeRequest() and RPC.encodeResponseForSuccess() in the same way.

我正在使用GWT和GWTController,因为我正在使用Spring,我按照此消息中的描述进行了修改。该消息解释了如何修改GrailsRemoteServiceServlet,但GWTController以相同的方式调用RPC.decodeRequest()和RPC.encodeResponseForSuccess()。

This is the final version of GWTController I'm using:

这是我正在使用的GWTController的最终版本:

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

#8


0  

I found that just putting it in the client package or using it in a dummy service interface was not sufficient as it seemed the system optimized it away.

我发现只是将它放在客户端软件包中或在虚拟服务接口中使用它是不够的,因为它似乎系统优化了它。

I found it easiest to create a class that derived from one of the types already used in the service interface and stick it in the client package. Nothing else needed.

我发现最简单的方法是创建一个派生自已在服务接口中使用的类型之一的类,并将其粘贴在客户端包中。没有别的需要。

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

#9


0  

I had this problem but ended up tracing the problem back to a line of code in my Serializable object:

我有这个问题,但最终将问题追溯到我的Serializable对象中的一行代码:

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

There were no other complaints before the exception gets caught in:

在异常被发现之前没有其他投诉:

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

And the business end of the stack trace is:

堆栈跟踪的业务端是:

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)

#1


12  

Any specific types that you include in your service interface and any types that they reference will be automatically whitelisted, as long as they implement java.io.Serializable, eg:

您在服务界面中包含的任何特定类型以及它们引用的任何类型都将自动列入白名单,只要它们实现java.io.Serializable,例如:

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

Will result in ArrayList and Date both being included on the whitelist.

将导致ArrayList和Date都包含在白名单中。

It gets trickier if you try and use java.lang.Object instead of specific types:

如果您尝试使用java.lang.Object而不是特定类型,则会变得更加棘手:

public Object getObjectForString(String str);

Because the compiler doesn't know what to whitelist. In that case if the objects are not referenced anywhere in your service interface, you have to mark them explicitly with the IsSerializable interface, otherwise it won't let you pass them through the RPC mechanism.

因为编译器不知道白名单是什么。在这种情况下,如果对象未在服务接口中的任何位置引用,则必须使用IsSerializable接口显式标记它们,否则它将不允许您通过RPC机制传递它们。

#2


29  

There's a workaround: define a new Dummy class with member fields of all the types that you want to be included in serialization. Then add a method to your RPC interface:

有一种解决方法:使用您希望包含在序列化中的所有类型的成员字段定义一个新的Dummy类。然后在RPC接口中添加一个方法:

Dummy dummy(Dummy d);

The implementation is just this:

实现就是这样:

Dummy dummy(Dummy d) { return d; }

And the async interface will have this:

异步接口将具有以下内容:

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

The GWT compiler will pick this up, and because the Dummy class references those types, it will include them in the white list.

GWT编译器会选择它,因为Dummy类引用这些类型,它会将它们包含在白名单中。

Example Dummy class:

示例虚拟类:

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

#3


7  

The whitelist is generated by the GWT compiler and contains all the entries that are designated by the IsSerializable marker interface.

白名单由GWT编译器生成,包含IsSerializable标记接口指定的所有条目。

To add a type to the list you just need to make sure that the class implements the IsSerializable interface.

要向列表中添加类型,您只需确保该类实现IsSerializable接口。

Additionally for serialization to work correctly the class must have a default no arg constructor (constructor can be private if needed). Also if the class is an inner it must be marked as static.

此外,为了使序列化正常工作,类必须具有默认的无arg构造函数(如果需要,构造函数可以是私有的)。此外,如果类是内部,则必须将其标记为静态。

#4


2  

IMHO the simpliest way to access whitelist programmatically is to create a class similar to this:

恕我直言,以编程方式访问白名单的最简单方法是创建一个类似于这样的类:

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

Then include it in the .client package and reference from the RPC service (so it gets analyzed by the compiler).

然后将它包含在.client包中并从RPC服务引用(因此它将由编译器进行分析)。

I couldn't find a better way to enable tranfer of unparameterized maps, which is obviously what you sometimes need in order to create more generic services...

我找不到更好的方法来启用非参数化地图的转移,这显然是您有时需要创建更通用的服务...

#5


1  

The whitelist is generated by the gwt compiler and contains all the entries that are designated by the IsSerializable marker interface.

白名单由gwt编译器生成,包含IsSerializable标记接口指定的所有条目。

To add a type to the list you just need to make sure that the class implements the IsSerializable interface.

要向列表中添加类型,您只需确保该类实现IsSerializable接口。

-- Andrej

This is probably the easiest solution. The only thing to remember with this is that all the classes that you want to serialize should have "public, no-argument" constructor, and (depending upon requirements) setter methods for the member fields.

这可能是最简单的解决方案。唯一需要记住的是,您要序列化的所有类都应该具有“public,no-argument”构造函数,并且(根据需要)成员字段的setter方法。

#6


1  

to ensure the desired result delete all war/<app>/gwt/*.gwt.rpc

确保所需的结果删除所有war / / gwt / * .gwt.rpc

#7


0  

To anyone who will have the same question and doesn't find previous answers satisfactory...

对于任何会有同样问题且未找到满意答案的人来说......

I'm using GWT with GWTController, since I'm using Spring, which I modified as described in this message. The message explains how to modify GrailsRemoteServiceServlet, but GWTController calls RPC.decodeRequest() and RPC.encodeResponseForSuccess() in the same way.

我正在使用GWT和GWTController,因为我正在使用Spring,我按照此消息中的描述进行了修改。该消息解释了如何修改GrailsRemoteServiceServlet,但GWTController以相同的方式调用RPC.decodeRequest()和RPC.encodeResponseForSuccess()。

This is the final version of GWTController I'm using:

这是我正在使用的GWTController的最终版本:

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

#8


0  

I found that just putting it in the client package or using it in a dummy service interface was not sufficient as it seemed the system optimized it away.

我发现只是将它放在客户端软件包中或在虚拟服务接口中使用它是不够的,因为它似乎系统优化了它。

I found it easiest to create a class that derived from one of the types already used in the service interface and stick it in the client package. Nothing else needed.

我发现最简单的方法是创建一个派生自已在服务接口中使用的类型之一的类,并将其粘贴在客户端包中。没有别的需要。

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

#9


0  

I had this problem but ended up tracing the problem back to a line of code in my Serializable object:

我有这个问题,但最终将问题追溯到我的Serializable对象中的一行代码:

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

There were no other complaints before the exception gets caught in:

在异常被发现之前没有其他投诉:

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

And the business end of the stack trace is:

堆栈跟踪的业务端是:

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)