简体   繁体   中英

Serialization and deserialization of Map with Jersey and Jackson

I've got one Pojo object which is serialized by Jersey using jackson:

public class BookOfFriendsAnswer {
private Map<String, List<BookSummary>> books;

public BookOfFriendsAnswer() {

}

public BookOfFriendsAnswer(Map<String, List<BookSummary>> books) {
    this.books = books;
}

public Map<String, List<BookSummary>> getBooks() {
    return books;
}

public void setBooks(Map<String, List<BookSummary>> books) {
    this.books = books;
}
}

The serialization produces a JSon like this one:

{
  "books": {
    "entry": [
      {
        "key": "54567bbce4b0e0ef9379993e",
        "value": "BookSummary{id='54567bbde4b0e0ef9379993f', title='title 1', authors=[Steve,James] } BookSummary{id='54567bd9e4b0e0ef93799940', title='Title 2', authors=[Simon, Austin]}"
      }
    ]
  }
}

However, when I'm trying to deserialize the message from my client like this:

mapper.readValue(json, clazz)

I get the following error:

Unrecognized field "key" (class com.example.server.api.BookSummary), not marked as ignorable

I don't know if the problem comes from the JSOn produced by the server or the deserialization on client's side.

Do you know what is the problem and how to correct it?

Thanks a lot

So after a little testing with:

  • Jersey 1.18.1 (with jersey-json-1.18.1 for JSON support)
  • Jersey 2.13 (with jersey-media-json-jackson-2.13 for JSON support)
  • Jersey 2.13 (with jersey-media-moxy-2.13 for JSON support)

The last test (jersey-media-moxy-2.13) was the only one to produce this exact output

{
  "books": {
    "entry": [
      {
        "key": "54567bbce4b0e0ef9379993e",
        "value": "BookSummary{id='54567bbde4b0e0ef9379993f', title='title 1', authors=[Steve,James] } BookSummary{id='54567bd9e4b0e0ef93799940', title='Title 2', authors=[Simon, Austin]}"
      }
    ]
  }
}

That being said, I'll make the assumption you're using a Jersey 2.x version. I'm not sure if there is any configuration in MOXy to better support this use case, but to make things easy, just add the following dependency, and get rid of the MOXy

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey-version}</version>
</dependency>

With this, you will get the correct JSON output

{ //  BookOfFriendsAnswer object
    "books": {  // Map<String, List<BookSummary>> books
        "randomKey": [  // String (key) , List<BookSummary> (value)
            {  // BookSummary object
                "id": "54567bbde4b0e0ef9379993f",
                "title": "Title 1",
                "authors": ["Steve", "James"]
            }
        ]
    }
}

Simple Test

Resource method

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getResponse() {
    BookOfFriendsAnswer books = new BookOfFriendsAnswer();
    String id = "randomKey";  <===== Not sure if you want the key to be 
                                     the BookSummary id
    BookSummary summary = new BookSummary();
    summary.setId(id);
    summary.setTitle("Title 1");
    summary.getAuthors().add("Steve");
    summary.getAuthors().add("James");
    List<BookSummary> summaries = new ArrayList<>();
    summaries.add(summary);
    books.getBooks().put("randomKey", summaries);
    return Response.ok(books).build();
}

Test With ObjectMapper

@Test
public void testGetIt() throws Exception {
    String responseMsg = target.path("book").request().get(String.class);
    ObjectMapper mapper = new ObjectMapper();
    BookOfFriendsAnswer books = mapper.readValue(
            responseMsg, BookOfFriendsAnswer.class);
    System.out.println(books);
}

Test Without ObjectMapper - Using the automatically configured Jackson provider

@Test
public void testGetIt() throws Exception {
    BookOfFriendsAnswer responseMsg
            = target.path("book").request().get(BookOfFriendsAnswer.class);
    System.out.println(responseMsg);
}

I think that you should create specific Map type and provide it into deserialization process:

TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, ArrayList.class);
HashMap<String, List<BookSummary>> map = mapper.readValue(json, mapType);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM