Rest JAX-RS exception, MessageBodyWriter not found

2019-07-15 09:15发布

问题:

I am using Jersey 2.13

I get MessageBoddyWriter not found exception when I try to access a resource via a url in a browser.

Exception:

MessageBodyWriter not found for media type=application/json, 
type=class java.util.ArrayList, genericType=java.util.List<com.webservices.entity.Book>.

I have another method that produces "APPLICATION_XML" and that seems to work fine.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Book { 
    @XmlElement
    private String name;    
    @XmlElement
    private String author;
    //getters setters
}

@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
public List<Book> getJsonResponse(JAXBElement<Book> book){
    return new ArrayList<Book>();
}

My thought was jersey would automatically find the "JacksonJsonProvider", a message writer class, provided by Jackson but it doesn't.

My lib folder:

回答1:

According to mkyong jersey+jackson tutorial, you need to add com.sun.jersey.api.json.POJOMappingFeature param in your web.xml to integrate them

<servlet>
    <servlet-name>jersey-serlvet</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>com.mkyong.rest</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>


回答2:

Starting with Jersey 2.9, automatic discovery of converter classes has been disabled. You have to register the converter class of your JSON library with Jersey manually. Here is what I do (I'm using Genson):

@ApplicationPath( "/api/library" )
public class RestService extends Application {
   @Override
   public Set<Class<?>> getClasses( ) {
      final Set<Class<?>> returnValue = new HashSet<Class<?>>( );
      returnValue.add( GensonJsonConverter.class );
      return returnValue;
   }
}


回答3:

If you want to make your application code support both xml and json you need to create a wrapper object to support the collection rather than returning a GenericType. The PojoMappingFeature will work as it uses the native Jackson ObjectMapper instead of using the jaxb annotations for marshalling the object.

If you want it to be portable the best solution is to create a simple wrapper object as such.

@XmlRootElement
public class Books {

   private List<Book> books;

   public Books() {
   }

   public Books(List<Book> books) {
       this.books = books;
   }

   @XmlElement(name="book")
   public List<Book> getBooks() {
      return books;
   }

   public void setBooks(List<Book> books) {
      this.books = books;
   }
}


@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
public Books getJsonResponse(JAXBElement<Book> book){
    return new Books(new ArrayList<Book>());
}

If you decide you want to also support MediaType.APPLICATION_XML then this is required. This will also solve the json (jackson) problem.