I have ObservableField<O, V>
class, of which instances are held by custom entity classes to keep track of data changes.
However, I couldn't find a way to write a custom TypeAdapterFactory
implementation for this ObservableField class, because I don't know how to get the field owner in an uninitialized state.
The actual ObservableField<O, V> looks like this.
public class ObservableField<O, V> {
private final O owner;
private V value;
private final List<ObservableFieldHandler<O, V>> handlers = new ArrayList<>();
public ObservableField(O owner, V value) {
this.owner = owner;
this.value = value;
}
public O getOwner() {
return owner;
}
public V get() {
return value;
}
public void set(V value) {
V old = this.value;
this.value = value;
this.handlers.forEach(it -> it.accept(this, old, value));
}
public void subscribe(ObservableFieldHandler<O, V> handler) {
handlers.add(handler);
}
public boolean unsubscribe(ObservableFieldHandler<O, V> handler) {
return handlers.remove(handler);
}
}
This is an example of entity class that uses ObservableField
@Getter
@Setter
public class Member {
private final UUID id;
private final ObservableField<Member, Integer> balance;
public Member(UUID id) {
this.id = id;
this.balance = new ObservableField(this, 0);
}
}
This is my ObservableFieldTypeAdapterFactory I wrote but did not work.
public class ObservableFieldTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType() != ObservableField.class) return null;
Type param = ((ParameterizedType) type.getType()).getActualTypeArguments()[0];
return (TypeAdapter<T>) new TypeAdapter<ObservableField<?, ?>>() {
@Override
public void write(JsonWriter out, ObservableField<?, ?> value) throws IOException {
gson.toJson(value.get(), param, out);
}
@Override
public ObservableField<?, ?> read(JsonReader in) throws IOException {
return new ObservableField<>(/* FIXME: get field owner!*/, gson.fromJson(in, param));
}
};
}
}
Is there any way to get the field owner in an uninitialized state? (If I remember correctly, GSON uses the Unsafe class to create an instance of the uninitialized object, then fills fields later.)
I could not find a solution, so I added ObservableField#initialize method to lazily initialize the owner to resolve this issue.
public class ObservableField<O, V> {
private O owner;
private V value;
private final List<ObservableFieldHandler<O, V>> handlers = new ArrayList<>();
public ObservableField(V value) {
this.value = value;
}
public O getOwner() {
if (owner == null) {
throw new IllegalStateException("Not initialized");
}
return owner;
}
public void initialize(O owner) {
if (this.owner != null) {
if (this.owner.equals(owner)) return;
throw new IllegalStateException("Already initialized");
}
this.owner = owner;
}
public V get() {
return value;
}
public void set(V value) {
V old = this.value;
this.value = value;
this.handlers.forEach(it -> it.accept(this, old, value));
}
public void subscribe(ObservableFieldHandler<O, V> handler) {
handlers.add(handler);
}
public boolean unsubscribe(ObservableFieldHandler<O, V> handler) {
return handlers.remove(handler);
}
}