包含类型化成员的参数化 AutoBean 类型
问题
有没有办法使用 AutoBean 框架反序列化 JSON,以便生成的 bean 具有影响其一个或多个成员的类型的类型参数?
带有 JSON 结果的后台
RPC
我正在使用 GWT (RequestBuilder
) 来执行 RPC 请求。返回的 JSON 有效负载采用以下形式:
{
"resultSet": [{...}, {...}, ...], // items requested; say, items 150-160
"totalCount": 15330 // total matching items in DB
}
resultSet
中的对象的类型有所不同,具体取决于我调用的特定 RPC。
AutoBean 接口
我想使用 AutoBean 反序列化此 JSON。我尝试如下表示该对象:
interface RpcResults<T> {
List<T> getResultSet();
void setResultSet(List<T> resultSet);
int getTotalCount();
void setTotalCount(int totalCount);
}
我还创建了适当的接口来表示 resultSet
中可能存在的每种类型的对象。最后,我设置了对 AutoBeanCodex.decode 的适当调用。
运行代码
尝试在开发模式下运行此代码会导致控制台中出现以下堆栈跟踪:
19:44:23.791 [ERROR] [xcbackend] Uncaught exception escaped
java.lang.IllegalArgumentException: The AutoBeanFactory cannot create a java.lang.Object
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.push(AutoBeanCodex.java:240)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.decode(AutoBeanCodex.java:50)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.visitCollectionProperty(AutoBeanCodex.java:83)
at com.citrix.xenclient.backend.client.json.RpcResultsAutoBean.traverseProperties(RpcResultsAutoBean.java:100)
at com.google.gwt.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:153)
at com.google.gwt.autobean.shared.impl.AbstractAutoBean.accept(AbstractAutoBean.java:112)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.decode(AutoBeanCodex.java:51)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:505)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:521)
at com.citrix.xenclient.backend.client.services.JSONResponseResultSetHandler.onResponseReceived(JSONResponseResultSetHandler.java:51)
at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:287)
at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:395)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:326)
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:207)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:126)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:214)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:281)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:531)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:352)
at java.lang.Thread.run(Thread.java:636)
根据此堆栈跟踪,我的预感如下:
- 类型擦除使得看起来
RpcResults.getResultSet() 返回一个原始的
List
。 - AutoBean 反序列化器尝试为
resultSet
中的每个项目创建Object
实例。 - 再次失败
问题
我是否在 AutoBean API 中缺少一些可以让我轻松完成此操作的东西?如果不是,是否有我应该调查的明显攻击点?对于我正在做的事情,是否有更明智的替代方案(除了我已经在使用的 JSONParser 和 JavaScriptObject 之外)?
Question
Is there any way to deserialize JSON using the AutoBean framework such that the resulting bean has a type parameter that affects the type of one or more of its members?
Background
RPC with JSON results
I'm using GWT (RequestBuilder
) to perform RPC requests. The JSON payload returned is of the following form:
{
"resultSet": [{...}, {...}, ...], // items requested; say, items 150-160
"totalCount": 15330 // total matching items in DB
}
The objects in resultSet
vary in type depending on the specific RPC I'm calling.
AutoBean interface
I'd like to deserialize this JSON using AutoBean. I'm trying to represent this object as follows:
interface RpcResults<T> {
List<T> getResultSet();
void setResultSet(List<T> resultSet);
int getTotalCount();
void setTotalCount(int totalCount);
}
I've also created appropriate interfaces representing each type of object that could exist within resultSet
. Finally, I set up the appropriate call to AutoBeanCodex.decode
.
Running the code
Attempting to run this code in development mode causes the following stack trace to appear in the console:
19:44:23.791 [ERROR] [xcbackend] Uncaught exception escaped
java.lang.IllegalArgumentException: The AutoBeanFactory cannot create a java.lang.Object
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.push(AutoBeanCodex.java:240)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.decode(AutoBeanCodex.java:50)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.visitCollectionProperty(AutoBeanCodex.java:83)
at com.citrix.xenclient.backend.client.json.RpcResultsAutoBean.traverseProperties(RpcResultsAutoBean.java:100)
at com.google.gwt.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:153)
at com.google.gwt.autobean.shared.impl.AbstractAutoBean.accept(AbstractAutoBean.java:112)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.decode(AutoBeanCodex.java:51)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:505)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:521)
at com.citrix.xenclient.backend.client.services.JSONResponseResultSetHandler.onResponseReceived(JSONResponseResultSetHandler.java:51)
at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:287)
at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:395)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:326)
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:207)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:126)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:214)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:281)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:531)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:352)
at java.lang.Thread.run(Thread.java:636)
Based on this stack trace, my hunch is the following:
- Type erasure makes it seem that
RpcResults.getResultSet()
is returning a rawList
. - The AutoBean deserialiser attempts to create
Object
instances for each item inresultSet
. - Failure
Question again
Am I missing something in the AutoBean API that will allow me to do this easily? If not, is there an obvious point of attack I should look into? Is there a more sensible alternative for what I'm doing (other than JSONParser and JavaScriptObject, which I'm already using)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于 Java 类型擦除,这并不简单。类型
T
在运行时不存在,已被擦除为Object
以代替任何其他下限。 AutoBeanCodex 需要类型信息才能具体化传入 json 有效负载的元素。此类型信息通常由 AutoBean 实现提供,但由于T
擦除,它只知道它包含一个List
如果您可以在运行时提供类文字,则可以将 getter 声明为
Splittable getResultSet()
,并通过调用AutoBeanCodex.decode(autoBeanFactory, SomeInterfaceType.class, getResultSet().get(index))
。通过使用类别
,您可以添加; AutoBean 接口的 T getResultAs(Classclazz, int index)
方法。这看起来像:This is not simple, due to Java type erasure. The type
T
does not exist at runtime, having been erased toObject
in lieu of any other lower bound. The AutoBeanCodex requires type information in order to reify the elements of the incoming json payload. This type information is usually provided by the AutoBean implementation, but due to theT
erasure, all it knows is that it contains aList<Object>
.If you can provide a class literal at runtime, the getter could be declared as
Splittable getResultSet()
and the individual elements of the list reified by callingAutoBeanCodex.decode(autoBeanFactory, SomeInterfaceType.class, getResultSet().get(index))
. By using aCategory
, you could add a<T> T getResultAs(Class<T> clazz, int index)
method to the AutoBean interface. This would look something like:尝试重写特定于对象的接口中的 .getResultSet() 和 .setResultSet() 方法:
以下测试适用于我 (GWT 2.3.0):
删除 ThingPage 接口中的重写将会破坏它。
Try overriding the .getResultSet() and .setResultSet() methods in your object-specific interfaces:
The following test works for me (GWT 2.3.0):
Removing the overrides in the ThingPage interface will break it.