You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JaVers能否追踪含Observable Properties的JavaFX模型类变更?

解决JaVers与JavaFX ObjectProperty的序列化/反序列化冲突问题

我之前也碰到过一模一样的问题,核心原因就是JaVers依赖的GSON在反序列化时,会尝试用无参构造实例化你的ObjectProperty字段,但JavaFX的SimpleObjectProperty并没有公开的无参构造函数,所以才抛出了你看到的那个RuntimeException。下面给你两个可行的解决方案,优先推荐第二个,实现起来更简单:

方案一:给GSON添加自定义TypeAdapter处理ObjectProperty

你可以写一个GSON的类型适配器,专门处理JavaFX的ObjectProperty类型,序列化时取它的实际值,反序列化时创建带值的SimpleObjectProperty实例。

首先写一个通用的TypeAdapterFactory:

public class ObjectPropertyTypeAdapterFactory implements TypeAdapterFactory {
    @SuppressWarnings("unchecked")
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        // 只处理ObjectProperty类型
        if (!ObjectProperty.class.isAssignableFrom(typeToken.getRawType())) {
            return null;
        }
        // 获取泛型参数类型(比如ObjectProperty<String>里的String)
        Type genericType = ((ParameterizedType) typeToken.getType()).getActualTypeArguments()[0];
        TypeAdapter<?> delegate = gson.getAdapter(TypeToken.get(genericType));
        
        return (TypeAdapter<T>) new TypeAdapter<ObjectProperty<?>>() {
            @Override
            public void write(JsonWriter out, ObjectProperty<?> value) throws IOException {
                if (value == null) {
                    out.nullValue();
                    return;
                }
                // 序列化时输出实际值
                delegate.write(out, value.getValue());
            }

            @Override
            public ObjectProperty<?> read(JsonReader in) throws IOException {
                // 反序列化时读取值并创建SimpleObjectProperty
                Object value = delegate.read(in);
                // 注意:如果需要绑定到Demo实例,这里没法自动获取,若不需要绑定功能,用这个构造就行
                return new SimpleObjectProperty<>(value);
            }
        };
    }
}

然后在创建Javers实例时,把这个工厂注册到GSON中:

Gson customGson = new GsonBuilder()
        .registerTypeAdapterFactory(new ObjectPropertyTypeAdapterFactory())
        .create();

Javers javers = JaversBuilder.javers()
        .withMappingStyle(MappingStyle.BEAN)
        .withGson(customGson)
        .build();

这个方案的缺点是:如果你的ObjectProperty需要绑定到Demo实例(比如支持JavaFX的属性变更监听),通用适配器没法自动传入Demo实例,需要额外处理。

方案二:用@JsonIgnore忽略ObjectProperty字段(推荐)

这个方案更简单,只需要在你的ObjectProperty字段上添加GSON的@JsonIgnore注解,让GSON跳过这个字段,转而通过你的getter/setter来处理实际的String值:

import com.google.gson.annotations.JsonIgnore;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import org.javers.core.metamodel.annotation.Id;

class Demo { 
    @JsonIgnore // 让GSON忽略这个字段
    private ObjectProperty<String> someProp = new SimpleObjectProperty<>(this, "someProp"); 

    public Demo(String someProp) { 
        this.someProp.setValue(someProp); 
    } 

    public ObjectProperty<String> somePropProperty() { 
        return someProp; 
    } 

    @Id 
    public String getSomeProp() { 
        return someProp.getValue(); 
    } 

    public void setSomeProp(String someProp) { 
        this.someProp.setValue(someProp); 
    } 
}

这样GSON在序列化/反序列化Demo对象时,只会处理getSomeProp()和setSomeProp()对应的String属性,完全不会碰ObjectProperty字段,自然就不会触发无参构造的异常了。而且这个方案完全不影响JavaFX的绑定功能,somePropProperty()依然能正常返回属性供UI绑定使用。

之后你再运行原来的Javers代码,应该就能正常查询到变更记录了。

内容的提问来源于stack exchange,提问作者Joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:16:39