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

Posted

技术标签:

【中文标题】如何将类型添加到 GWT 的序列化策略白名单?【英文标题】:How do I add a type to GWT's Serialization Policy whitelist? 【发布时间】:2010-09-13 09:05:13 【问题描述】:

GWT 的序列化程序对java.io.Serializable 的支持有限,但出于安全原因,它支持的类型有一个白名单。我找到的文档,例如this FAQ entry 说,您想要序列化的任何类型“必须包含在序列化策略白名单中”,并且该列表是在编译时生成的,但没有解释编译器如何决定白名单上的内容。

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

应该添加——该类还需要有一个公共的默认无参数构造函数。仅仅实现 IsSerializable 接口而没有它是不够的。经过一个小时的调试后发现了这一点:) @AdrianPetrescu 这并不完全正确。 no args 构造函数可能是私有的,但它必须在那里。此外,类本身不能是私有的,如果是内部类,它必须是静态的。并且该类可能没有最终的非静态字段。【参考方案2】:

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

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

然后将其包含在 .client 包中并从 RPC 服务引用(以便编译器对其进行分析)。

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

【讨论】:

【参考方案3】:

有一个解决方法:定义一个新的Dummy 类,其中包含要包含在序列化中的所有类型的成员字段。然后在你的 RPC 接口中添加一个方法:

Dummy dummy(Dummy d);

实现就是这样:

Dummy dummy(Dummy d)  return d; 

而且异步接口会有这个:

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

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

例如Dummy类:

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

【讨论】:

【参考方案4】:

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

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

在异常被捕获之前没有其他投诉:

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

而堆栈跟踪的业务端是:

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)

【讨论】:

【参考方案5】:

为确保所需的结果删除所有war/&lt;app&gt;/gwt/*.gwt.rpc

【讨论】:

【参考方案6】:

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

我发现最简单的方法是创建一个派生自服务接口中已使用的类型之一的类,并将其粘贴到客户端包中。不需要其他任何东西。

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

【讨论】:

【参考方案7】:

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

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

-- 安德烈

这可能是最简单的解决方案。 唯一要记住的是,您要序列化的所有类都应具有“公共、无参数”构造函数,并且(取决于要求)成员字段的 setter 方法。

【讨论】:

默认构造函数的可见性并不重要。您只需要一个任何可见性的零参数默认构造函数(即使是私有的也可以)【参考方案8】:

致任何有相同问题但对以前的答案不满意的人...

我将 GWT 与 GWTController 一起使用,因为我使用的是 Spring,我按照 in this message 的描述对其进行了修改。该消息解释了如何修改 GrailsRemoteServiceServlet,但 GWTController 调用 RPC.decodeRequest() 和 RPC.encodeResponseForSuccess() 的方式相同。

这是我正在使用的 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;
 

【讨论】:

【参考方案9】:

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

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

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

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

public Object getObjectForString(String str);

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

【讨论】:

java.lang.Double 出现错误,所以很清楚 我收到 java.lang.Double 和其他我无法编辑的类型的错误。那么我将如何向它们添加 IsSerializable 呢?你能举个例子吗?

以上是关于如何将类型添加到 GWT 的序列化策略白名单?的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 对列入白名单的链接说“域未列入白名单”

如何设置UAC白名单

在 Firefox 中使用 csp sha-256 将内联脚本列入白名单

win2008服务器 防火墙如何加ip地址的白名单

“阿里云”ECS服务器怎么设置IP白名单?

Win8如何给UAC添加白名单使其信任某个程序?