GSON:在两个类中引用了相同的对象,解码后重复了实例

我正在使用GSON进行持久化并将数据恢复到我的应用程序中。问题在于,在某些情况下,我有两个不同对象中引用的对象,我的意思是,引用了相同的实例。因此,多条路径可以导致同一个对象。

当持久保存我模型的已解码GSON字符串时,如果在两个地方存在相同对象的两个引用,则显然可以持久保存它们,但是当再次打开应用程序并加载数据并解码GSON字符串时,两个将创建同一对象的不同实例,而不是同一实例。在第一个实例中进行更改不会在第二个实例中反映出来,因为在解码json之后是不同的对象。

这是问题的痕迹:

具有模型,人员和车辆:

public class Model{
    Car car;
    Person person;
}

public class Person{
    Car car;
}

我将汽车的相同实例设置为模型和人员:

Car car = new Car();
model.setCar(car);
person.setCar(car);

汽车在汽车和人中是相同的实例,现在我用GSON编码并保留数据:

Gson gson = new Gson();
String json = gson.toJson(model);

然后我关闭应用程序并重新打开应用程序,然后解码json字符串以恢复模型:

Gson gson = new Gson();
gson.fromJson(json,Model.class);

现在,我有两个不同的Car实例,一个是内部人员,另一个是内部Model,它们不是同一实例,但必须是同一实例!如果我修改Model的汽车,那么人的汽车没有被修改,那是一个错误。

如何解决这个问题?

yj9981n 回答:GSON:在两个类中引用了相同的对象,解码后重复了实例

getUserInfo默认不提供任何缓存实例并检查实例是否已被看到的方法。为此,我们需要实现自定义Gson。另外,我们需要假设com.google.gson.TypeAdapterFactory类(如果需要,还可以使用Car类)正确实现了Personpublic boolean equals(Object o),因此我们可以使用public int hashCode()来缓存所有实例

让我们假设您的模型如下所示:

Map

class Model { private Car car; private Person person; // getters,setters,toString } class Person { private int id; private String name; private Car car; // getters,toString @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return id == person.id; } @Override public int hashCode() { return Objects.hash(id); } } class Car { private int id; private String name; // getters,toString @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Car car = (Car) o; return id == car.id; } @Override public int hashCode() { return Objects.hash(id); } } Car类具有Person字段,我们使用它们来区分实例。您可以在实现中使用所需的任何属性。

使用id缓存实例的自定义适配器实现:

Map

然后在下面找到如何使用它的示例:

class CachedInstancesTypeAdapterFactory implements TypeAdapterFactory {

    private final Map<Class,Map> cachedMaps = new HashMap<>();

    public CachedInstancesTypeAdapterFactory(Set<Class> customizedClasses) {
        Objects.requireNonNull(customizedClasses);
        customizedClasses.forEach(clazz -> cachedMaps.compute(clazz,(c,m) -> new HashMap<>()));
    }

    public final <T> TypeAdapter<T> create(Gson gson,TypeToken<T> type) {
        if (cachedMaps.containsKey(type.getRawType())) {
            final TypeAdapter<T> delegate = gson.getDelegateAdapter(this,type);
            return createCustomTypeAdapter(delegate);
        }

        return null;
    }

    @SuppressWarnings("unchecked")
    private <T> TypeAdapter<T> createCustomTypeAdapter(TypeAdapter<T> delegate) {
        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out,T value) throws IOException {
                delegate.write(out,value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                Object deserialized = delegate.read(in);

                Map tInstances = Objects.requireNonNull(cachedMaps.get(deserialized.getClass()));
                return (T) tInstances.computeIfAbsent(deserialized,k -> deserialized);
            }
        };
    }
}

上面的代码打印出来,首先是import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; public class GsonApp { public static void main(String[] args) { Gson gson = createGson(); String json = gson.toJson(createModel()); System.out.println(json); Model result = gson.fromJson(json,Model.class); System.out.println(result); System.out.println("Two car instances are the same: " + (result.getCar() == result.getPerson().getCar())); } private static Model createModel() { Car car = new Car(); car.setId(9943); car.setName("Honda"); Person person = new Person(); person.setId(123); person.setName("Jon"); person.setCar(car); Model model = new Model(); model.setCar(car); model.setPerson(person); return model; } private static Gson createGson() { Set<Class> classes = new HashSet<>(); classes.add(Car.class); classes.add(Person.class); return new GsonBuilder() .setPrettyPrinting() .registerTypeAdapterFactory(new CachedInstancesTypeAdapterFactory(classes)) .create(); } }

JSON

然后:

{
  "car": {
    "id": 9943,"name": "Honda"
  },"person": {
    "id": 123,"name": "Jon","car": {
      "id": 9943,"name": "Honda"
    }
  }
}

注意

Model{car=Car{id=9943,name='Honda'},person=Person{id=123,name='Jon',car=Car{id=9943,name='Honda'}}} Two car instances are the same: true 之上的实现不是线程安全的。此外,当您想使用CachedInstancesTypeAdapterFactoryGson实例反序列化JSON有效负载时,必须为每个线程和每次尝试创建一个总是新的Car对象。原因是Person对象只能使用一次。

另请参阅:

本文链接:https://www.f2er.com/3108569.html

大家都在问