【问题标题】:Java.util.Map to JSON Object with Jersey / JAXB / JacksonJava.util.Map to JSON Object with Jersey / JAXB / Jackson
【发布时间】:2011-08-13 06:37:24
【问题描述】:

我一直在尝试创建 Jersey REST Web 服务。我想从 Java 类接收和发出 JSON 对象,如下所示:

@XmlRootElement
public class Book {

    public String code;

    public HashMap<String, String> names;

}

这应该像这样转换成 JSON:

{
    "code": "ABC123",
    "names": {
        "de": "Die fabelhafte Welt der Amelie",
        "fr": "Le fabuleux destin d'Amelie Poulain"
    }
}

但是我找不到一个标准的解决方案。每个人似乎都在实现自己的wrappersolution。这个要求对我来说似乎非常基本;我不敢相信这是普遍接受的解决方案,尤其是因为 Jersey 确实是 Java 中更有趣的部分之一。

我还尝试升级到 Jackson 1.8,它只给了我这个,这是极度混淆的 JSON:

{
    "code": "ABC123",
    "names": {
        "entry": [{
            "key": "de",
            "value": "Die fabelhafte Welt der Amelie"
        },
        {
            "key": "fr",
            "value": "Le fabuleux destin d'Amelie Poulain"
        }]
    }
}

对此有什么建议的解决方案吗?

【问题讨论】:

    标签: java json rest jersey jackson


    【解决方案1】:

    我知道很久以前就有人问过了,但是事情发生了变化,所以对于没有包 com.sun.jersey 的最新 Jersey v2.22,添加了这两个依赖项在项目中 pom.xml 解决了同样的问题:

    <dependency>
      <groupId>org.glassfish.jersey.media</groupId>
      <artifactId>jersey-media-json-jackson</artifactId>
      <version>2.22</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.jaxrs</groupId>
      <artifactId>jackson-jaxrs-json-provider</artifactId>
      <version>2.5.4</version> <!-- jackson version used by jersey v2.22 -->
    </dependency>
    

    无需在 web.xml 中添加任何内容。 第一个依赖项将指示 jersey 使用 jackson 进行 POJO 到 JSON 的转换。 第二个依赖项会将 jackson 注册为 jersey JSON 提供程序。

    同样针对POJO中的null问题,在POJO类中加入这个注解:

    @JsonInclude(JsonInclude.Include.NON_NULL)
    

    【讨论】:

      【解决方案2】:

      我不知道为什么这不是默认设置,我花了一段时间才弄清楚,但如果你想使用 Jersey 进行 JSON 转换,请添加

          <init-param>
              <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
              <param-value>true</param-value>
          </init-param>
      

      到您的 web.xml,您的所有问题都应该得到解决。

      PS:你还需要去掉 @XmlRootElement 注释才能让它工作

      【讨论】:

      • 小费+1。但请注意,POJO 映射也会在 JSON 中返回 NULL 值。我更喜欢 JAXB 并使用包含额外 POJO 的列表。
      • 这是服务器端设置。在客户端上执行此操作: ClientConfig clientConfig = new DefaultClientConfig(); clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);客户端client = Client.create(clientConfig);
      • @Jan 如果我需要将 Book 转换为 json 和 xml(带有 accepts 的请求)怎么办?如果我删除 XmlRootElement xml 序列化不再起作用
      • 哇。这将是一个很好的答案,除了按照建议添加到 web.xml,无论是否删除 @XmlRootElement 和相关注释都会导致:com.sun.jersey.spi.container.ContainerRequest getEntity SEVERE: A message body reader for Java com.hp.web.user.dto.ProfileDto 类和 Java 类型 com.hp.web.user.dto.ProfileDto 类和 MIME 媒体类型 application/json; charset=UTF-8 未找到。
      • 是的,Russ 说的。此非解决方案给出“未找到消息正文编写器”错误
      【解决方案3】:
      @POST
      @Consumes("application/json")
      public void createBook(Book book)
      {
       .....
       .....
      }
      

      当然,您需要为 Book 中的每个属性设置 getter/setter。

      推荐使用包装类(通常是一个映射)的原因也是为了避免为您要发送的每种数据创建多个 DTO。使用映射进行序列化/反序列化并作为业务逻辑的一部分将其转换为相应的 POJO 以进行内部处理更容易,特别是如果您使用该 POJO 进行对象关系映射。

      【讨论】:

        【解决方案4】:

        您可以使用google-gson。这是一个示例代码:

            @Test
            public void testGson(){
               Book book = new Book();
               book.code = "1234";
               book.names = new HashMap<String,String>();
               book.names.put("Manish", "Pandit");
               book.names.put("Some","Name");
               String json = new Gson().toJson(book);
               System.out.println(json);
           }
        

        输出为{"code":"1234","names":{"Some":"Name","Manish":"Pandit"}}

        【讨论】:

        • 谢谢,但我对与 Jersey 集成的解决方案特别感兴趣。
        • 我更喜欢这种返回复杂数据结构的方法,而不是简单的 POJO。它完美地工作,它与 Jersey 集成(你只需要在你的 get 方法中返回一个“字符串”),你不必搞乱转换器的 web.xml。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-02
        • 2015-06-24
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多