Reputation: 464
I am trying to map some JSON into a pojo. I've seen how to do it with using information in the actual data, but it my case I don't really have anything identifying how the data is different, but I do know what the list is made up of. In the example below, I could be getting a list of prisoners or buildings, but in this case I know I am getting a list of prisoners.
I am given the JSON below (I know the nested data is odd, but I am being given the JSON, I have no control over it.)
{
"data": [{
"data": {
"create_date": "2015-09-30",
"building": "12",
"dob": "2/11/1965",
"gender": "M",
"location": {
"zip": "10459"
},
"name": {
"first": "James",
"last": "Bond"
},
"id": "45"
},
"uri": "/prisoner/45"
}, {
"data": {
"create_date": "2015-09-27",
"building": "12",
"dob": "12/15/1985",
"gender": "M",
"location": {
"zip": "10459"
},
"name": {
"first": "Hans",
"last": "Gruber"
},
"id": "56"
},
"uri": "/prisoner/56"
}],
"totals": {
"total": 2,
"page": 1
},
"links": [{
"uri": "/prisoners?limit=2"
}]
}
I have a Data object that contains a totals object and a links object. I also have a Collection (in this case, a list) of a Datum object that contains the nested Data object array. The Datum object has a Thing abstract class along with a Uri string. I have a Prisoner and a Building class extending Thing. In the above JSON, I know I am getting a list of prisoners.
My current code:
ObjectMapper mapper = new ObjectMapper();
Data data = mapper.readValue(responseJSON.toString(), Data.class);
If I go into Datum and change the Thing object to the Prisoner object, it works perfectly. My question is how do I make it accept Prisoner or Building but still have the abstract Thing class in place, or at least make it so it can be more generic. I know I can make several Datum classes, but I believe there must be a way to have 1 Datum class. I actually have dozens of different possibilities of data I could get, not just the 2 in my example.
Upvotes: 2
Views: 327
Reputation: 133542
Do you mean, you know what the types of Thing will be at the time that you read the value? Because in that case, you could parameterise Data (i.e. Data<T extends Thing>
), and propagate the type parameter to Datum to specify the subclass of Thing that you have. And then you need to tell Jackson about the parameterised type when you call readValue, which can be done statically like this:
mapper.readValue(jsonString, new TypeReference<Data<Prisoner>>(){});
It can be done dynamically by constructing a parameterised type using the TypeFactory available from the ObjectMapper. Something like:
mapper.readValue("", mapper.getTypeFactory()
.constructParametricType(Data.class, thingSubclass));
Upvotes: 4