问题
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