Lucas W. Lucas W. - 1 month ago 6
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 :

SendData.java :

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 :

{"actionType":"verify","parameters":{"myMap":{"15789":"hreher-489hre-gdsf","13057":"rtyuiop-4g8ezg","16741":"gfd456-uiop789"},"myString1":"myStringValue1","myString2":"myStringValue2"},"customClas":{"attr1":"value1","attr2":"value2"}}


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 :

{"sendData":{"actionType":"verify","parameters":{},"customClass":{"attr1":"value1","attr2":"value2"}}}


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

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.

Comments