- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一些正在序列化/反序列化的多态java类。我使用 Gson-extras 中的 RuntimeTypeAdapterFactory 来确保类正确序列化和反序列化,并将“type”字段设置为派生类的名称。运行良好。
我还有一些正在序列化/反序列化的其他类,其中有一些应用了 transient 修饰符的变量。我正在使用 PostConstructAdapterFactory(也来自 Gson-extras)向我的类添加 PostConstruct 方法,以便可以在反序列化完成后和调用类中的任何函数之前重新分配 transient 变量的值。这也运行良好。
我面临的挑战是,我有另一组多态类,并且也有 transient 变量,我希望在反序列化后执行 PostConstruct 方法。我所有同时使用 RuntimeTypeAdapterFactory 和 PostConstructAdapterFactory 的尝试都失败了。我可以注册两者,但是当我执行 PostConstructAdapterFactory 行为时似乎会覆盖 RuntimeTypeAdapterFactory 行为,导致我的类不再存储多态类所需的“类型”字段。
看来我可以选择其中之一,但不能同时拥有两者。我什至考虑编写一个具有两个适配器工厂功能的混合 AdapterFactory 类,但这也没成功。
我觉得我可能遗漏了一些关于这些设计方式的明显内容。当然可以让这两个功能在我的类中协同工作吗?下面是一个简单的例子来演示我所说的。
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);
在这种情况下,只要我的 DerivedClass 没有定义 PostConstruct 方法,DerivedClass 的序列化/反序列化就可以正常工作。但如果是这样,“type”属性不会写入文件。
重申一下,如果我直接序列化/反序列化 DerivedClass,一切都很好,但如果它在 WrapperClass 内部并且我序列化/反序列化 WrapperClass 并且如果我定义 PostConstruct 方法,则它不起作用。
最佳答案
一切都很好类型适配器,你可以同时使用它们。在您的情况下,问题在于代码的执行顺序。
GsonUtils.getGson()
- 使用适配器创建 Gson
对象。gson.toJson(new DerivedClass(6), BaseClass.class)
- 您创建 DerivedClass
实例,该实例从 BaseClass
执行 super 构造函数,其中在适配器中注册给定的类(原文如此!)。试试这个代码:
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
应仅包含公共(public)属性和一些基本逻辑:
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();
}
}
如果您不想手动指定所有类,则需要在运行时扫描环境。看看:At runtime, find all classes in a Java application that extend a base class .
看起来TypeAdapterFactory
链接并不像我想象的那么简单。它取决于给定的 TypeAdapterFactory
实现,它是返回 null
还是返回带有某些委托(delegate)给其他工厂的新对象。
我找到了一种解决方法,但在实际项目中可能不太容易使用:
Gson
对象:一个用于序列化,一个用于反序列化。仅针对反序列化过程,我们注册 PostConstructAdapterFactory
。BaseClass
添加一个带有 @PostConstruct
注解的方法。示例:
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} }
关于java - 使用 Gson-extras 反序列化带有 transient 变量的多态 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59810141/
我正在将 ansible 合并到我们的内部 RHN 卫星中。我有来自 Red Hat 的完全更新的 RHEL 7 基础 repo 、附加、补充、可选和 RHN 工具。当我们需要它们时,我还会将选定的包
我尝试将一些值发送到另一个 Activity 。 recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicatio
我有这个代码: Intent intent = new Intent(); intent.setAction(Intent.ACTION_PICK); intent.s
几天前,我一直在努力寻找一种方法来为我的闹钟使用自定义 Intent 。虽然我得到了明确的答案,但我必须根据一些唯一的 ID 来定制 Intent,例如。 setAction()还是有一些问题。 我这
通知正在提供旧值。我阅读了 stackoverflow 链接,但仍然不适合我: Notification passes old Intent Extras 我有一个 Activity A。当我在 Ac
我想写以下内容: result = [] for x in list(range(10)): if x%2 != 0: for a in [1,2]:
我在使用 mysql 5.5.12 时遇到了 Amazon RDS 的 IO 性能问题。有 2 种实例类型相似且价格接近: 超大数据库实例:15 GB 内存、8 个 ECU(4 个虚拟核心,每个 2
这里是 Android 的新手,我正在与一位资深人士就 bundle 和 Intent 进行辩论。这就是我一直在做的...... Intent intent = new Intent(this, Ta
我使用的是MinGW+MSYS, 我添加了 extra-include-dirs、extra-lib-dirs,但似乎没有任何东西可以帮助 cabal 找到 PCRE 库。以下是我尝试过的一些命令行,
我已将 CVS 中的一个模块 check out 到新安装的 Windows 7 计算机上。病毒扫描程序尚未安装。 后来,当我尝试进行更新时,收到以下错误消息: 无法将文件 CVS/Entries.E
Alpine镜像中的telnet在3.7版本后被转移至busybox-extras包中,需要使用apk单独安装。 现象 Alpine版本为3.8, 不再有指向busybox的telent
对lazy="extra"究竟能做什么,有没有很好的解释? 我看过的所有帖子都只是重复了一个事实,即它会引用 MyObject.ItsCollection.Count进入 select count(*
这个问题已经有答案了: Two semicolons inside a for-loop parentheses (4 个回答) Endless loop in C/C++ [closed] (12
我的包为包含的额外内容返回空字符串。不是 NPE,是实际的“空”值。关于为什么会发生这种情况的任何想法? 新 bundle String u = nul
在 es6 中,以下似乎是有效代码: function test(a1,{a=1,b=2} = {},) {} 注意函数参数中额外的,。我不确定这是否是一个错误,因为这个额外的 , 仅适用于解构分配。
我正在查看一个包含 .myClass a.extra{...} 和 .myClass a.extra:hover{...} 的 css 模板“额外”是什么意思? 最佳答案 extra 是类名。 因为你
我来自 Web 开发的前端世界,我们非常努力地尝试限制发出的 HTTP 请求的数量(通过合并 css、js 文件、图像等)。 对于数据库连接 (MySQL),显然您不希望有不必要的连接,但作为一般规则
问题是关于包含不必要的 header 以避免在子文件中多次调用它。这是场景,我有几个文件: srlogger.h srinterface.h srinterface.cc #include #inc
我有一个程序表现出奇怪的行为 #include #include using namespace std; class man{ int i ; public:
本文整理了Java中org.threeten.extra.YearQuarter类的一些代码示例,展示了YearQuarter类的具体用法。这些代码示例主要来源于Github/Stackoverflo
我是一名优秀的程序员,十分优秀!