媒体类型为application/json的MessageBodyWriter未找到。

81

在使用JAX-RS作为JSON消费服务时,我遇到了问题。

以下是我的代码:

这是我的服务类:

//Sets the path to base URL + /hello
@Path("/hello") 
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class Hello {

    @GET
    @Produces("application/json")
    public Student getStudent() {

        Student s = new Student();
        s.first_name = "Test First Name !!!";
        s.last_name = "Test Last Name!!!";

        return s;
    }

我正在尝试从服务中获取的 Student 类:

@XmlRootElement
public class Student implements Serializable {

    public String first_name;
    public String last_name;

    public String getFirst_name() {
        return first_name;
    }

    public void setFirst_name(String first_name) {
        this.first_name = first_name;
    }

    public String getLast_name() {
        return last_name;
    }

    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }

    public Student()
    {
        first_name = "Fahad";
        last_name = "Mullaji";
    }
}

服务端的Web XML。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>com.vogella.jersey.first</display-name>
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <!-- Register resources and providers under com.vogella.jersey.first package. -->
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.vogella.jersey.first</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app> 

我不知道如何解决这个问题。 我正在使用SOAP UI测试JSON响应,但我想它不应该有影响。

我在很多地方读到需要添加下面的代码。但我不知道在哪里添加。我没有使用Maven进行构建。

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
</dependency>
服务器正在寻找将Student对象解析为JSON的函数,但无法找到相应的函数或jar文件。我已经添加了Genson、Moxy、RESTEasy和Jackson的jar,但我认为这可能是问题所在。我认为我错过了某个映射。

你正在构建什么? - John Ament
我按照http://www.vogella.com/tutorials/REST/article.html进行了操作。他没有提到使用MAVEN或ANT构建服务的任何内容。我需要使用什么来进行构建吗?谢谢回复。 - Fahad Mullaji
14个回答

132
我通过安装jersey-media-json-jackson解决了它。
将依赖项添加到pom.xml文件中。
<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-json-jackson</artifactId>
  <scope>runtime</scope>
</dependency>

9
谢谢!其他人,请不要忘记添加“版本”。 - asgs
7
选择最新的版本: https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson - Nikita Bosik
19
为什么这个解决方案有效?我为什么应该盲目地将它放入我的pom文件中? - orange14
1
请注意,Glassfish/Payara默认使用MOXy作为JSON序列化器,这会覆盖默认行为。 - Jakob
2
OP明确表示他们没有使用Maven。对于这个问题的正确答案应该展示所有需要的JAR文件。然后,对于Maven用户,可以作为额外的提示提供这个依赖项。同时还要解释为什么需要这些,即解释实体提供者相关内容。 - Paul Samsotha

63

你必须创建一个空的构造函数,因为JAX-RS会初始化这些类...你的构造函数必须没有参数:

你需要创建一个空的构造函数,因为JAX-RS会初始化这些类。你的构造函数必须不带参数:

@XmlRootElement
public class Student implements Serializable {

    public String first_name;
    public String last_name;

    public String getFirst_name() {
        return first_name;
    }

    public void setFirst_name(String first_name) {
        this.first_name = first_name;
    }

    public String getLast_name() {
        return last_name;
    }

    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }

    public Student()
    {
        first_name = "Fahad";
        last_name = "Mullaji";
    }


 public Student()
    {
    }
}

5
我遇到了与我的代码相同的问题,通过添加一个空构造函数来解决。 - asad.qazi
2
太棒了!为什么这不是被接受的答案超出了我的理解。 - Matthew Oakley
1
这应该是正确的答案。不过,您介意解释一下为什么我们需要一个空构造函数吗? - dkonayuki
我们需要在JSON响应中使用XML根吗? - BlueDolphin
是的,@xmlRootElement 是用于 JSON 的。 - asad.qazi
显示剩余4条评论

20

我曾处于同样的情况:
- 我没有使用Maven或Ant,
- 我完成了这个Vogella Jersey教程,
- 当我尝试使用@Produces(MediaType.APPLICATION_JSON)时,我遇到了MessageBodyWriter错误。

这个答案由@peeskillet解决了这个问题 - 你必须使用可以从FasterXML Jackson下载页面获得的Jackson *.jar文件。 你需要core文件和jaxrs文件。

我将它们添加到了WebContent/WEB-INF/lib文件夹中,就像上面的教程一样,并对web.xml文件进行了一些小的更改(如@peeskillet最初分享的那样):

<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
    your.other.package.here, com.fasterxml.jackson.jaxrs.json 
</param-value>

重要的部分是com.fasterxml.jackson.jaxrs.json


我认为我遇到了需要解决的相同问题,但我不确定“your.other.package.here”是什么? - jsh6303
你的Java服务控制器和端点定义在哪个包或多个包中。例如,我可以有一个“login”包,其中包含路由登录的类。因此,“your.other.package.here”将是“login”。 - user3063836
1
您真是太棒了,值得一座奖杯。感谢您提到了这个部分:your.other.package.here,com.fasterxml.jackson.jaxrs.json,正是我所缺少的。 - Mouhammed Soueidane
1
非常感谢你,你救了下周(我花了两天时间将Jersey从1升级到2,并与Weblogic一起使用)。 - Ismail Sahin
1
这是对我有效的方法。相应的代码版本大致如下: ResourceConfig jerseyConfig = new ResourceConfig(); jerseyConfig.packages("com.dataminr.eawatcher", "com.fasterxml.jackson.jaxrs.json"); ServletContainer servletContainer = new ServletContainer(jerseyConfig); - Robert Fraser
仍在与Weblogic从12.1升级到12.2的问题苦苦挣扎,这正是我需要的! - J Steven Perry

16

取消下面代码的注释有所帮助

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

在我的基于Maven的项目中,pom.xml文件中存在这个依赖项,解决了我的错误。


减1,因为OP明确表示他们没有使用Maven。 - Paul Samsotha

13

以下应该在您的pom.xml文件中排在其他jersy/jackson依赖项之上。在我的情况下,它如下所示:jersy-client dep-cy,然后我收到了“找不到支持媒体类型=application/json的MessageBodyWriter”错误。

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

2
谢谢,这对我有用。之后进入项目设置,选择所有的jar文件并选择添加到web-inf/lib文件夹中,然后重新构建。(使用IntelliJ) :) - Developine
减1,因为OP明确表示他们没有使用Maven。 - Paul Samsotha
2
因为我使用Maven时遇到了同样的问题,而omilus的解决方案解决了我的问题,所以加1。 - Pierluigi Vernetto
1
加 1 是因为这是唯一对我有效的方法。我可以使用 jettyVersion: '9.4.30.v20200611'/'9.4.6.v20170531' 和 jerseyVersion = '2.28' 重新产生这个问题。 - Wade H

9
为了解决这个问题,请尝试以下方法。对我很有效。
pom.xml 文件中添加以下依赖项。
<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-json-jackson</artifactId>
  <version>2.25</version>
</dependency>

确保模型类包含无参构造函数

 public Student()
    {
    }

减1,因为OP明确表示他们没有使用Maven,而且OP已经有了一个无参构造函数。 - Paul Samsotha
这个依赖解决了我的问题。我正在使用Maven。 - codrelphi
Paul Samsotha,你错了,如果没有其他参数构造函数,它就有no-arg constructor。你应该说加一。 - java dev

2
我认为你可以尝试将数据转换为Json格式。你可以使用gson库来完成这个任务。尝试以下代码:

我不知道这是否是最好的解决方案,但你可以按照这种方式处理。这对我起作用了。

示例:`

@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response info(@HeaderParam("Accept") String accept) {
    Info information = new Info();
    information.setInfo("Calc Application Info");
    System.out.println(accept);
    if (!accept.equals(MediaType.APPLICATION_JSON)) {
        return Response.status(Status.ACCEPTED).entity(information).build();
    } else {
        Gson jsonConverter = new GsonBuilder().create();
        return Response.status(Status.ACCEPTED).entity(jsonConverter.toJson(information)).build();
    }
}

1
虽然这个方法可能可行,但不是一个非常优雅的解决方案。将Java对象转换为JSON的工作可以由Jersey完成(这就是使用这样一个框架的全部意义),所以不必自己动手。 - sleske

1

我更喜欢使用注册JacksonJsonProvider到你的Jersey ResourceConfig,而不是引入其他答案中提到的jersey-media-json-jackson依赖项:

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.glassfish.jersey.server.ResourceConfig;

...

ResourceConfig myResourceConfig = new ResourceConfig();
myResourceConfig.register(JacksonJsonProvider.class);

JacksonJsonProvider 的 Javadoc 解释如下:

Basic implementation of JAX-RS abstractions (MessageBodyReader,
MessageBodyWriter) needed for binding JSON ("application/json") 
content to and from Java Objects ("POJO"s).

Actual data binding functionality is implemented by ObjectMapper:
mapper to use can be configured in multiple ways:

 By explicitly passing mapper to use in constructor
 By explictly setting mapper to use by setMapper
 By defining JAX-RS Provider that returns ObjectMappers.
 By doing none of above, in which case a default mapper instance is
    constructed (and configured if configuration methods are called)

The last method ("do nothing specific") is often good enough; explicit passing
of Mapper is simple and explicit; and Provider-based method may make sense
with Depedency Injection frameworks, or if Mapper has to be configured differently
for different media types.

Note that the default mapper instance will be automatically created if
one of explicit configuration methods (like configure)
is called: if so, Provider-based introspection is NOT used, but the
resulting Mapper is used as configured.

Note: version 1.3 added a sub-class (JacksonJaxbJsonProvider) which
is configured by default to use both Jackson and JAXB annotations for configuration
(base class when used as-is defaults to using just Jackson annotations)

正如其名,您还可以使用JacksonJaxbJsonProvider


1
根据我的经验,这个错误很常见,由于某种原因,Jersey有时会在解析自定义Java类型时出现问题。通常,您只需要确保遵守以下3个条件:
  1. 如果使用Maven,请在pom.xml中添加jersey-media-json-jackson或将其添加到构建路径中;
  2. 在您尝试进行序列化/反序列化的数据类型中,必须有一个空构造函数;
  3. 对于您的自定义数据类型,在类和字段级别上都必须具有相关注释(xmlelement和/或jsonproperty);
但是,我曾遇到过这些条件不足以解决问题的情况。那么,您可以始终将您的自定义数据类型包装在GenericEntity中,并将其作为此类对象传递给ResponseBuilder:
GenericEntity<CustomDataType> entity = new GenericEntity<CustomDataType>(myObj) {};
return Response.status(httpCode).entity(entity).build();

这种方式可以帮助jersey找到适合您对象的正确/相关序列化提供程序。 但有时这还不够。在我的情况下,我试图从自定义数据类型生成text/plain。理论上,jersey应该使用StringMessageProvider,但由于某些原因,我没有发现它给了我这个错误:

org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=text/plain

对我来说解决问题的方法是使用Jackson的writeValueAsString()进行自己的序列化。虽然我不太自豪,但最终我能提供一个可接受的解决方案。


是的,这意味着你正在尝试对一个数据类型进行反/序列化,但它的构造函数为空 - java dev

0
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>3.1.0-M8</version>
</dependency>

这个对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接