0

My JSON structure might be part of the problem but this is what I'm working with:

{
   "data":[
      {
         "id":"1",
         "title":"hello"
      }
   ]
}

I want to simply print out the value of id.

Here is my Java main class:

public static void main(String[] args){
        ObjectMapper objectMapper = new 
        ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        List<Data> data = objectMapper.readValue(out, new TypeReference<List<Data>>(){});
        System.out.println("data = " + data.get(0).getId());
}

Here is my Data class:

private String id;
private String title;
public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}
public String getTitle() {
    return title;
}
public void setTitle(String title) {
    this.title = title;
}

It only ever prints null. But it seems like it should work since I have one instance of Data in the List, then I fetch the first (and only) instance and then try to fetch id.

0

1 Answer 1

2

TypeReference<List<Data>> matches the following, different JSON string:

[
   {
      "id":"1",
      "title":"hello"
   }
]

You need another wrapper class with a List<Data> data field or use a map to deserialize.

With a map:

Map<String, List<Data>> data = objectMapper.readValue(out, new TypeReference<Map<String, List<Data>>>(){});
System.out.println("data = " + data.get("data").get(0).getId());

Wrapper class:

class Wrapper {
  private List<Data> data;
  public List<Data> getData() { return data; }
  public void setData(final List<Data> data) { this.data = data; }
}

// ...
Wrapper data = objectMapper.readValue(out, new TypeReference<Wrapper>(){});
System.out.println("data = " + data.getData().get(0).getId());

Following is a fully functional JUnit 5 test parsing the input JSON string and asserting the correct value:

class Question {
    @Test
    void deserialize() throws JsonProcessingException {
        final ObjectMapper objectMapper = new ObjectMapper()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

        final String input = "{\n"
                + "   \"data\":[\n"
                + "      {\n"
                + "         \"id\":\"1\",\n"
                + "         \"title\":\"hello\"\n"
                + "      }\n"
                + "   ]\n"
                + "}";

        final Map<String, List<Data>> map = objectMapper.readValue(input, new TypeReference<>() {});
        Assertions.assertEquals("1", map.get("data").get(0).getId());

        final Wrapper wrapper = objectMapper.readValue(input, new TypeReference<>() {});
        Assertions.assertEquals("1", wrapper.getData().get(0).getId());
    }

    private static class Wrapper {
        private List<Data> data;

        public List<Data> getData() {return data;}
        public void setData(final List<Data> data) {this.data = data;}
    }

    private static class Data {
        private String id;
        private String title;

        public String getId() {return id;}
        public void setId(final String id) {this.id = id;}

        public String getTitle() {return title;}
        public void setTitle(final String title) {this.title = title;}
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

hmmm....both the examples you provided result in the same runtime error: Cannot deserialize value of type java.lang.String from Array value (token JsonToken.START_ARRAY)
@Shawman then your question does not accurately reflect your input JSON or withholds other important details. I have updated my answer with a fully functional program as JUnit test showing that parsing works as expected when the correct type is provided.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.