I have a netty decoder which uses GSon to convert JSon coming from web client to appropriate java objects.
The requirement is:
Client could be sending unrelated classes, Class A, Class B, Class C etc but I would like to use the same singleton decoder instance in the pipeline to do conversion(since I use spring for configuring it). The issue I am facing is I need to know the class
object before hand.
public Object decode()
{
gson.fromJson(jsonString, A.class);
}
This cannot decode B or C. The users of my library, now need to write separate decoders for each class instead of a cast later down the line. The only way I can see for doing this is to pass the String name of the class say "org.example.C" in the JSon string from web client, parse it out in the decoder and then use Class.forName
to get the class. Is there a better way to do this?
We can convert a JSON to Java Object using the readValue() method of ObjectMapper class, this method deserializes a JSON content from given JSON content String.
Deserialization in the context of Gson means converting a JSON string to an equivalent Java object. In order to do the deserialization, we need a Gson object and call the function fromJson() and pass two parameters i.e. JSON string and expected java type after parsing is finished. Program output.
Gson is the main actor class of Google Gson library. It provides functionalities to convert Java objects to matching JSON constructs and vice versa. Gson is first constructed using GsonBuilder and then toJson(Object) or fromJson(String, Class) methods are used to read/write JSON constructs.
There are two parameters in the fromJson() method, the first parameter is JSON String which we want to parse and the second parameter is Java class to parse JSON string. We can pass one parameter into the toJson() method is the Java object which we want to convert into a JSON string.
GSon MUST know the class matching the json string. If you don't wan't to provide it with fromJson(), you can actually specify it in the Json. A way is to define an interface and bind an adapter on it.
Like :
class A implements MyInterface {
// ...
}
public Object decode()
{
Gson gson = builder.registerTypeAdapter(MyInterface.class, new MyInterfaceAdapter());
MyInterface a = gson.fromJson(jsonString, MyInterface.class);
}
Adapter can be like :
public final class MYInterfaceAdapter implements JsonDeserializer<MyInterface>, JsonSerializer<MyInterface> {
private static final String PROP_NAME = "myClass";
@Override
public MyInterface deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
String classPath = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<MyInterface> cls = (Class<MyInterface>) Class.forName(classPath);
return (MyInterface) context.deserialize(json, cls);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public JsonElement serialize(MyInterface src, Type typeOfSrc, JsonSerializationContext context) {
// note : won't work, you must delegate this
JsonObject jo = context.serialize(src).getAsJsonObject();
String classPath = src.getClass().getName();
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}
Suppose you have these 2 possible JSON responses:
{
"classA": {"foo": "fooValue"}
}
or
{
"classB": {"bar": "barValue"}
}
You can create a class structure like this:
public class Response {
private A classA;
private B classB;
//more possible responses...
//getters and setters...
}
public class A {
private String foo;
//getters and setters...
}
public class B {
private String bar;
//getters and setters...
}
Then you can parse any of the possible JSON responses with:
Response response = gson.fromJson(jsonString, Response.class);
Gson will ignore all the JSON fields that don't correspond with any of the attributes in your class structure, so you can adapt a single class to parse different responses...
Then you can check which of the attributes classA
, classB
, ... is not null
and you'll know which response you have received.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With