Jackson deserialization - aggregate several fields

风格不统一 提交于 2019-12-24 08:15:10

问题


suppose I've got a collection of people defined like this in JSON.

{
        "NOM": "Doe",
        "PRENOM": "John",
        "EMAIL": "john.doe@email.me",
        "VILLE": "Somewhere",
        "LIKE1": "Lolcats",
        "LIKE2": "Loldogs",
        "LIKE3": "Lolwut",
        "HATE1": "Bad stuff",
        "HATE2": "Bad bad stuff"
}

Is it possible to write a JsonDeserializer that will aggregate and transform LIKE* and HATE* fields into a collection of Liking, set as a property of Person? (Note that there are only LIKE1, LIKE2, LIKE3, HATE1, HATE2.)

The final result properties would be something like:

public class Person {
    private final String lastName;
    private final String firstName;
    private final String email;
    private final String town;
    private final Collection<Liking> likings;
    // c-tor, getters
}

I've already the logic that can deserialize a given LIKE*/HATE* property into a Liking object but I fail to understand to aggregate and add them to a Person liking attribute.

Thx in advance!


回答1:


It would have been nice if you had some code that showed you began the process of solving this problem yourself. But, here is a sample custom deserializer that does pretty much what you're looking for:

class PersonDeserializer extends JsonDeserializer<Person> {

    @Override
    public Person deserialize(final JsonParser parser,
            final DeserializationContext content) throws IOException,
            JsonProcessingException {

        final ObjectCodec codec = parser.getCodec();
        final JsonNode node = codec.readTree(parser);

        final Person person = new Person();
        final Iterator<String> fieldNameIter = node.getFieldNames();
        while (fieldNameIter.hasNext()) {
            final String fieldName = fieldNameIter.next();
            if (fieldName.equalsIgnoreCase("EMAIL")) {
                person.setEmail(node.get(fieldName).getTextValue());
            } else if (fieldName.equalsIgnoreCase("NOM")) {
                person.setFirstName(node.get(fieldName).getTextValue());
            } else if (fieldName.equalsIgnoreCase("PRENOM")) {
                person.setLastName(node.get(fieldName).getTextValue());
            } else if (fieldName.equalsIgnoreCase("VILLE")) {
                person.setTown(node.get(fieldName).getTextValue());
            } else if (fieldName.startsWith("LIKE")) {
                person.addLike(Liking.LikingType.LIKE, node.get(fieldName)
                        .getTextValue());
            } else if (fieldName.startsWith("HATE")) {
                person.addLike(Liking.LikingType.HATE, node.get(fieldName)
                        .getTextValue());
            }
        }

        return person;
    }
}

It presumes a Liking object similar to this:

public class Liking {
    public static enum LikingType {
        LIKE, HATE;
    }

    private LikingType type;

    private String value;

    // Constructors, getters/setters
}

And some changes to your Person object which I think you can figure out. If you intend to serialize the object to JSON in the same custom format then you will have to write a corresponding JsonSerializer.

Another option, not quite as robust, would be too simply use a map to store the likes and dislikes exactly as is. This solution would omit any explicit mappings for likes/dislikes and utilize the @JsonAny annotation to capture them. In this scheme the Person object would look like this:

public class Person {
    private String lastName;
    private String firstName;
    private String email;
    private String town;
    @JsonAny
    private Map<String, Object> otherProperties;

    // Constructors, getters/setters
}

Deserializing your JSON into this modified version of Person will place all unrecognized properties into the hash map, as key-value pairs.




回答2:


I'm pretty sure you can't do it the way you intend, how about doing it like this:

{
        "NOM": "Doe",
        "PRENOM": "John",
        "EMAIL": "john.doe@email.me",
        "VILLE": "Somewhere",
        "likings": ["Lolcats", "Loldogs", "LIKE3": "Lolwut", "Bad stuff", "Bad bad stuff" ]
}


来源:https://stackoverflow.com/questions/15283502/jackson-deserialization-aggregate-several-fields

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!