I have some polymorphic java classes which I am serializing/deserializing. I'm using RuntimeTypeAdapterFactory from Gson-extras to ensure the classes serialize and deserialize correctly with "type" field set to the name of the derived class. It's working fine.
I have some other classes which I am serializing/deserializing which have some variables with the transient modifier applied. I am using PostConstructAdapterFactory, also from Gson-extras, to add a PostConstruct method to my classes so the values of the transient variables can be re-assigned after deserialization has completed and before any of the functions in the classes are called. This is also working fine.
The challenge I have is that I have another group of classes which are polymorphic and also have transient variables where I'd like to have a PostConstruct method execute after deserialization. All of my attempts to use both the RuntimeTypeAdapterFactory and PostConstructAdapterFactory together have failed. I can register both but when I do the PostConstructAdapterFactory behaviour seems to overwrite RuntimeTypeAdapterFactory behaviour resulting in my classes no longer storing the "type" field needed for the polymorphic classes.
It seems I can have one or the other but not both. I even looked at writing a hybrid AdapterFactory class with the capabilities of both Adapter Factories but that was unsuccessful too.
I feel I might be missing something obvious here about the way these are designed. Surely it's possible to get both pieces of functionality working together for my classes? Below is a simple example to demonstrate what I am saying.
public class BaseClass {
private static final RuntimeTypeAdapterFactory<BaseClass> ADAPTER = RuntimeTypeAdapterFactory.of(BaseClass.class);
private static final HashSet<Class<?>> REGISTERED_CLASSES= new HashSet<Class<?>>();
static { GsonUtils.registerType(ADAPTER); }
private synchronized void registerClass() {
if (!REGISTERED_CLASSES.contains(this.getClass())) {
REGISTERED_CLASSES.add(this.getClass());
ADAPTER.registerSubtype(this.getClass());
}
}
public BaseClass() {
registerClass();
}
}
public class DerivedClass extends BaseClass {
public DerivedClass(Integer number) {
super();
this.number = number;
Init();
}
protected Integer number;
protected transient Integer doubled;
protected transient Integer tripled;
protected transient Integer halved;
protected transient Integer squared;
protected transient Integer cubed;
public void Init() {
halved = number / 2;
doubled = number * 2;
tripled = number * 3;
squared = number * number;
cubed = number * number * number;
}
@PostConstruct
private void postConstruct() {
Init();
}
}
public class GsonUtils {
private static final GsonBuilder gsonBuilder = new GsonBuilder().registerTypeAdapterFactory(new PostConstructAdapterFactory());
public static void registerType(RuntimeTypeAdapterFactory<?> adapter) {
gsonBuilder.registerTypeAdapterFactory(adapter);
}
public static Gson getGson() {
return gsonBuilder.create();
}
}
Gson gson = GsonUtils.getGson();
String serialized = gson.toJson(new DerivedClass(6), BaseClass.class);
DerivedClass dc = gson.fromJson(serialized, DerivedClass.class);
Update: Thank you for the answer @michał-ziober. Doing as you said did indeed work. It does answer the question however, it still does not exactly solve my problem. Let me modify the question slightly.
The simplified version of my code was perhaps a little too simple. When I attempt to serialize/deserialize DerivedClass as a property on another class, my original problem is highlighted. As below:
public class WrapperClass {
protected BaseClass dc = new DerivedClass(6);
}
Gson gson = GsonUtils.getGson();
String serialized = gson.toJson(new WrapperClass());
WrapperClass wc = gson.fromJson(serialized, WrapperClass.class);
In this scenario, as long as my DerivedClass doesn't define the PostConstruct method, the serialization/deserialization of DerivedClass works fine. But if it does, the "type" property is not written to file.
Just to reiterate, if I serialize/deserialize DerivedClass directly, everything is fine but if it's inside WrapperClass and I serialize/deserialize WrapperClass AND if I define a PostConstruct method, it does not work.