-1

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.

knittl
  • 246,190
  • 53
  • 318
  • 364

1 Answers1

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;}
    }
}
knittl
  • 246,190
  • 53
  • 318
  • 364
  • 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 Oct 04 '22 at 15:21
  • 1
    @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. – knittl Oct 04 '22 at 17:10