Serializing and Deserializing a Card with Jersey and Jackson

I have one Pojo object that is serialized to 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;
}
}

      

Serialization creates a JSon like this:

{
  "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 try to deserialize a message from my client like this:

mapper.readValue(json, clazz)

      

I am getting the following error:

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

I don't know if the problem is from the server generated JSOn or client side deserialization.

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

Thank you so much

+3


source to share


2 answers


So after a little testing with:

  • Jersey 1.18.1 (with support jersey-json-1.18.1

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

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

    for JSON support)

The last test (jersey-media-moxy-2.13) was the only one able to get 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]}"
      }
    ]
  }
}

      

Having said that, I will make the assumption that you are using Jersey 2.x version. I'm not sure if there is any configuration in MOXy to better support this use case, but to keep things simple, just add the following dependency and get rid of 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 auto-configured Jackson provider

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

      

+5


source


I think you should create a specific type of card and provide it during the 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);

      

0


source







All Articles