I have my object implemented the PropertyChangeSupport
, but when I deserialize from a json string, the variable propertyChangeSupport
would be null
, despite I initialize the value myself with a new PropertyChangeSupport(this)
in the default constructor. How can I initialize or deserializing it properly using Gson?
Say I have this object:
public class Blah implements BlahInterface {
private PropertyChangeSupport propertyChangeSupport;
protected int id;
protected BlahType type;
public Blah() {
propertyChangeSupport = new PropertyChangeSupport(this);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public BlahType getType() {
return type;
}
public void setType(BlahType type) {
this.type = type;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.propertyChangeSupport.addPropertyChangeListener(listener);
}
public PropertyChangeListener[] getPropertyChangeListeners() {
return this.propertyChangeSupport.getPropertyChangeListeners();
}
}
I also tried putting the new PropertyChangeSupport(this);
directly at the beginning and is no go either. I kind a want to avoid manually making a function such as initializePropertyChangeSupport()
and then call it manually after deserialization since that's kinda ugly.
What I'm trying to do:
JsonArray ja = json.get("blahs").getAsJsonArray();
ja.forEach(item -> {
Blah blah = BlahInterface.Parse(item.toString());
// But here I can't addPropertyChangeListener because propertyChangeSupport is null
// vvvvvvvvvvvv
blah.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
BlahState state = (BlahState) evt.getNewValue();
Logger.debug("Property had been updated, " + state.toString());
}
});
});
This is my json parsing function:
@SuppressWarnings("unchecked")
public static <T extends Blah> T Parse(String json) {
Gson gson = new Gson();
Blah t = new Blah(gson.fromJson(json, Blah.class));
switch (t.getType()) {
case blahone:
return (T) gson.fromJson(json, BlahOne.class);
default:
return (T) t;
}
};
The solution to this problem is to implements InstanceCreator<T>
in my object. So that when Gson tries to deserialize the object, it would call the createInstance
function which in turns returns a proper object with the PropertyChangeSupport
variable initialized. Example code below:
public class Blah implements InstanceCreator<Blah> {
private final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
...
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
@Override
public Blah createInstance(Type type) {
return new Blah();
}
}
Note: transient keyword is there on the pcs
just so that Gson would skip it during serialize otherwise Gson would throw exception.