Lucas W. Lucas W. - 1 year ago 54
Java Question

Use Gson library with a generic class as a field of the class to serialize

After multiple researches on Google and Stack Overflow, i haven't found a similar case to mine.

I need to use Gson library to convert a Java object to Json. The fact is that this object contains a field with a custom generic type, as follow : :

public class SendData {
private SendDataRequestObject<?> sendData;

// Constructor + Getters and Setters

Here is the class definition of SendDataRequestObject :

public class SendDataRequestObject<T> {
private String actionType;
private T parameters;
private CustomClass customClass;

//Constructor + Getters and Setters

And finally, the class definition of MyRequest which may be injected in SendDataRequestObject as the T parameter

public class MyRequest {
private Map<Integer, String> myMap;
private String myString1;
private String myString2;

//Constructor + Getters and Setters

Actually, I'm able to parse SendDataRequestObject with Gson library as follow :

SendDataRequestObject<MyRequest> requestObject = new SendDataRequestObject<MyRequest>();
//Initializing and adding fields to requestObject
Type token = new TypeToken<SendDataRequestObject<MyRequest>>(){}.getType();
System.out.println(new GsonBuilder().create().toJson(requestObject, token));

The output is properly set and every fields, even the generic one, are included into the final json string :


But what I need is to parse SendData class, not SendDataRequestObject class. When I try to convert this class into json string, I obtain this output :


So, we can see that parameters field of SendDataRequestObject is not converted to Json, probably because this is a generic class.

If anybody has an idea of how to do it, I would be very grateful !

Answer Source

You can't do this without somehow knowing the type T at compile time in some manner due to Java's type erasure.

One option for this is the JSON can contain some information specifying the type, e.g.

  "sendDataType": "MyRequest",
  "sendData": {

If you then make SendData generic e.g.

SendData<T> { 
  private SendDataRequestObject<T> sendData; 

you can then parse the JSON once to find out the sendDataType:

SendData<?> genericSendData = new GsonBuilder().create().toJson(requestObject, new TypeToken<SendData<?>>(){});
String sendDataType = genericSendData.sendDataType;

and use that to create a TypeToken of the right type:

switch(sendDataType) {
  case "MyRequest":
    return new TypeToken<MyRequest>(){};

And then parse the JSON again specifying the generic type now that you know it:

SendData<?> myRequestSendData = new GsonBuilder().create().toJson(requestObject, typeToken);

This works because our switch statement knows the possible types at compile time and can create TypeTokens for them.