Gwt 包含类型化成员的参数化自动bean类型 问题:
是否有任何方法可以使用AutoBean框架反序列化JSON,从而使生成的bean具有影响其一个或多个成员类型的类型参数 背景 带有JSON结果的RPC 我正在使用GWT(Gwt 包含类型化成员的参数化自动bean类型 问题:,gwt,autobean,Gwt,Autobean,是否有任何方法可以使用AutoBean框架反序列化JSON,从而使生成的bean具有影响其一个或多个成员类型的类型参数 背景 带有JSON结果的RPC 我正在使用GWT(RequestBuilder)执行RPC请求。返回的JSON负载的形式如下: { "resultSet": [{...}, {...}, ...], // items requested; say, items 150-160 "totalCount": 15330 // total matc
RequestBuilder
)执行RPC请求。返回的JSON负载的形式如下:
{
"resultSet": [{...}, {...}, ...], // items requested; say, items 150-160
"totalCount": 15330 // total matching items in DB
}
resultSet
中的对象的类型因我调用的特定RPC而异
自动bean接口
我想使用AutoBean反序列化这个JSON。我试图将这个对象表示为:
interface RpcResults<T> {
List<T> getResultSet();
void setResultSet(List<T> resultSet);
int getTotalCount();
void setTotalCount(int totalCount);
}
基于此堆栈跟踪,我的直觉如下:
RpcResults.getResultSet()
似乎正在返回原始列表
resultSet
中的每个项创建对象
实例我是否在AutoBean API中遗漏了一些可以让我轻松做到这一点的东西?如果没有,我是否应该调查一个明显的攻击点?除了我已经在使用的JSONParser和JavaScriptObject之外,还有其他更合理的替代方法吗?由于Java类型的擦除,这并不简单。运行时不存在类型
T
,该类型已被擦除为Object
,以代替任何其他下限。AutoBeanCodex需要类型信息来具体化传入json负载的元素。这种类型信息通常由AutoBean实现提供,但由于T
擦除,它只知道它包含一个列表
如果可以在运行时提供类文本,则可以将getter声明为Splittable getResultSet()
,并通过调用AutoBeanCodex.decode(autoBeanFactory,SomeInterfaceType.class,getResultSet().get(index))
来具体化列表中的各个元素。通过使用,您可以向AutoBean接口添加一个T getResultAs(Class clazz,int index)
方法。这看起来像:
@Category(MyCategory.class)
interface MyFactory extends AutoBeanFactory {
AutoBean<ResultContainer> resultContainer();
}
interface ResultContainer<T> {
Splittable getResultSet();
// It's the class literal that makes it work
T getResultAs(Class<T> clazz, int index);
}
class MyCategory {
public static <T> T getResultAs(Autobean<ResultContainer> bean,
Class<T> clazz, int index) {
return AutoBeanCodex.decode(bean.getFactory(), clazz,
bean.as().getResultSet().get(index)).as();
}
}
@Category(MyCategory.class)
接口MyFactory扩展了AutoBeanFactory{
自动生成结果容器();
}
接口结果容器{
可拆分的getResultSet();
//正是类文本使其工作
T getResultAs(类分类,整数索引);
}
类别MyCategory{
公共静态T getResultAs(自动bean,
类分类,整数索引){
返回AutoBeanCodex.decode(bean.getFactory(),clazz,
bean.as().getResultSet().get(index)).as();
}
}
尝试覆盖对象特定接口中的.getResultSet()和.setResultSet()方法:
interface FooRpcResults extends RpcResults<Foo> {
@Override
List<Foo> getResultSet();
@Override
void setResultSet(List<Foo> value);
}
接口FooRpcResults扩展了RpcResults{
@凌驾
列出getResultSet();
@凌驾
作废setResultSet(列表值);
}
以下测试适用于我(GWT 2.3.0):
导入静态org.junit.Assert.assertEquals;
导入静态org.junit.Assert.assertNotNull;
导入java.util.ArrayList;
导入java.util.List;
导入org.junit.Test;
导入com.google.web.bindery.autobean.shared.autobean;
导入com.google.web.bindery.autobean.shared.AutoBeanCodex;
导入com.google.web.bindery.autobean.shared.AutoBeanFactory;
导入com.google.web.bindery.autobean.shared.AutoBeanUtils;
导入com.google.web.bindery.autobean.vm.AutoBeanFactorySource;
公共类自动测试{
公共静态接口页{
int getDataSize();
列出getPage();
int getStartIndex();
void setDataSize(int值);
无效设置页(列表值);
无效设置起始索引(int值);
}
公共静态接口{
字符串getName();
void setName(字符串值);
}
公共静态接口ThingFactory扩展了AutoBeanFactory{
AutoBean createThing();
AutoBean createThingPage();
}
公共静态接口ThingPage扩展页面{
@凌驾
列出getPage();
@凌驾
无效设置页(列表值);
}
@试验
public void testAutoBean(){
最终ThingFactory工厂=AutoBeanFactorySource
.create(ThingFactory.class);
final Thing thing1=factory.createThing().as();
内容1.设置名称(“一”);
final Thing thing2=factory.createThing().as();
内容2.设置名称(“两个”);
final List things=new ArrayList();
事物。添加(事物1);
事物。添加(事物2);
最终页面=factory.createThingPage().as();
第1页:索引(50);
page.setDataSize(1000);
page.setPage(事物);
最终字符串json=AutoBeanCodex.encode(
getAutoBean(第页)).getPayload();
最终页面接收页面=AutoBeanCodex.decode(工厂、,
ThingPage.class,json).as();
assertEquals(receivedPage.getStartIndex(),page.getStartIndex());
assertEquals(receivedPage.getDataSize(),page.getDataSize());
assertNotNull(receivedPage.getPage());
assertEquals(receivedPage.getPage().size(),page.getPage().size());
对于(int i=0;i
删除ThingPage界面中的覆盖将破坏它。这种方法对我来说非常有意义。然而,即使使用GWT2.2.0,泛型类型似乎也不能作为分类方法的参数。这意味着不可能将类对象传递给
getResultAs
。我已经将您的示例简化为,但GWT编译器会抱怨。如果不能传入类对象,这个相当优雅的解决方案就不起作用了。我认为您的类别中有一个输入错误。您添加了一个方法getResultSet(),而不是将其命名为getResultAs()。您是对的。修正了打字错误,修正了我粘贴的简化案例。我试着更接近你答案中的代码,结果是。但是,这会导致编译错误。(我在ResultCategory.getResultAs
的签名中尝试了autobeanbean
和autobeanbean
,结果相同。)我仍然是
interface FooRpcResults extends RpcResults<Foo> {
@Override
List<Foo> getResultSet();
@Override
void setResultSet(List<Foo> value);
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanCodex;
import com.google.web.bindery.autobean.shared.AutoBeanFactory;
import com.google.web.bindery.autobean.shared.AutoBeanUtils;
import com.google.web.bindery.autobean.vm.AutoBeanFactorySource;
public class AutoBeanTest {
public static interface Page<T> {
int getDataSize();
List<T> getPage();
int getStartIndex();
void setDataSize(int value);
void setPage(List<T> value);
void setStartIndex(int value);
}
public static interface Thing {
String getName();
void setName(String value);
}
public static interface ThingFactory extends AutoBeanFactory {
AutoBean<Thing> createThing();
AutoBean<ThingPage> createThingPage();
}
public static interface ThingPage extends Page<Thing> {
@Override
List<Thing> getPage();
@Override
void setPage(List<Thing> value);
}
@Test
public void testAutoBean() {
final ThingFactory factory = AutoBeanFactorySource
.create(ThingFactory.class);
final Thing thing1 = factory.createThing().as();
thing1.setName("One");
final Thing thing2 = factory.createThing().as();
thing2.setName("Two");
final List<Thing> things = new ArrayList<Thing>();
things.add(thing1);
things.add(thing2);
final Page<Thing> page = factory.createThingPage().as();
page.setStartIndex(50);
page.setDataSize(1000);
page.setPage(things);
final String json = AutoBeanCodex.encode(
AutoBeanUtils.getAutoBean(page)).getPayload();
final Page<Thing> receivedPage = AutoBeanCodex.decode(factory,
ThingPage.class, json).as();
assertEquals(receivedPage.getStartIndex(), page.getStartIndex());
assertEquals(receivedPage.getDataSize(), page.getDataSize());
assertNotNull(receivedPage.getPage());
assertEquals(receivedPage.getPage().size(), page.getPage().size());
for (int i = 0; i < receivedPage.getPage().size(); i++) {
assertNotNull(receivedPage.getPage().get(i));
assertEquals(receivedPage.getPage().get(i).getName(), page
.getPage().get(i).getName());
}
}
}