0

I am expecting to get from a json a LinkedList<Request>. The pojos look like this:

@Data
@Builder
public class Request {
    private String id;
    private List<Parameter> parameters;
}

@Data
@SuperBuilder
public abstract class Parameter implements Serializable {
    private String key;
    public abstract Object getValue();
}

@Data
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
public class StringParameter extends Parameter implements Serializable {
    private String value;
}

@Data
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
public class PasswordParameter extends Parameter implements Serializable {
    private String value;
}

The serialization works fine, it generates the json, but it crashes at deserialization (maybe it's the abstract class or/and that I am expecting a LinkedList and/or the lombok annotations)? I tryed writting a gson deserializer (quite a standard one found googling), but it doesn't do the job.

Tatiana B
  • 101
  • 9
  • 1
    You cannot do that unless you can distinguish between concrete parameters in principle (structurally, `StringParameter` and `PasswordParameter` are equivalent and there is no way to reconstruct the initial class). Structural deserialization is pretty hard as it takes more computation, time. One of possible solutions is adding the discriminating field to `Parameter` holding the concrete type name. See https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java – terrorrussia-keeps-killing Oct 11 '20 at 07:04
  • 1
    `RuntimeTypeAdapterFactory` is not bundled with Gson so you have simply copy it to your codebase (and this is what folks typically do with it). However, not sure if adding the `type` field would work fine with Lombok as the `type` field is supposed to be constant across any `Parameter` child classes. – terrorrussia-keeps-killing Oct 11 '20 at 07:07
  • 1
    Here you go: https://stackoverflow.com/questions/19588020/gson-serialize-a-list-of-polymorphic-objects/22081826#22081826 – terrorrussia-keeps-killing Oct 11 '20 at 07:08

1 Answers1

0

Thanks to @fluffy's suggestion, I managed to skip writing a custom deserialiser and making use of RuntimeTypeAdapterFactory from gson-extras library:

public static void writeObjectToFile(Object object, String filePath) {
      RuntimeTypeAdapterFactory<Parameter> parameterAdapterFactory = RuntimeTypeAdapterFactory.of(Parameter.class, "type");
      parameterAdapterFactory.registerSubtype(StringParameter.class, "StringParameter");
      parameterAdapterFactory.registerSubtype(PasswordParameter.class, "PasswordParameter");
      Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapterFactory(parameterAdapterFactory).create();
      try {
          FileWriter fileWriter = new FileWriter(filePath);
          gson.toJson(object, fileWriter);
          fileWriter.flush();
          fileWriter.close();
      } catch (IOException e) {
          System.out.println(e.getMessage());
      }
  }

  public static LinkedList<Request> readObjectFromFile(String filePath) {
      RuntimeTypeAdapterFactory<Parameter> parameterAdapterFactory = RuntimeTypeAdapterFactory.of(Parameter.class, "type");
      parameterAdapterFactory.registerSubtype(StringParameter.class, "StringParameter");
      parameterAdapterFactory.registerSubtype(PasswordParameter.class, "PasswordParameter");
      Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapterFactory(parameterAdapterFactory).create();
      try {
          BufferedReader jsonBuffer = new BufferedReader(new FileReader(filePath));
          return gson.fromJson(jsonBuffer, new TypeToken<LinkedList<Request>>(){}.getType());
      } catch (FileNotFoundException e) {
          System.out.println(e.getMessage());
      }
      return  null;
  }

I also kept only the lombok annotations and did not write constructors and getters/setters for my POJOs

Tatiana B
  • 101
  • 9