28

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

现在,我希望能够为非 REST 目的利用这种酷炫的 JSON 化功能 - 我希望能够将其中一些对象序列化到磁盘,作为 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 中公开了此功能以满足我的需求?到目前为止我还没有找到它...

谢谢!

更新 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 访问它?谢谢!

4

7 回答 7

19

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

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

http://wiki.fasterxml.com/JacksonJAXBAnnotations

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

于 2009-11-06T23:05:56.060 回答
6

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

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

于 2009-11-22T15:46:44.473 回答
5
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
于 2011-11-02T10:49:31.400 回答
3

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

List myArray = new ArrayList();

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

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

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

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

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

于 2010-11-17T14:39:37.207 回答
1

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

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

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

于 2009-07-09T17:27:40.653 回答
1

通过一些特定于 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 慢,并且比必要的复杂得多。

于 2012-05-30T12:35:36.977 回答
0

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

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

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

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

于 2009-08-09T15:40:31.593 回答