3

I am not able to unmarshall a JSON key which can hold either a string value or an another JSON Object using Jackson Library.

Ex:- Below are the two possible values.

1)

"ProviderData": {
    "INVALID": "HEX",
    "#text": "Sample"
}

2)

"ProviderData": "1C"

Could someone please verify and suggest me on this issue.

Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
carao
  • 53
  • 3

2 Answers2

0

you could deserialize to JsonNode and then extract the contents individually, or deserialize to an Object and use instanceof to determine if it's a Map or another type, or use a custom deserializer to unpack the data into a custom object that handles both cases.

jspcal
  • 50,847
  • 7
  • 72
  • 76
0

You can write custom deserialiser and handle these both cases or write two constructors for ProviderData POJO class and properly use JsonCreator and JsonCreator annotations. See below example:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        System.out.println(mapper.readValue(jsonFile, Response.class));
    }
}

class Response {

    @JsonProperty("ProviderData")
    private ProviderData data;

    // getters, setters, toString
}

class ProviderData {

    private static final String INVALID_NAME = "INVALID";
    private static final String TEXT_NAME = "#text";

    @JsonProperty(INVALID_NAME)
    private final String invalid;

    @JsonProperty(TEXT_NAME)
    private final String text;

    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public ProviderData(String invalid) {
        this(invalid, null);
    }

    @JsonCreator
    public ProviderData(@JsonProperty(INVALID_NAME) String invalid, @JsonProperty(TEXT_NAME) String text) {
        this.invalid = invalid;
        this.text = text;
    }

    // getters, toString
}

For this JSON payload:

{
  "ProviderData": {
    "INVALID": "HEX",
    "#text": "Sample"
  }
}

Above example prints:

Response{data=ProviderData{invalid='HEX', text='Sample'}}

And for String primitive JSON payload:

{
  "ProviderData": "1C"
}

Above example prints:

Response{data=ProviderData{invalid='1C', text='null'}}

As you can see, JSON Object is mapped properly using 2-arg constructor and String primitive is mapped using 1-arg constructor and we assume that this value means invalid key from JSON Object example.

See also:

  1. Custom JSON Deserialization with Jackson.
  2. sequentially deserialize using Jackson.
  3. Deserialize strings and objects using jackson annotations in java.
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • @AnkammaRao, I'm glad it works. Since you are new user, please, take a look at [How does accepting an answer work?](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) – Michał Ziober May 29 '19 at 21:37