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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/138099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:45:22  来源:igfitidea点击:

How do I add a type to GWT's Serialization Policy whitelist?

javaserializationgwtwhitelist

提问by user3562

GWT's serializer has limited java.io.Serializablesupport, but for security reasons there is a whitelist of types it supports. The documentation I've found, for example this FAQ entrysays 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.Stringand java.util.HashMap. I get an error when trying to serialize java.sql.Date, which implements the Serializableinterface, but is not on the whitelist. How can I add this type to the list?

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

采纳答案by rustyshelf

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 机制传递它们。

回答by pfranza

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.

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

回答by rustyshelf

There's a workaround: define a new Dummyclass 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 Dummyclass references those types, it will include them in the white list.

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

Example Dummyclass:

示例Dummy类:

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

回答by rustyshelf

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 .clientpackage 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...

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

回答by rustyshelf

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

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

回答by Domchi

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

回答by Asif Sheikh

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

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

-- Andrej

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

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

——安德烈

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.

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

回答by Glenn

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() {}
}

回答by Dominic Tracey

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)