使用 Jersey 在 REST Web 服务中返回 JSON 时,找不到媒体类型 = application/json 的 MessageBodyWriter

问题描述 投票:0回答:6

我正在尝试使用 Jersey 创建一个非常简单的 REST 服务。这是服务代码

@Path("/UserService")
public class UserService {

    @GET
    @Path("/users")
    @Produces(MediaType.APPLICATION_XML)
    public List<User> getUsers() {
        User user = new User(1, "Thomas", "Greene");
        List<User> userList = new ArrayList<User>();
        userList.add(user);
        return userList;
    }
}

当我通过 Postman 运行它时,它会返回一个 XML 响应

现在,我想获取 JSON 响应。所以,我将媒体类型更改为

application/json

@Path("/UserService")
public class UserService {

    @GET
    @Path("/users")
    @Produces(MediaType.APPLICATION_JSON)
    public List<User> getUsers(){ 
        User user = new User(1, "Thomas", "Greene");
        List<User> userList = new ArrayList<User>();
        userList.add(user);
        return userList;
   }    
}

它在 Tomcat 日志中给出以下错误:

严重:找不到 Media type=application/json、type=class java.util.ArrayList、genericType=java.util.List 的 MessageBodyWriter。

有人可以指导我如何获取 JSON 响应吗?

json rest jersey
6个回答
14
投票

要使用 Jackson 2.x 作为 JSON 提供程序,您需要将

jersey-media-json-jackson
模块添加到您的
pom.xml
文件中:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.22.2</version>
</dependency>

然后在您的

JacksonFeature
/
Application
子类中注册
ResourceConfig

有关更多详细信息,请查看 Jersey 文档


3
投票

我现在对 JAXB 绑定也有点不安,因此让我在这里总结一下我的发现 - 如果我说了什么愚蠢的话,请纠正我:

  1. 当然,你必须有一个库来进行 JSON(反)序列化,在我的例子中它是 Moxy。
  2. 您必须告诉 JAXB 它应该支持哪些类。有多种方法可以做到这一点,最简单的似乎是在与您的类匹配的目录中添加一个 jaxb.properties 文件,其唯一内容是文本 javax.xml.bind.context.factory=org.eclipse。 persistence.jaxb.JAXBContextFactory。对于目录,我的意思是,如果您的类位于目录 src/main/java 中,并且存在包 com.pkg1.entities,请将此文件添加到 src/main/resources 中,并在那里作为 com/pkg1 /entities/jaxb.properties.
  3. 默认情况下,JAXB 适用于 POJO。因此,您需要一个不带参数的构造函数、一个 get 方法和一个 set 方法。只有这样该字段才会出现在 JSON 中。
  4. 我经常做的是添加第二个构造函数,该构造函数获取传入的运行时对象并将所有字段设置为直接公开。因此我不需要也不想要设置方法。解决方案是在 get 方法上注释 @XmlElement
  5. 我有说过你需要一个空/默认构造函数吗?我花了三个小时才找出为什么 class1 工作正常,而 class2 却出现 MessageBodyWriter 错误。我忘记了构造函数。咕噜咕噜。
  6. 当类配置良好但其字段之一返回无法序列化的类型时,您会得到相同的错误(我相信)。
  7. 我相信有一种情况是类注释 @XmlRootElement 导致了该错误。不确定,但我目前几乎不使用该注释。
  8. 如果您有一个 List 作为要转换为 Json 数组的元素之一,JAXB 将使用 myAbstract 类进行序列化。不是很有用,您希望序列化实际对象。但是 JAXB 应该如何知道谁实现/扩展了这个类呢?您必须使用注释 @XmlSeeAlso 来说明。因此 MyAbstract 类获得一个类注释 @XmlSeeAlso({MyConcrete1.class, MyConcrete2.class})。至少 Moxy 确实添加了一个额外的 type 字段,告诉消费者它是什么类别。完全有道理。
  9. 虽然你可以返回 userList 更好的选择是返回 Response.ok().entity(userList).build();然后你也可以返回错误。逻辑上是一样的。
  10. 注意您使用的数据类型。 String 可以,ArrayList 也可以,Hashtable 不行。也取决于您使用的序列化器。

我希望这对其他人有帮助。


2
投票

您的类路径上需要一个 json 序列化器才能完成这项工作。

只需添加 Jackson,Jersey 就会在 writer 中使用它。 例如。如果您使用maven,请将其添加到pom.xml

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.7.4</version>
</dependency>

2
投票

您的 xml 正在运行,所以我假设您的

@XmlRootElement
类中有
User
注释。

问题是,它知道如何使用注释

@XmlRootElement
将其转换为 xml,但不知道如何将其转换为 JSON。

因此,为了使其使用相同的 xml 注释(即

@XmlRootElement
)将所有内容转换为 JSON,我们可以添加

jersey-media-moxy-<whatever version>.jar

或者对于 Maven 用户

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

它还应该有一个无参数的构造函数


1
投票

我尝试了大量这些依赖项,但它们都不适用于我的 Jersey3 版本。我需要做的是将 Arraylist 转换为实际的数组。我用

toArray()
管理了这个,它开始正确序列化!


0
投票

真正的问题是你需要将列表放入类中,试试这个:

public class UserListClass() {
  private List<User> userList = new ArrayList<User>();

  public List<User> getUserList() { return userList; }
  public setUserList(List<User> userList) { this.userList = userList; }
}

你的代码是这样的:

@Path("/UserService")
public class UserService {

    @GET
    @Path("/users")
    @Produces(MediaType.APPLICATION_XML)
    public UserListClass getUsers() {
        User user = new User(1, "Thomas", "Greene");
        List<User> userList = new ArrayList<User>();
        userList.add(user);
        UserListClass ulc = new UserListClass();
        ulc.setUserList(userList);
        return ulc;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.