SEVERE: A message body writer for Java class java.

2020-02-13 07:21发布

问题:

I am testing RESTful services and when I execute I am getting exceptions although I have the following jars in my class path(WEB-INF/lib), I am not using Maven and my JDK version is 1.5. Other questions regarding this issue didn't help to resolve the problem.

Code snippet

@GET
@Produces("application/json")    
//@Produces({MediaType.APPLICATION_JSON}) tried this, didn't work either
public List<Emp> getEmployees() {        
    List<Emp> empList = myDAO.getAllEmployees();
    log.info("size   " + empList.size());
    return empList;
}

@XmlRootElement
public class Emp {
......

web.xml

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>test.employees</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>

 <servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

List of jars

jersey-server-1.2.jar
jersey-core-1.2.jar
jsr311-api-1.1.jar
asm-3.1.jar
jaxb-api-2.0.jar
jaxb-impl-2.0.jar
jackson-xc-1.2.0.jar
jackson-jaxrs-1.2.0.jar
jackson-mapper-asl-1.2.0.jar
jackson-core-asl-1.2.0.jar
jettison-1.2.jar
jersey-client-1.2.jar
jersey-servlet-1.10.jar
jersey-json-1.8.jar

Exception stack

 SEVERE: A message body writer for Java class java.util.ArrayList,
 and Java type java.util.List<test.Emp>, 
 and MIME media type application/json was not found
Nov 21, 2013 11:47:26 AM com.sun.jersey.spi.container.ContainerResponse traceException
SEVERE: Mapped exception to response: 500 (Internal Server Error)

javax.ws.rs.WebApplicationException
    at javax.ws.rs.WebApplicationException.<init>(WebApplicationException.java:97)
    at javax.ws.rs.WebApplicationException.<init>(WebApplicationException.java:55)
    at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:267)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1035)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:947)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:939)
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:399)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:478)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:663)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
    at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:719)
    at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:376)
    at com.evermind.server.http.HttpRequestHandler.doProcessRequest(HttpRequestHandler.java:870)
    at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:451)
    at com.evermind.server.http.HttpRequestHandler.serveOneRequest(HttpRequestHandler.java:218)
    at com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:119)
    at com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:112)
    at oracle.oc4j.network.ServerSocketReadHandler$SafeRunnable.run(ServerSocketReadHandler.java:260)
    at oracle.oc4j.network.ServerSocketAcceptHandler.procClientSocket(ServerSocketAcceptHandler.java:230)
    at oracle.oc4j.network.ServerSocketAcceptHandler.access$800(ServerSocketAcceptHandler.java:33)
    at oracle.oc4j.network.ServerSocketAcceptHandler$AcceptHandlerHorse.run(ServerSocketAcceptHandler.java:831)
    at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:303)
    at java.lang.Thread.run(Thread.java:595)

How can I resolve this issue?

回答1:

Make sure you don't have multiple Jersey versions in your project. From the list you provided there are modules from 3 different versions (1.2, 1.10, 1.8). For some modules Jersey does a check that the version of a module is the same as the version of the core. If it's not then providers of the module (such as MessageBodyReaders, MessageBodyWriters) are not registered in the runtime. This can be problem in your setup - json vs core (1.8 vs 1.2).



回答2:

The problem may be how you're trying to return your result. I have seen others write their service-layer code this way too, but Jersey provides a way to do it cleanly and it will support JSON, XML and HTML output which you only need to specify using your @Produces annotation. This is what I do:

import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.Response;

@GET
@Produces( MediaType.APPLICATION_JSON )
public Response getEmployees()
{        
    List< Emp >                  matched;
    GenericEntity< List< Emp > > entity;

    matched = myDAO.getAllEmployees();
    entity  = new GenericEntity< List< Emp > >( matched ) { };

    return Response.ok( entity ).build();
}

I'm using the following Jersey libraries:

  • jersey-core-1.8.jar
  • jersey-json-1.8.jar
  • jersey-server-1.8.jar


回答3:

You cannot define the response Xml as List<Emp>, as the JAXB is unable to identify the @XmlRootElement over the java.util.List or java.util.ArrayList class definition.

Ideally, you should have one parent/root element for your collection of Child Elements.

Create one more Class as Employees to contains the Collection of Emp objects as like below and try it.

@GET
@Produces("application/json")    
public Employees getEmployees() {        
    List<Emp> empList = myDAO.getAllEmployees();
    log.info("size   " + empList.size());
    Employees employees = new Employees();
    employees.setEmployeeList(empList);

    return employees;
}

@XmlRootElement(name = "Employees")
public class Employees {

    List<Emp> employeeList;

    //setters and getters goes here
}

@XmlRootElement()
class Emp {
   //fields here
}

Please try this approach, it will work.



回答4:

Add this to your pom.xml. Solved my problem.

        <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.18.1</version>
    </dependency>
    <dependency>
        <groupId>com.owlike</groupId>
        <artifactId>genson</artifactId>
        <version>0.99</version>
    </dependency>


回答5:

Specifying @XmlRootElement(name = "yourclass") on the class you want to pass as output. This has solved the problem for me when I get this exception.



回答6:

I had the same problem.

The thing is it knows how to convert it to xml with the annotation @XmlRootElement but it doesn't know how to convert it to JSON.

So for making it convert everything to JSON with the same annotation of xml(ie @XmlRootElement) we can add

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

or for maven users

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

Also it should have a no argument constructor



回答7:

You have to declare in the servlet container of jersey the param as the following:

'com.sun.jersey.api.json.POJOMappingFeature' like this: 
 <servlet>
    <servlet-name>myServices</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>services</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>


回答8:

cross check your pojo class may be not done the JAXBinding if not done mark your pojo with @XmlRootElement