How can I model a generic Jackson POJO with a field that is changing the name?

huangapple go评论61阅读模式
英文:

How can I model a generic Jackson POJO with a field that is changing the name?

问题

我与一组API进行交互,它们都返回类似的响应:

{
    "common1": ...,
    "common2": ...,
    "common3": ...,
    "someList": [
        //这里是多态对象
    ]
}

目前,我为每个响应都有一个单独的POJO。但是我希望将其因子化为一个通用对象,因为我总是对这样的对象执行相同的操作,这导致了很多代码重复。

最初,我想创建一个类似的Jackson类:

public class CommonClass<T> {
    @JsonProperty("common1")
    private final CommonType1 common1;
    @JsonProperty("common2")
    private final CommonType2 common2;
    @JsonProperty("common3")
    private final CommonType3 common3;
    @JsonProperty("someList")
    private final List<T> someList;

    //这里放构造函数和getter方法
}

这样会很好运行,但有一个问题:someList的Json名称也会变化。有时它是someListA,有时它是someListB... 基本上它的名称会根据它包含的类型而变化。

这使得按照这种方法(至少我认为是这样)变得不可能,因为我无法动态更改我的POJO中JsonProperty()注解的值。

我知道我可以创建一个基类,然后创建多个该类的扩展,每个扩展都有不同名称的列表,但这不是我的理想解决方案,因为我将无法拥有一个通用的getter方法来处理元素,而无需向我正在处理的POJO的具体类型进行向下转换。

对于这个问题,你有任何想法/建议/方法吗?

英文:

I interact with a set of APIs that all return a similar response:

{
    &quot;common1&quot;: ...,
    &quot;common2&quot;: ...,
    &quot;common3&quot;: ...,
    &quot;someList&quot;: [
        //polymorph objects here
    ]
}

Currently, I have a separate POJO for each of these responses. However I would like to factorize this in a common object since I always perform the same actions with such object and that makes a lot of code duplication.

Initially, I had thought to create a similar Jackson class:

public class CommonClass&lt;T&gt; {
    @JsonProperty(&quot;common1&quot;)
    private final CommonType1 common1;
    @JsonProperty(&quot;common2&quot;)
    private final CommonType2 common2;
    @JsonProperty(&quot;common3&quot;)
    private final CommonType3 common3;
    @JsonProperty(&quot;someList&quot;)
    private final List&lt;T&gt; someList;

    //constructor and getters here
}

This would work fine, except for an issue: the Json name of someList changes as well. Sometimes it's someListA, sometimes it's someListB... basically it changes depending on the type it contains.

That makes it impossible to follow this approach (at least I think) since I can't dynamically change the value of the JsonProperty() annotations in my POJO.

I know that I could create a base class and then multiple extensions of such class, each one with a different list (differently named), but that wouldn't be my ideal solution because I wouldn't be able to have a common getter to process the elements without downcasting to the concrete type of POJO that I'm handling.

Do you have any idea/suggestion/approach for such problem?

答案1

得分: 1

如果名称选项列表不太长,您可以使用JsonAlias

> 注解可用于定义一个或多个属性的替代名称,在反序列化期间作为官方名称的替代名称被接受。在POJO内省期间,别名信息也会被公开,但在序列化期间没有任何效果,始终使用主要名称。

示例:

public class CommonClass<T> {
    @JsonProperty("common1")
    private final CommonType1 common1;
    @JsonProperty("common2")
    private final CommonType2 common2;
    @JsonProperty("common3")
    private final CommonType3 common3;
    @JsonProperty("someList")//official name, used during serialization
    @JsonAlias({"someListA", "someListB"})//aliases used during deserialization, if the official name was not found
    private final List<T> someList;
}
英文:

If the list of options for the name is not too long, you can use JsonAlias.

> Annotation that can be used to define one or more alternative names for a property, accepted during deserialization as alternative to the official name. Alias information is also exposed during POJO introspection, but has no effect during serialization where primary name is always used.

Example:

public class CommonClass&lt;T&gt; {
    @JsonProperty(&quot;common1&quot;)
    private final CommonType1 common1;
    @JsonProperty(&quot;common2&quot;)
    private final CommonType2 common2;
    @JsonProperty(&quot;common3&quot;)
    private final CommonType3 common3;
    @JsonProperty(&quot;someList&quot;)//official name, used during serialization
    @JsonAlias({&quot;someListA&quot;, &quot;someListB&quot;})//aliases used during deserialization, if the official name was not found
    private final List&lt;T&gt; someList;
}

答案2

得分: 0

最简单的方法是将其反序列化为 Map<String, Object>,然后以相同的方式处理映射,只是在检索 someList* 属性时,不是查找特定的键,如 someListASomeListB,而是搜索以 &quot;someList&quot; 前缀开头的键。

英文:

The simplest way is to deserialize it as a Map&lt;String, Object&gt; and than treat your map the same way except when retrieving someList* property instead of looking for a particular key such as someListA or SomeListB just search for the key that starts with &quot;someList&quot; prefix

huangapple
  • 本文由 发表于 2023年3月15日 20:41:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75744857.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定