GWT 的序列化程序对 java.io.Serialized
支持有限,但出于安全原因,它支持的类型有一个白名单。 我找到的文档,例如此常见问题解答条目 表示您想要序列化的任何类型“必须包含在序列化策略白名单中”,并且该列表是在编译时生成的,但没有解释编译器如何决定白名单上的内容。
生成的列表包含许多属于标准库的类型,例如 java.lang.String 和 java.util.HashMap。 我在尝试序列化 java.sql.Date
时遇到错误,它实现了 Serialized
接口,但不在白名单中。 如何将此类型添加到列表中?
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.
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?
发布评论
评论(9)
有一个解决方法:定义一个新的
Dummy
类,其中包含要包含在序列化中的所有类型的成员字段。 然后向您的 RPC 接口添加一个方法:实现就是这样:
异步接口将具有以下内容:
GWT 编译器将选择此方法,并且由于
Dummy
类引用这些类型,因此它将包括他们在白名单中。示例
Dummy
类: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:The implementation is just this:
And the async interface will have this:
The GWT compiler will pick this up, and because the
Dummy
class references those types, it will include them in the white list.Example
Dummy
class:您在服务接口中包含的任何特定类型以及它们引用的任何类型都将自动列入白名单,只要它们实现 java.io.Serialized,例如:
将导致 ArrayList 和 Date 都包含在白名单中。
如果您尝试使用 java.lang.Object 而不是特定类型,事情会变得更加棘手:
因为编译器不知道将哪些内容列入白名单。 在这种情况下,如果服务接口中的任何地方都没有引用这些对象,则必须使用 IsSerialized 接口显式标记它们,否则它不会让您通过 RPC 机制传递它们。
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:
Will result in ArrayList and Date both being included on the whitelist.
It gets trickier if you try and use java.lang.Object instead of specific types:
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.
白名单由 GWT 编译器生成,包含由 IsSerialized 标记接口指定的所有条目。
要将类型添加到列表中,您只需确保该类实现 IsSerializable 接口。
此外,为了使序列化正常工作,类必须有一个默认的无参数构造函数(如果需要,构造函数可以是私有的)。 此外,如果该类是内部类,则必须将其标记为静态。
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.
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.
恕我直言,以编程方式访问白名单的最简单方法是创建一个与此类似的类:
然后将其包含在
.client
包中并从 RPC 服务引用(以便编译器对其进行分析)。我找不到更好的方法来启用非参数化地图的传输,这显然是您有时需要创建更通用的服务......
IMHO the simpliest way to access whitelist programmatically is to create a class similar to this:
Then include it in the
.client
package and reference from the RPC service (so it gets analyzed by the compiler).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...
这可能是最简单的解决方案。
唯一要记住的是,您想要序列化的所有类都应该具有“公共、无参数”构造函数,以及(根据要求)成员字段的 setter 方法。
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.
为了确保获得所需的结果,请删除所有
war//gwt/*.gwt.rpc
to ensure the desired result delete all
war/<app>/gwt/*.gwt.rpc
对于任何有同样问题并且没有找到令人满意的答案的人...
我将 GWT 与 GWTController 一起使用,因为我使用的是 Spring,我按照 在此消息中。 该消息解释了如何修改 GrailsRemoteServiceServlet,但 GWTController 以相同的方式调用 RPC.decodeRequest() 和 RPC.encodeResponseForSuccess()。
这是我正在使用的 GWTController 的最终版本:
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.
This is the final version of GWTController I'm using:
我发现仅仅将其放入客户端包中或在虚拟服务接口中使用它是不够的,因为系统似乎将其优化掉了。
我发现最简单的方法是创建一个派生自服务接口中已使用的类型之一的类,并将其粘贴到客户端包中。 不需要其他任何东西。
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.
我遇到了这个问题,但最终将问题追溯到可序列化对象中的一行代码:
在异常被捕获之前没有其他抱怨:
堆栈跟踪的业务端是:
I had this problem but ended up tracing the problem back to a line of code in my Serializable object:
There were no other complaints before the exception gets caught in:
And the business end of the stack trace is: