Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealing with json field that is either an array or an object?

Tags:

java

json

jackson

So with this api that I’m using I often encounter json containing a field that is either an array or an object, and I’m not sure how to deal with this the right way.

What happens is that I have an array in my json which is

  • an empty array if there are no entries
  • an array of objects when there are more than one entries
  • actually not an array but an object when there is exactly one entry.

Here is an example to make things clearer:

none:

{
    "what": "kittens",
    "why": "I don't meow",
    "kittens": []
}

one:

{
    "what": "kittens",
    "why": "I don't meow",
    "kittens": {
        "name": "Ser Pounce",
        "gender": "male"
    }
}

many:

{
    "what": "kittens",
    "why": "I don't meow",
    "kittens": [
        {
            "name": "Ser Pounce",
            "gender": "male"
        },
        {
            "name": "Mr. Snuffles",
            "gender": "male"
        }
    ]
}

Now, if this wasn't the case and the second example looked like this

{
    "what": "kittens",
    "why": "I don't meow",
    "kittens": [
        {
            "name": "Ser Pounce",
            "gender": "male"
        }
    ]
}

I could just use a POJO

public class Kittens
{
    public String what;
    public String why;
    public List<Kitten> kittens;

    public static class Kitten
    {
        public String name;
        public String gender;
    }
}

and then deserialize everything the standard way:

Kittens kittens = objectMapper.readValue(good_kitten, Kittens.class);

So an alternative would be using the tree model and doing a lot of type checking manually (with JsonNode.isArray() etc.)

That wouldn't be viable though because there would be a lot of overhead, it wouldn't be elegant and did I mention there's also some nesting going on of course:

{
    "what": "kittens",
    "why": "I don't meow",
    "kittens": [
        {
            "name": "Ser Pounce",
            "gender": "male",
            "kittens": []
        },
        {
            "name": "Mr. Snuffles",
            "gender": "male",
            "kittens": {
                "name": "Waffles",
                "gender": "female",
                "kittens": [
                    {
                        "name": "Mittens",
                        "gender": "male",
                        "kittens": []
                    },
                    {
                        "name": "Winston",
                        "gender": "male",
                        "kittens": {
                            "name": "Fiona",
                            "gender": "female",
                            "kittens": []
                        }
                    }
                ]
            }
        }
    ]
}

Now I would really like to define a model like the following and be done with it

public class NestedKittens
{
    public String what;
    public String why;
    public List<Kitten> kittens;

    public static class Kitten
    {
        public String name;
        public String gender;
        public List<Kitten> kittens;
    }
}

But this won't work because in the json there are Plain Old Kitten Objects where there should be List<Kitten>.

So, are there any annotations or configurations available that make jackson convert from Kitten to List<Kitten> automagically when it needs to?

like image 658
florian Avatar asked Sep 25 '14 20:09

florian


People also ask

Can a JSON object contain an array?

In JSON, array values must be of type string, number, object, array, boolean or null. In JavaScript, array values can be all of the above, plus any other valid JavaScript expression, including functions, dates, and undefined.

What is the difference between {} and [] in JSON?

{} denote containers, [] denote arrays.

Can you store an array in a JSON file?

JSON array can store string , number , boolean , object or other array inside JSON array. In JSON array, values must be separated by comma. Arrays in JSON are almost the same as arrays in JavaScript.


1 Answers

The solution turned out to be really simple:

objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
like image 173
florian Avatar answered Nov 04 '22 02:11

florian