【问题标题】:Custom de-/serialization of Json involving multiple implementations of some interfaceJson 的自定义反序列化/序列化涉及某些接口的多个实现
【发布时间】:2019-12-30 19:40:37
【问题描述】:

有以下几种:

一个

public interface A {    
}

Aa

class Aa implements A {
    private int aInt;
    private String aString;
    private boolean aBoolean;

    //getters and setters
}

Bb

public class Bb implements A {
    private int bInt;
    private String bString;
    private boolean bBoolean;

    //getters and setters
}

C

public class C implements serializable {
    private int cInt;
    private String cString;
    private boolean cBoolean;
    private List<A> aList;

    //getters and setters
}

如何为 C 类编写自定义的反序列化器和序列化器? C 类的实例包含 Aa 类和 Bb 类对象的列表。

【问题讨论】:

  • Bb implements B?不应该是Bb implements A吗?在您的示例中,所有实现都有不同的属性集。它在您的应用程序中看起来是否相同?你在这个example 这样的基类中有type 属性吗?如果您可以控制序列化,则应该使用它。
  • 是的,它是一个错字,它应该是实现 A.. 更正
  • 其他问题呢?您能否添加额外的 type 字段,该字段将用作给定类型的决定因素?
  • 不,我不能添加额外的类型参数..

标签: java json jackson gson deserialization


【解决方案1】:

对于序列化程序:我看不出有任何理由(除了在我的回答底部看到)为什么您需要任何自定义序列化程序。 Gson 几乎可以流畅地序列化任何内容。

问题与反序列化有关,因为您的List&lt;A&gt; aList - 在序列化为 JSON 对象后 - 在其对象中不包含实现类的信息。恐怕唯一可用的选项是偷看您当前正在序列化的 JSON 对象中的字段(或任何类似的间谍、值)是什么。

例如,您可以使用以下反序列化器:

public class PeekingDeserializer implements JsonDeserializer<A> {

    private final Gson gson = new Gson();

    @Override
    public A deserialize(JsonElement je, Type typeOfT, 
                            JsonDeserializationContext context)
            throws JsonParseException {
        return buildInstance(je);
    }

    private A buildInstance(JsonElement je) {
        Class<? extends A> classA;
        if (null != je.getAsJsonObject().getAsJsonPrimitive("aInt")) {
            classA = Aa.class;
        } else if (null != je.getAsJsonObject().getAsJsonPrimitive("bInt")) {
            classA = Bb.class;
        } else {
            throw new IllegalArgumentException("Could not resolve class");
        }
        return gson.fromJson(je, classA);
    }
}

正如您在上面看到的,实现信任字段aIntbInt 始终存在。我认为它们可以是null,但它们必须存在于 JSON 对象中。主要的是必须有一些东西可以用来识别对象的类型。如果您无法识别类型,如果您无法对反序列化器进行编码,则无法期望 Gson 可以以某种自动魔术方式完成。

我认为Michał Ziober 在他的评论中考虑使用RuntimeTypeAdapterFactory 或在序列化C(或List&lt;A&gt;)时添加类型信息的可能性。对于后者,您可以使用自定义序列化程序 - 使用它将类型信息标记为字段 type - 但如果您的 JSON 来自其他地方并且没有被您序列化,则此选项无济于事。

【讨论】:

  • 我会试试这个!另一方面,如果变量名称在 2 个实现中相同并且都是不同的原语,如 String 和 Integer.. je.getAsJsonObject().getAsJsonPrimitive("aInt").. 在这种情况下会如何变化?
  • 类A;在我的情况下,这一行应该包含未扩展的工具。但是“”给出了编译错误。你有其他选择吗?
  • 忽略以上内容,错误地我包中引用的 A 不是我想要的。它从不同的包中导入。因此问题。
  • @stallion 是的,无论如何你只能在泛型中使用带有通配符的extendssuper。字符串不是原始的,我认为几乎任何 JSON 值都可以实例化为字符串。但是对于数字和其他类型,您可以尝试从 JSON 实例化它捕获异常,然后为具有相同名称的 var 尝试下一个可能的类型(so class)。您还可以比较检查多个字段,它不必只有一个。
猜你喜欢
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
  • 2017-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-14
  • 1970-01-01
相关资源
最近更新 更多