【问题标题】:Deserializing to a class using non-constructor method使用非构造方法反序列化为类
【发布时间】:2020-01-11 10:25:41
【问题描述】:

我正在尝试反序列化 jackson 序列化的 Google Ads sdk 对象。特别是,我在实例化行为类似于枚举的特定类时遇到了问题,例如:

public class CampaignStatus implements Serializable {
    private String _value_;
    private static HashMap _table_ = new HashMap();
    public static final String _UNKNOWN = "UNKNOWN";
    public static final String _ENABLED = "ENABLED";
    public static final String _PAUSED = "PAUSED";
    public static final String _REMOVED = "REMOVED";
    public static final CampaignStatus UNKNOWN = new CampaignStatus("UNKNOWN");
    public static final CampaignStatus ENABLED = new CampaignStatus("ENABLED");
    public static final CampaignStatus PAUSED = new CampaignStatus("PAUSED");
    public static final CampaignStatus REMOVED = new CampaignStatus("REMOVED");
    private static TypeDesc typeDesc = new TypeDesc(CampaignStatus.class);

    protected CampaignStatus(String value) {
        this._value_ = value;
        _table_.put(this._value_, this);
    }

    public String getValue() {
        return this._value_;
    }

    public static CampaignStatus fromValue(String value) throws IllegalArgumentException {
        CampaignStatus enumeration = (CampaignStatus)_table_.get(value);
        if (enumeration == null) {
            throw new IllegalArgumentException();
        } else {
            return enumeration;
        }
    }

    public static CampaignStatus fromString(String value) throws IllegalArgumentException {
        return fromValue(value);
    }

    public boolean equals(Object obj) {
        return obj == this;
    }

    public int hashCode() {
        return this.toString().hashCode();
    }

    public String toString() {
        return this._value_;
    }

    public Object readResolve() throws ObjectStreamException {
        return fromValue(this._value_);
    }

    public static Serializer getSerializer(String mechType, Class _javaType, QName _xmlType) {
        return new EnumSerializer(_javaType, _xmlType);
    }

    public static Deserializer getDeserializer(String mechType, Class _javaType, QName _xmlType) {
        return new EnumDeserializer(_javaType, _xmlType);
    }

    public static TypeDesc getTypeDesc() {
        return typeDesc;
    }

    static {
        typeDesc.setXmlType(new QName("https://adwords.google.com/api/adwords/cm/v201809", "CampaignStatus"));
    }
}

当一个 Campaign 对象被序列化时(它包含一个上面定义的 CampaignStatus),JSON 看起来像这样:

“状态”:{“值”:“启用”}

在尝试将 JSON 营销活动写入营销活动对象时,反序列化程序会引发不匹配的输入异常。由于对象归 Google 所有,我无法修改现有类或添加注释。我的解决方案需要适用于 250 多个遵循此模式的类,因此单独包装或扩展这些不是可行的解决方案。此外,我将有许多不同的利益相关者序列化这些对象,因此修改它们的序列化方式也不是一个可用的解决方案。

我需要的是某种方式向反序列化器表明,当它遇到这样的情况时,它应该寻找 fromValue 方法并使用它。我可以明确说明使用这种方法需要哪些 json 键/值;我只需要一种比扩展类或添加注释更动态的方式来修改序列化。

【问题讨论】:

  • “由于对象归 Google 所有,我无法修改现有的类或添加注释。” Jackson 支持 mixin annotations,让您可以将注释应用到代码中你控制不了。但我想,既然你要处理这么多类,那与包装或扩展它们一样多,你已经说过你不想这样做。
  • 这绝对有用。如果这不能以通用方式实现,那么使用这些 mixin 注释可能比扩展每个对象更现实。

标签: java json jackson jackson-databind fasterxml


【解决方案1】:

您可以使用@JsonCreator 注释来指示工厂方法 - Jackson 将使用它来执行反序列化。

在你的情况下,它看起来像这样:

    @JsonCreator
    public static CampaignStatus fromValue(@JsonProperty("value") String value) throws IllegalArgumentException {
        CampaignStatus enumeration = (CampaignStatus)_table_.get(value);
        if (enumeration == null) {
            throw new IllegalArgumentException();
        } else {
            return enumeration;
        }
    }

我对您到底想要实现什么感到有些困惑,但您可以随意将任何满足您要求的逻辑放入上述方法中。

【讨论】:

  • 我在研究中看到了这个解决方案,它肯定可以工作,问题是这不可行,因为 1. 我无法修改这些文件,除非我分叉整个 Google Ads 库 2 .我需要为大量的课程这样做。我正在寻找的解决方案是一种反序列化这些而不显式修改/扩展现有类的方法。
【解决方案2】:

所以我没有找到最好的解决方案,但我会分享我能想到的最好的解决方案。我实现了一个扩展 JsonDeserializer 的新通用反序列化器,并在反序列化方法中使用反射来调用 .fromValue 方法。然后我使用反射在目录中搜索所有类,并在每个类中搜索匹配的 .fromValue 方法。每次我成功找到遵循此模式的类时,我都会使用对应类的新通用反序列化器将其注册到映射器。这有点贵,但我只在实例化时注册反序列化器,所以它是一个复杂的没关系。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    • 2015-10-12
    • 2011-07-09
    • 1970-01-01
    相关资源
    最近更新 更多