【问题标题】:How to reuse Jersey's JSON/JAXB for serialization?如何重用 Jersey 的 JSON/JAXB 进行序列化?
【发布时间】:2009-07-01 23:03:05
【问题描述】:

我有一个使用 Jersey 实现的 JAX-RS REST 服务。 JAX-RS/Jersey 的一个很酷的特性是 POJO 可以很容易地转换为 REST 服务,只需添加一些 Java 注释......包括一种将 POJO 转换为 JSON 的简单机制 - 使用 JAXB 注释。

现在,我希望能够将这种酷炫的 JSON 化功能用于非 REST 目的 - 我希望能够将其中一些对象序列化到磁盘,作为 JSON 文本。这是我想要序列化的示例 JAXB 对象:

@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {

    public UserInfoImpl() {} 

    public UserInfoImpl(String user, String details) {
        this.user = user;
        this.details = details;
    }

    public String getUser() { return user; }
    public void setUser(String user) { this.user = user; }

    public String getDetails() { return details; }
    public void setDetails(String details) { this.details = details; }

    private String user;
    private String details;
}

Jersey 可以将其中之一转换为 json,无需额外信息。我想知道 Jersey 是否已经在 API 中公开了此功能以满足我的需求?到目前为止我还没有找到它......

谢谢!

UPDATE 2009-07-09:我了解到我可以使用 Providers 对象来几乎做我想做的事:

  @Context Providers ps;
  MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);

  uw.writeTo(....)

... 这会将对象作为 json 写入任何输出流,这对我来说是完美的,但我只能使用 @Component 对象中的 @Context 获取 Providers 对象。有谁知道如何从常规的、未注释的 POJO 访问它?谢谢!

【问题讨论】:

  • 我也在尝试查找这方面的信息,但我正在寻找仅使用 javax.*/java.* API 的东西(我不介意为 JUnit 测试添加额外的库,但是我希望他们出现在 JEE6 RI
  • 我也可以调用一个类进行引导。

标签: json jersey jax-rs


【解决方案1】:

Jersey 使用几个不同的框架,具体取决于您使用的是 mapped()、badgerfish() 还是 natural() 表示法。自然通常是人们想要的。我相信,这是使用非常好(而且非常快)的独立 Jackson JSON 处理器实现的,它来自 Object->JAXB->JSON。然而,Jackson 也提供了它自己的 JAX-RS 提供程序来直接使用 Object->JSON。

事实上,他们甚至添加了对 JAXB 注释的支持。来看看

http://wiki.fasterxml.com/JacksonJAXBAnnotations

我认为这最终就是您要寻找的。 Jackson 进行 ObjectJSON 处理...Jersey 只是为您拨打电话

【讨论】:

  • 谢谢,安迪。这确实听起来像我正在寻找的东西。我只是不想添加不必要的额外依赖项。谢谢!
  • 好吧,这样想:您需要一个用于 XML 序列化的库(JAXB、XStream 等)。您需要一个用于 JSON 的 JSON 库:JAXB 不提供它;泽西岛还将它发送到图书馆。所以问题是要添加哪个库;不是你是否需要添加一些东西。所以 Jackson(或 json-tools、gson)可以轻松做到。 JAX-RS 提供者实际上只不过是对媒体类型进行操作的调度程序,选择要呈现的“视图”(json、xml、...),然后调用适当的库。
【解决方案2】:

这是一个使用 JAXB 将对象映射到 JSON 的简单简短示例(使用 Jackson):

http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-jackson-howto.texy

【讨论】:

    【解决方案3】:
    ObjectMapper mapper = new ObjectMapper();
    String str = mapper.writeValueAsString(pojoObject);
    

    【讨论】:

      【解决方案4】:

      JAXB 注释在序列化为 XML 时可以正常工作。 主要问题是 JAXB 不支持空数组。所以当序列化这样的东西时......

      List myArray = new ArrayList();
      

      ...通过 jaxb 注释到 json 您所有的空数组都变为 null 而不是 []。

      要解决这个问题,您可以通过 jackson 将 pojos 直接序列化为 json。

      看看 Jersey 的用户指南: http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959

      这是在没有 JAXB 的情况下使用 Jackson 提供程序的最佳方式。此外,您始终可以通过从其网站下载 jackson-all-x.y.z-jar 来使用最新版本的 jackson。

      此方法不会干扰您的 jaxb 注释,因此我建议您尝试一下!

      【讨论】:

        【解决方案5】:

        由于 Jersey 是 JAX-RS 的参考实现,而 JAX-RS 完全专注于为 REST 服务提供实现端点的标准方法,因此序列化有效负载的问题留给其他标准处理。

        我认为,如果他们在 JAX-RS 标准中包含对象序列化,它将很快成为一个难以实现的大型多头野兽,并失去一些关注点。

        我很欣赏 Jersey 专注于提供干净且易于使用的 REST 端点。在我的例子中,我刚刚将一个包含所有 JAXB 管道的父级子类化,因此二进制和 XML 之间的编组对象非常干净。

        【讨论】:

        • 我想我不是很清楚。问题是,Jersey 已经将 JAXB 对象转换为 JSON。我不是在寻找 Jersey 来添加“序列化”支持,而是为了访问它已经为我的 own 序列化代码提供的 Provider 功能。我将更新我的问题以增加清晰度。谢谢!
        【解决方案6】:

        通过一些特定于 Jersey 的引导,您可以使用它为您创建必要的 JSON 对象。需要包含以下依赖(可以使用bundle,但是如果使用Weld进行测试会出问题):

            <dependency>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-json</artifactId>
                <version>1.12</version>
            </dependency>
            <dependency>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-client</artifactId>
                <version>1.12</version>
            </dependency>
        

        您可以从那里创建一个带有 JAXB 注释的类。下面是一个例子:

        @XmlRootElement
        public class TextMessage {
        private String text;
            public String getText() { return text; }
            public void setText(String s) { this.text = text; }
        }
        

        然后你可以创建如下单元测试:

            TextMessage textMessage = new TextMessage();
            textMessage.setText("hello");
            textMessage.setUuid(UUID.randomUUID());
        
            // Jersey specific start
            final Providers ps = new Client().getProviders();
            // Jersey specific end
            final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {
        
                @Override
                public void add(final String key, final Object value) {
                }
        
                @Override
                public void clear() {
                }
        
                @Override
                public boolean containsKey(final Object key) {
                    return false;
                }
        
                @Override
                public boolean containsValue(final Object value) {
                    return false;
                }
        
                @Override
                public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
                    return null;
                }
        
                @Override
                public List<Object> get(final Object key) {
                    return null;
                }
        
                @Override
                public Object getFirst(final String key) {
                    return null;
                }
        
                @Override
                public boolean isEmpty() {
                    return false;
                }
        
                @Override
                public Set<String> keySet() {
                    return null;
                }
        
                @Override
                public List<Object> put(final String key, final List<Object> value) {
                    return null;
                }
        
                @Override
                public void putAll(
                        final Map<? extends String, ? extends List<Object>> m) {
                }
        
                @Override
                public void putSingle(final String key, final Object value) {
                }
        
                @Override
                public List<Object> remove(final Object key) {
                    return null;
                }
        
                @Override
                public int size() {
                    return 0;
                }
        
                @Override
                public Collection<List<Object>> values() {
                    return null;
                }
            };
        
            final MessageBodyWriter<TextMessage> messageBodyWriter = ps
                    .getMessageBodyWriter(TextMessage.class, TextMessage.class,
                            new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Assert.assertNotNull(messageBodyWriter);
        
            messageBodyWriter.writeTo(textMessage, TextMessage.class,
                    TextMessage.class, new Annotation[0],
                    MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
            final String jsonString = new String(baos.toByteArray());
            Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));
        

        这种方法的优点是它将所有内容都保留在 JEE6 API 中,除了测试和获取提供程序之外,不需要明确需要外部库。但是,您需要创建 MultivaluedMap 的实现,因为标准中没有提供任何内容,我们实际上并没有使用它。它可能也比 GSON 慢,而且比必要的复杂得多。

        【讨论】:

          【解决方案7】:

          我了解 XML 视图,但如果将 POJO 的 JSON 支持作为标准设备,这将显示出一些远见。如果您的实现是 JSON 并且您的客户端是 JavaScript RIA,那么必须使用特殊字符修改 JSON 标识符是没有意义的。

          另外,并不是说 Java Bean 不是 POJO。我想在我的网络层的外表面使用这样的东西:

          public class Model
          {
             @Property height;
             @Property weight;
             @Property age;
          }
          

          没有默认构造函数,没有 getter/setter 噪音,只是一个带有我自己注释的 POJO。

          【讨论】:

          • 我不认为这是 JAXB 的错误:JAXB 是 XML 的 API,而不是其他格式的 API。但接下来的问题是 JAXB API 是否应该适用于其他格式——如果是这样,则需要变通方法。 XML != JSON。顺便说一句:已经提到的 Jackson 允许使用非 Bean POJO;可以使用字段或 getter/setter,使用实际的构造函数等等。如果用户真的想要,它可以使用 JAXB 注释作为额外的可选信息。但这不需要它们。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-11-09
          • 2012-12-06
          • 2012-03-29
          • 2011-12-20
          • 2015-01-05
          • 2016-12-11
          • 1970-01-01
          相关资源
          最近更新 更多