如何在GWT的序列化政策白名单中添加类型?
GWT的序列化器对java.io.Serializable的支持有限,但是出于安全原因,它支持一个白名单。我找到的文档(例如此FAQ条目)说,我们要序列化的任何类型"都必须包含在序列化策略白名单中",并且该列表是在编译时生成的,但没有说明编译器如何决定白名单上的内容。
生成的列表包含许多标准库的类型,例如java.lang.String和java.util.HashMap。尝试序列化实现了Serializable接口的java.sql.Date时出现错误,但不在白名单上。如何将这种类型添加到列表中?
解决方案
白名单由GWT编译器生成,并且包含IsSerializable标记接口指定的所有条目。
要将类型添加到列表中,只需确保该类实现IsSerializable接口。
此外,为了使序列化正常工作,该类必须具有默认的no arg构造函数(如果需要,构造函数可以是私有的)。同样,如果该类是内部类,则必须将其标记为静态。
只要我们实现了java.io.Serializable,我们在服务界面中包括的任何特定类型及其引用的任何类型都将自动列入白名单,例如:
public String getStringForDates(ArrayList<java.util.Date> dates);
将导致ArrayList和Date都包含在白名单中。
如果尝试使用java.lang.Object而不是特定类型,则将变得更加棘手:
public Object getObjectForString(String str);
因为编译器不知道将哪些内容列入白名单。在这种情况下,如果未在服务接口中的任何地方引用对象,则必须使用IsSerializable接口显式标记它们,否则,将无法通过RPC机制传递它们。
有一种解决方法:使用要包含在序列化中的所有类型的成员字段定义一个新的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;
}
恕我直言,以编程方式访问白名单的最简单方法是创建一个类似于以下内容的类:
public class SerializableWhitelist implements IsSerializable {
String[] dummy1;
SomeOtherThingsIWishToSerialize dummy2;
}
然后将其包含在.client包中,并从RPC服务中进行引用(以便由编译器进行分析)。
我找不到更好的方法来启用非参数化映射的传输,这显然是有时我们需要创建更多通用服务所需要的...
为了确保获得期望的结果,请删除所有war / <app> / gwt / *。gwt.rpc
对于将有相同问题且以前的答案不满意的任何人...
我将GWT和GWTController一起使用,因为我使用的是Spring,我已按照此消息中的说明进行了修改。该消息说明了如何修改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;
}
}
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
这可能是最简单的解决方案。
唯一要记住的是,我们要序列化的所有类都应具有"公共,无参数"构造函数,以及(取决于要求)成员字段的setter方法。

