Json <-> Java序列化,需要与GWT兼容

59
我正在寻找一个适用于Java且可能与GWT兼容的简单Json(de)serializer。我已经搜索了一些解决方案,但要么需要注释每个成员,要么定义无用的接口。这相当无聊。为什么我们没有像下面这样真正简单的东西呢?
class MyBean {
    ...
}

new GoodSerializer().makeString(new MyBean());
new GoodSerializer().makeObject("{ ... }", MyBean.class)

4
问题在于Java本身使用了一个“无用的接口”来将对象标记为可序列化。 - Powerlord
1
请查看http://restygwt.fusesource.org/documentation/restygwt-user-guide.html。 - itaifrenkel
13个回答

56

看一下GWT的覆盖类型。我认为这是在GWT中处理JSON最简单的方法。以下是从链接文章修改过的代码示例:

public class Customer extends JavaScriptObject {
    public final native String getFirstName() /*-{ 
        return this.first_name;
    }-*/;
    public final native void setFirstName(String value) /*-{
        this.first_name = value;
    }-*/;
    public final native String getLastName() /*-{
        return this.last_name;
    }-*/;
    public final native void setLastName(String value) /*-{
        this.last_name = value;
    }-*/;
}

一旦您定义了覆盖类型,就很容易从JSON创建JavaScript对象并在Java中访问其属性:

public static final native Customer buildCustomer(String json) /*-{
    return eval('(' + json + ')');
}-*/;
如果您想再次获得对象的JSON表示形式,可以将覆盖类型包装在JSONObject中:
Customer customer = buildCustomer("{'Bart', 'Simpson'}");
customer.setFirstName("Lisa");
// Displays {"first_name":"Lisa","last_name":"Simpson"}
Window.alert(new JSONObject(customer).toString());

2
我对重叠类型的主要问题在于它们意味着您无法在Java端和GWT端使用相同的对象表示。但是,我还没有找到更好的反序列化解决方案。 - mooreds
2
我认为最好的方法是注释getter,并在编译时生成(反)序列化方法。 - skrat
1
为什么不直接使用GWT内置的JSON库?http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/json/client/或者在提问时这个功能还没有推出?我会在下面添加答案。 - Eric Nguyen
如果SO有嵌套语法高亮就太好了... - barfuin
显示剩余2条评论

38

还有一个值得尝试的方法是使用 GWT 2.1 新引入的 AutoBean 框架。

你可以定义 bean 的接口和 factory 来提供它们,然后 GWT 会为你生成实现。

interface MyBean {
  String getFoo();
  void setFoo(String foo);
}

interface MyBiggerBean {
  List<MyBean> getBeans();
  void setBeans(List<MyBean> beans>;
}

interface Beanery extends AutoBeanFactory{
  AutoBean<MyBean> makeBean();
  AutoBean<MyBiggerBean> makeBigBean();
}

Beanery beanFactory = GWT.create(Beanery.class);

void go() {
  MyBean bean = beanFactory.makeBean().as();
  bean.setFoo("Hello, beans");
}

AutoBeanCodex 可以用于将它们序列化为JSON格式并反序列化回来。

AutoBean<MyBean> autoBean = AutoBeanUtils.getAutoBean(bean);
String asJson = AutoBeanCodex.encode(autoBean).getPayload();

AutoBean<MyBean> autoBeanCloneAB = 
  AutoBeanCodex.decode(beanFactory, MyBean.class, asJson );

MyBean autoBeanClone = autoBeanCloneAB.as(); 
assertTrue(AutoBeanUtils.deepEquals(autoBean, autoBeanClone));

它们也可以在服务器端使用—使用AutoBeanFactoryMagic.create(Beanery.class)而不是GWT.create(Beanery.class)


1
如果您在服务器端使用DTO并且想要重用接口,AutoBean绝对是最好的选择。感谢rjrjr,它拯救了我的生命...(或者至少节省了几个小时) - zdenda.online
这需要在非 GWT 服务器上使用接口和 POJO。是否有纯 Jackson 兼容的 POJO 解决方案? - itaifrenkel
你可以在GWT客户端中使用AutoBean,并使用你喜欢的框架创建JSON。它是网络上的纯JSON。 - Christian Kuetbach
如果我可以多次点赞,我一定会这样做。这是一个非常棒的解决方案,解决了一个困难的问题。 - Spedge

12

最简单的方法是使用GWT内置的JSON API。这里是文档。这里也有一篇很棒的教程介绍如何使用。

做法非常简单:

String json = //json string
JSONValue value = JSONParser.parse(json);

JSONValue API相当不错,它允许您在从JSON对象中提取值时链接验证,这样如果格式出了任何问题,就会抛出异常。


更不用说,效率更高。 - Mark Renouf

11

似乎我找到了自己问题的正确答案。

我发现在GWT中将Bean转换为JSON和JSON转换为Bean并不是一个简单的任务。已知的库不能使用,因为GWT需要它们的完整源代码,而且这个源代码必须只使用GWT模拟的Java类。此外,在GWT中不能使用反射。要求非常苛刻!

我找到了唯一存在的解决方案,名为 gwt-jsonizer。它使用自定义Generator类,并且对于每个“jsonable” bean都需要一个卫星接口。不幸的是,它在最新版本的GWT上不能正常工作,需要打补丁,并且长时间没有更新过。

所以,我个人认为让我的Beans知道如何自行转换为JSON和从JSON中转换回来更加便捷和快速,像这样:

public class SmartBean {
    private String name;

    public String getName() { return name; }
    public void setName(String value) { name = value;  }

    public JSONObject toJson() {
        JSONObject result = new JSONObject();
        result.put("name", new JSONString(this.name));
        return result;
    }
    public void fromJson(JSONObject value) {
        this.name = value.get("name").isString().stringValue();
    }

}

JSONxxxx 是 GWT 内置的类,提供低级别的 JSON 支持。


有趣。这对我来说似乎是GWT的一个缺点。 但知道有一种方法还是很好的。我们可能需要在未来自己做这件事,因为我们使用GWT编写了一个仪表板应用程序。 - StaxMan
是的,这就是为什么他们最终开发了一个内置的GWT JSON解析器。http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/json/client/ 我也添加了一个更完整的答案。 - Eric Nguyen
1
这应该被标记为答案,因为它是最干净的方式,不依赖于任何非核心 GWT 库来完成。 - Jason Washo

6

RestyGWT 是一个强大的库,能在 GWT 中对 Java 对象进行 JSON 编码或解码:

import javax.ws.rs.POST;
...
public interface PizzaOrderCodec extends JsonEncoderDecoder<PizzaOrder> {
}

然后:

// GWT will implement the interface for you
PizzaOrderCodec codec = GWT.create(PizzaOrderCodec.class);

// Encoding an object to json
PizzaOrder order = ... 
JSONValue json = codec.encode(order);

// decoding an object to from json
PizzaOrder other = codec.decode(json);

它还具有易于使用的API,可用于消耗Restful Web服务。
祝您愉快。

5

目前,最先进的技术是GWT内置的JSON解析器。http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/json/client/ 我也添加了一个更完整的答案。 - Eric Nguyen
问题是关于序列化,而不是解析... - Mark Renouf

3

2
我认为目前(根据此评论的日期)Piriti和RestyGWT是两个最好的解决方案。RestyGWT比Piriti更少侵入性,但Piriti似乎更强大。 - sksamuel

2
在Google Web Toolkit应用程序中,作者Ryan Dewsbury在第510至522页展示了如何使用GWT代码生成将数据序列化为XML和JSON文档。您可以在此处下载代码;您需要下载第10章的代码包,然后查看src/com/gwtapps/serialization包。我没有看到这个代码的许可证,但已经给作者发送了电子邮件以了解他的想法。如果他回复了,我会更新这篇文章。
这种解决方案存在一些问题: - 您必须在所有要序列化的对象上添加标记接口(他使用java.io.Serializable,但我想您也可以使用其他接口——如果您正在使用Hibernate作为后端,您的POJO可能已经被标记了)。 - 该代码仅支持字符串属性;它可以进行扩展。 - 该代码仅适用于1.4和1.5。
因此,这不是一个开箱即用的解决方案,但对于想要构建符合GWT的JSON序列化器的人来说,这是一个很好的起点。再加上像json-lib这样的服务器端JSON序列化器,您就可以开始使用了。
我还发现了这个项目(同样需要标记接口)。

1

你可能想要查看这个项目 https://gerrit.googlesource.com/gwtjsonrpc/

这是一个库,旨在支持 Android 的代码审查系统 Gerrit,但它是一个独立的模块,可以嵌入到任何 GWT 项目中,而不仅仅是 Gerrit。

一个合理的教程可能是目录顶层的 README。它与标准的 GWT RPC 相似,但使用 JSON 编码。它还具有内置的 XSRF 保护。


1

尝试使用来自Google Code的此序列化程序:http://code.google.com/p/json-io/

如果您需要在Java中编写或读取JSON格式,这是要使用的工具。无需创建额外的类等。通过一次调用将Java对象图转换为JSON格式。反之亦然-创建JSON字符串或流以获取Java对象。这是我见过的最快的库,用于执行此操作。在大多数情况下,它比使用二进制格式的ObjectOutputStream和ObjectInputStream更快。

非常方便的实用程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接