Skip to content
Advertisement

How to write common pojo deserializer for json attribute which can be an object and an array both?

Background:

I am getting mismatchedInputException, when parsing json. com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type java.util.ArrayList<Data> from Object value (token JsonToken.START_OBJECT)

Problem:

nodes is a json-array which contains data, which can be either json-object or json-array .

I need to represent this correctly in POJO.

Things Tried: Map<String, Object>, List, ,@JsonDeserialize(using = NodeDeserializer.class)

Below is my nested json document for ref.

{
  "parent": {
    "nodes": [
      {
        "data": {
          "desc": "a1",
          "url": "http://a1.a11"
        }
      },
      {
        "data": [
          {
            "desc": "b1",
            "url": "http://b1.b11"
          },
          {
            "desc": "b2",
            "url": "http://b2.b21"
          }
        ]
      }
    ]
  }
}

Below is Pojo Java classes and Runner class, I am using for SER/DE for above Json

Data.java

import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
class Data {
    @JsonProperty("desc")
    private String desc;

    @JsonProperty("url")
    private String url;
}

Node.java

import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
class Node {
    @JsonProperty("data")
    //Map<String, Object> data = new LinkedHashMap<>();
    //private List<Object> data;
    private List<Data> data;
}

Parent.java

import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
class Parent {
    @JsonProperty("nodes")
    private List<Node> nodes;
}

Test.java

import lombok.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Test {
    @JsonProperty("parent")
    private Parent parent;
}

Runner Class

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

public class TestJsonParse {
    public static void main(String[] args) throws JsonProcessingException {
        String jsonString = "{n" +
                "  "parent": {n" +
                "    "nodes": [n" +
                "      {n" +
                "        "data": {n" +
                "          "desc": "a1",n" +
                "          "url": "http://a1.a11"n" +
                "        }n" +
                "      },n" +
                "      {n" +
                "        "data": [n" +
                "          {n" +
                "            "desc": "b1",n" +
                "            "url": "http://b1.b11"n" +
                "          },n" +
                "          {n" +
                "            "desc": "b2",n" +
                "            "url": "http://b2.b21"n" +
                "          }n" +
                "        ]n" +
                "      }n" +
                "    ]n" +
                "  }n" +
                "}";

        // print pojo
        ObjectMapper objectMapper = new ObjectMapper();
        Test test = objectMapper.readValue(jsonString, Test.class);
        System.out.println(test);
    }
}

Advertisement

Answer

How to write common pojo deserializer for json attribute which can be an object and an array both?

It is possible if you use the JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY deserialization feature consisting of an override for the DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY feature which allows deserialization of JSON non-array values into single-element Java arrays and Collections. So you can annotate the data field of your Node class to obtain the expected behaviour:

class Node {
    @JsonProperty("data")
    @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
    private List<Data> data;
}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement