使用 Gson-extras 使用瞬态变量反序列化多态 JSON



我有一些多态Java类,我正在序列化/反序列化。 我正在使用Gson-extras的RuntimeTypeAdapterFactory来确保类正确序列化和反序列化,并将"type"字段设置为派生类的名称。 它工作正常。

我还有其他一些正在序列化/反序列化的类,这些类有一些应用了瞬态修饰符的变量。 我正在使用同样来自 Gson-extras 的 PostConstructAdapterFactory 将 PostConstruct 方法添加到我的类中,以便在反序列化完成后和调用类中的任何函数之前重新分配瞬态变量的值。 这也工作正常。

我面临的挑战是我有另一组多态的类,并且还具有瞬态变量,我希望在反序列化后执行PostConstruct方法。 我同时使用 RuntimeTypeAdapterFactory 和 PostConstructAdapterFactory 的所有尝试都失败了。 我可以同时注册两者,但是当我执行PostConstructAdapterFactory行为时,似乎覆盖了RuntimeTypeAdapterFactory行为,导致我的类不再存储多态类所需的"类型"字段。

似乎我可以有一个或另一个,但不能同时拥有两者。 我甚至考虑编写一个具有两个适配器工厂功能的混合适配器工厂类,但这也没有成功。

我觉得我可能在这里错过了一些关于这些设计方式的明显内容。 当然,有可能让我的课程同时使用这两个功能吗? 下面是一个简单的例子来演示我所说的。

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);

更新:感谢您的回答@micha ł-ziober。 按照你说的做确实有效。 它确实回答了这个问题,但是,它仍然不能完全解决我的问题。 让我稍微修改一下这个问题。

我的代码的简化版本可能有点太简单了。 当我尝试将 DerivedClass 序列化/反序列化为另一个类上的属性时,我的原始问题突出显示。 如下:

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);

在这种情况下,只要我的衍生类没有定义 PostConstruct 方法,派生类的序列化/反序列化就可以正常工作。 但如果是这样,则"type"属性不会写入文件。

重申一下,如果我直接序列化/反序列化衍生类,一切都很好,但如果它在 WrapperClass 中并且我序列化/反序列化 WrapperClass 并且如果我定义一个 PostConstruct,它不起作用。

类型适配器一切都

很好,您可以同时使用它们。在您的情况下,问题在于执行代码的顺序。
  1. GsonUtils.getGson()- 使用适配器创建Gson对象。
  2. gson.toJson(new DerivedClass(6), BaseClass.class)- 您创建DerivedClass实例,该实例从适配器中注册给定类的BaseClass执行超级构造函数(原文如此!

试试这个代码:

DerivedClass src = new DerivedClass(6);
Gson gson1 = GsonUtils.getGson();
String serialized = gson1.toJson(src, BaseClass.class);
System.out.println(serialized);
DerivedClass dc = gson1.fromJson(serialized, DerivedClass.class);

它将按预期工作。创建DerivedClass有一个副作用 - 这是为什么类应该彼此分离的一个非常好的例子。BaseClass中不应有任何Gson特定的类。

在最好的世界中,BaseClass应该只包含公共属性和一些基本逻辑:

class BaseClass {
// getters, setters, business logic.
}

所有Gson配置都应放在GsonUtils类中:

class GsonUtils {
public static Gson getGson() {
return new GsonBuilder()
.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(BaseClass.class)
.registerSubtype(DerivedClass.class))
.registerTypeAdapterFactory(new PostConstructAdapterFactory())
.create();
}
}

如果不想手动指定所有类,则需要在运行时扫描环境。看一下:在运行时,查找 Java 应用程序中扩展基类的所有类。

问题更新后编辑

看起来TypeAdapterFactory链接并不像我想象的那么简单。这取决于给定的TypeAdapterFactory实现是返回null还是返回新对象,并将一些委托给其他工厂。

我找到了一个解决方法,但在实际项目中可能不容易使用:

  1. 我创建了两个Gson对象:一个用于序列化,一个用于反序列化。仅对于反序列化过程,我们注册PostConstructAdapterFactory
  2. 我们将一个带有@PostConstruct注释的方法添加到BaseClass.

例:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.typeadapters.PostConstructAdapterFactory;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
import javax.annotation.PostConstruct;
public class GsonApp {
public static void main(String[] args) {
RuntimeTypeAdapterFactory<BaseClass> typeFactory = RuntimeTypeAdapterFactory.of(BaseClass.class)
.registerSubtype(DerivedClass.class);
Gson serializer = new GsonBuilder()
.registerTypeAdapterFactory(typeFactory)
.create();
Gson deserializer = new GsonBuilder()
.registerTypeAdapterFactory(typeFactory)
.registerTypeAdapterFactory(new PostConstructAdapterFactory())
.create();
WrapperClass wrapper = new WrapperClass();
wrapper.setDc(new DerivedClass(8));
String json = serializer.toJson(wrapper);
System.out.println(json);
System.out.println(deserializer.fromJson(json, WrapperClass.class));
}
}
class WrapperClass {
protected BaseClass dc;
public BaseClass getDc() {
return dc;
}
public void setDc(BaseClass dc) {
this.dc = dc;
}
@Override
public String toString() {
return "WrapperClass{" +
"dc=" + dc +
'}';
}
}
class BaseClass {
@PostConstruct
protected void postConstruct() {
}
}
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
protected void postConstruct() {
Init();
}
@Override
public String toString() {
return "DerivedClass{" +
"number=" + number +
", doubled=" + doubled +
", tripled=" + tripled +
", halved=" + halved +
", squared=" + squared +
", cubed=" + cubed +
"} ";
}
}

上面的代码打印:

{"dc":{"type":"DerivedClass","number":8}}
WrapperClass{dc=DerivedClass{number=8, doubled=16, tripled=24, halved=4, squared=64, cubed=512} }

最新更新