【问题标题】:Jersey: Return a list of stringsJersey:返回字符串列表
【发布时间】:2011-07-20 12:41:54
【问题描述】:

我尝试将 Jersey 中的字符串列表作为 JSON 和 XML 返回。 我认为这将是微不足道的。

我的第一次尝试是写这样的东西

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("/bar")
public List<String> get() {
    return dao.get();
}

我希望输出与此类似:["string1", ..., "stringN] 不幸的是,我得到了这个:

com.sun.jersey.api.MessageException: A message body writer for Java class java.util.LinkedList, and Java type java.util.List<java.lang.String>, and MIME media type application/json was not found 

然后我为 List 写了一个包装器 StringList

@XmlRootElement
public class StringList {

    private List<String> data;

    public StringList() {
    }

    public StringList(List<String> data) {
        this.data = data;
    }

    public List<String> getData() {
        return data;
    }

    public void setData(List<String> data) {
        this.data = data;
    }
}

并将外观修改为

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("/foo")
public StringList stringlist() {
    return new StringList(sl());
}

这对于项目数超过 1 的列表非常有用。

{"data":["foo","bar"]}

不幸的是,对于一个或零个元素,我得到了两个意外结果

{"data": "just one"} // for one element i would expect {"data": ["just one"]}

null // for no elements i would expect {"data": []}

我做错了什么吗? 我该如何解决这个问题?

【问题讨论】:

    标签: java rest jersey jax-rs


    【解决方案1】:

    好的,我可以通过搜索示例来解决它

    这确实有效,但它只能用于 JSON 而不能用于 XML

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("/get")
    public JSONArray get() {;
        return new JSONArray(dao.getStringList());
    }
    

    解决了问题,但是否还有通用方法?

    【讨论】:

    • 这与特定的表示相关,因此它是一个非常低劣的解决方案。
    【解决方案2】:

    你可以使用javax.ws.rs.core.GenericEntity:

    @GET
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    @Path("/foo")
    public GenericEntity<List<String>> stringlist()
    {
      List<String> list = Arrays.asList("test", "as");
    
      return new GenericEntity<List<String>>(list) {};
    }
    

    【讨论】:

    • 有人对这种方法有好运吗?我在上面的代码中看到了同样的异常......
    • 我看到了与 John McCann 提到的这种方法相同的异常
    • 看起来好像遗漏了一些东西,这种方法不起作用。 “找不到 Java 类 javax.ws.rs.core.GenericEntity 和 Java 类型类 javax.ws.rs.core.GenericEntity 和 MIME 媒体类型 application/json 的消息正文阅读器”消息被抛出
    • 不适用于 Jersey 2.0 n tomcat 7,获取 description The server encountered an internal error that prevented it from fulfilling this request.
    • 不确定为什么这是公认的答案。它不起作用。雄猫 7,泽西 2,莫西
    【解决方案3】:

    为了说服 Jersey 以你想要的方式输出列表,你需要提供一个自己的 ContextResolver:

    @Provider
    public class JaxbContentResolver implements ContextResolver<JAXBContext> {
    
        private Log log = LogFactory.getLog(getClass());
        private JAXBContext context;
    
        public JaxbContentResolver() throws JAXBException {
            Class[] types = {StringList.class};
            context = new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(true).arrays("data").build(), types);
        }
    
        @Override
        public JAXBContext getContext(Class<?> objectType) {
            log.trace("Entering Test-getContext for type: " + objectType.getSimpleName());
            return context;
        }
    }
    

    这样列表将按照您希望的方式显示。

    注意:这种方法的一个缺点是您需要在代码中保留一个额外的位置;如果您想向 REST 接口添加另一个(列表包装器)类,您需要记住转到上面的代码并将该类添加到您的 ContextResolver...

    【讨论】:

      【解决方案4】:

      您需要使用备用 JSON 配置 JSONConfiguration.natural()。

      最好创建自己的ContextResolver,使用该替代配置作为提供者,并告诉它它负责哪些类。

      我不知道以另一种方式全局使用替代配置的方法。

      【讨论】:

        【解决方案5】:

        除了提供的答案之外,如果您仍然得到MessageBodyWriter not found,请尝试添加一个依赖项,例如:

            <dependency>
                <groupId>org.glassfish.jersey.media</groupId>
                <artifactId>jersey-media-moxy</artifactId>
            </dependency>
        

        【讨论】:

          【解决方案6】:

          我对此的解决方案是一个包装类(在某处找到它)。现在可以了。我不明白不支持 javas List 类作为根元素背后的想法。也许它与我不知道的一些 json 规范/最佳实践有关。

          但现在我使用这个:

          public class Houses {
              private List<String> houses;
          
              // Needed for jersey
              public Houses() { }
          
              public Houses(List<String> houses) {
                  this.houses = houses;
              }
          
              public void setHouses(List<String> houses) {
                  this.houses = houses;
              }
          
              public List<String> getHouses() {
                  return this.houses;
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-09-10
            • 2017-04-17
            • 1970-01-01
            • 2013-07-18
            • 2015-10-03
            • 2019-08-05
            • 2018-08-16
            • 1970-01-01
            相关资源
            最近更新 更多