Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert from JSon to multiple unknown java object types using GSon

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?

like image 812
Abe Avatar asked Jun 11 '13 16:06

Abe


People also ask

How do you convert JSON to Java object?

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.

How do I deserialize JSON with Gson?

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.

What does Gson toJson do?

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.

What is difference between fromJson and toJson?

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.


2 Answers

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;
  }
}
like image 137
PomPom Avatar answered Sep 27 '22 18:09

PomPom


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.

like image 27
MikO Avatar answered Sep 27 '22 20:09

MikO