Reputation: 839
My problem today is that I have this kind of JSON,
with an array of objects, each object having
two properties: type
and value
.
[{
"type": "Boolean",
"value": false
}, {
"type": "String[]",
"value": ["one", "two", "three"]
}]
As you see, the value
class depends on the type
.
I may have a type: MyClass
, with value
being a complex object.
I want to be able to deserialize this array (and serialize it back into JSON afterwards).
I started looking into the Gson library, but I may change anytime. From what I've read, there is only one way I know of:
public class MyExtractor implements JsonDeserializer<Object> {
@Override
public Object deserialize(JsonElement elem, Type jtype,
JsonDeserializationContext jdc) throws JsonParseException {
// elem is an object
JsonObject obj = elem.getAsJsonObject();
String type = obj.get("type").getAsString();
// Return a different kind of Object depending on the 'type' attr
switch (type) {
case "Boolean":
Boolean bool = obj.get("value").getAsBoolean();
return bool;
case "String[]":
JsonArray data = obj.get("value").getAsJsonArray();
List<String> list = new ArrayList<String>();
for (JsonElement item : data) {
list.add(item.getAsString());
}
return list;
}
}
}
And here I add code to associate each type
to its proper class.
This will probably work as I want, but is there a better way?
This one ends up requiring quite a lot of template.
Also, the deserialized items are cast into Object
so I don't
have access to their methods without reading their getClass()
and
casting them back, and I can't benefit from overloading.
Are there libraries with different approaches to the problem?
Upvotes: 2
Views: 1654
Reputation: 22271
pretius-jddl is capable of deserialization based on the existence or value of particular fields. The example in readme is almost exactly what you want.
In your case you'd have to create two rules that distinguish deserialization depending on the value of type
:
DynamicObjectDeserializer deserializer = new DynamicObjectDeserializer();
deserializer.addRule(DeserializationRuleFactory.typeByFieldValue(1,
"type", "Boolean", Boolean.class));
deserializer.addRule(DeserializationRuleFactory.typeByFieldValue(1,
"type", "String[]", String[].class));
There's more information on this blog post about jddl
Upvotes: 0
Reputation: 26926
If You can change the original json from:
[{
"type": "Boolean",
"value": false
}, {
"type": "String[]",
"value": ["one", "two", "three"]
}]
to
[false, ["one", "two", "three"]]
You can simply deserialize it as
String jsonString = ...
Object[] result = new Gson().fromJson(jsonString, Object[].class);
This work well for each standard type (String
, Boolean
, Integer
...), for custom classes it will create a Map
.
For example if the jsonString
has content
["testString", false, {"name":"Davide", "surname":"Marino"}]
it will generate an Object array with:
String
testString in first positionBoolean
false in second positionMap
with properties name (with value Davide) and surname (value Marino) in third position If You don't need to handle existing java classes, but you have 3 4 custom classes you can use a polimorphic deserialization.
Basically you need to create a custom interface (or base class) and implement (or extend) it. To see a more complete example see the accepted answer of
Gson serialize a list of polymorphic objects
Upvotes: 2
Reputation: 1869
You can try jolt json transformer and then use one of the standard mappers (Jackson, gson ect)
Upvotes: 1