简体   繁体   中英

Jackson Array Elements to POJO

I'm trying to deserialize an existing JSON document using Jackson, and was wondering if it was possible to perform the following translation without resorting to a stack of custom deserialization.

The input JSON looks like this:

{
    "type": "foo",
    "content": ["a", "b", {"some": "object", "goes": "here"}, 4]
}

The first 3 elements in content don't change, and are always String, String, SomeDataStructure, Integer (optional)

And I would like to deserialize into something like this:

class Foo {
    public static class FooContent {
        String some;
        String goes;
    }

    String aString;
    String bString;
    FooContent content;
    Integer cInt;      
}

Now I've already come across BeanAsArrayDeserializer, which sounds like it might be what I want, but I can't seem to find anything even remotely like a piece of example code to get me started.

So, any ideas?

You can always implement your custom deserializer. See below source code:

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

;

public class JacksonTest {

    public static void main(String[] args) throws Exception {
        String json = "{\"type\": \"foo\",\"content\": [\"a\", \"b\", {\"some\": \"object\", \"goes\": \"here\"}, 4]}";

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, true);

        Root pojo = mapper.readValue(json, Root.class);
        System.out.println(pojo);
    }
}

class Root {
    public String type;
    @JsonDeserialize(using = FooDeserializer.class)
    public Foo content;

    @Override
    public String toString() {
        return content.toString();
    }
}

class Foo {
    public static class FooContent {
        public String some;
        public String goes;

        @Override
        public String toString() {
            return "{" + some + ", " + goes + "}";
        }
    }

    String aString;
    String bString;
    FooContent content;
    Integer cInt;

    @Override
    public String toString() {
        return "Foo [aString=" + aString + ", bString=" + bString + ", content=" + content
                + ", cInt=" + cInt + "]";
    }
}

class FooDeserializer extends JsonDeserializer<Foo> {

    @Override
    public Foo deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
            JsonProcessingException {
        Foo f = new Foo();
        int index = 0;
        while (jp.nextToken() != JsonToken.END_ARRAY) {
            JsonToken token = jp.getCurrentToken();
            if (token.isStructStart()) {
                f.content = jp.readValueAs(Foo.FooContent.class);
                index++;
            } else {
                switch (index++) {
                case 0:
                    f.aString = jp.getText();
                    break;
                case 1:
                    f.bString = jp.getText();
                    break;
                case 3:
                    f.cInt = Integer.parseInt(jp.getText());
                    break;
                }
            }
        }
        return f;
    }
}

Above app prints:

Foo [aString=a, bString=b, content={object, here}, cInt=4]

The feature that allows to use the BeanAsArrayDeserializer (internally) is @JsonFormat . You can read some information about it in this blog post.

I also just learned about it recently, but I think a mapping that works for your case would look something like the following. You'd need a wrapper to hold the content field though, which would then be of type Foo .

@JsonFormat(shape = Shape.ARRAY)
@JsonPropertyOrder({ "aString", "bString", "content", "cInt" })
class Foo {
    public static class FooContent {
        String some;
        String goes;
    }

    @JsonFormat(shape = Shape.STRING)
    String aString;

    @JsonFormat(shape = Shape.STRING)
    String bString;

    FooContent content;

    @JsonFormat(shape = Shape.NUMBER)
    Integer cInt;      
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM