【问题标题】:Json schema with anyOf fields to POJO带有任何字段到 POJO 的 Json 模式
【发布时间】:2020-11-28 20:28:21
【问题描述】:

我想知道为带有“anyOf”字段的 Json 模式生成 POJO 的推荐方法是什么?

例如,给定以下 json 架构:

爱好.json
{
    "anyOf": [
        { "type": {"$ref": "./exercise.json" } },
        { "type": {"$ref": "./music.json" } }
    ]    
}
练习.json
{
    "type": "object"
    "properties" {
        "hobbyType": {"type": "string"}
        "exerciseName": { "type": "string" },
        "timeSpent": { "type": "number" },
        "place": { "type": "string" }
    }
}
音乐.json
{
    "type": "object"
    "properties" {
        "hobbyType": {"type": "string"}
        "instrument": { "type": "string" },
        "timeSpent": { "type": "number" }
    }
}

如何使用 Jackson 为 Hobby.java 生成 POJO?

【问题讨论】:

  • 在地图内使用地图,这可能会有所帮助
  • 在 anyOf 的情况下不应该也有一个鉴别器吗?
  • @SvenDöring Json Schema 是否支持鉴别器?我认为这是一个 openApi 规范。你能分享一个关于这个的文档吗?我可以知道哪个版本的 Json Schema 支持这个吗?

标签: java jackson jsonschema pojo jsonschema2pojo


【解决方案1】:

我认为有两种方法看起来很自然:

一种方法是生成一个类层次结构 Hobby,其公共字段 timeSpent 和 Music/Exercise 是具有其特定字段的子类。

另一种方法是将字段“联合”成一个 Hobby 类。

两者在语义上都是不正确的,这意味着您可以提出 JSON 架构正确验证但 Jackson 抛出错误或 POJO 中由于省略字段而缺少信息的情况。

所以我认为这里最好的方法是使用 Map 而不是 pojos。

例如,如果一个人有一个爱好,那么这个人 POJO 可能是:

class Person {
  String name;
  ...
  Map<String, Object> hobby;

或 List hobbies> 如果一个人可以有多个爱好。

【讨论】:

    【解决方案2】:

    我最终采用的方法是使用 Jackson 提供的多态编组/解组功能。

    具体来说-

    1. 使hobby成为一个接口并用@JsonTypeInfo@JsonSubTypes注释它
    @JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        property = "hobbyType",
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        visible = true
    )
    @JsonSubTypes({
            @Type(value = Exercise.class, name = "exercise"),
            @Type(value = Music.class, name = "music")
    })
    public interface Hobby {
    }
    
    1. 创建实现此接口的Exercise.javaMusic.java
    @Builder
    @Data
    @AllArgsConstructor
    public class Exercise implements Hobby {
        @JsonProperty("hobbyType")
        @Builder.Default
        @NonNull
        private final String hobbyType = "exercise";    
    
        @JsonProperty("exerciseName")
        private String exerciseName;
    
        @JsonProperty("place")
        private String place;
        //... (other fields)
    }
    
    1. 使用Hobby 进行序列化和反序列化。
    // create a Hobby object
    Hobby exercise = Exercise.builder().exerciseName("swimming").place("swimmingPool").build();
    
    // serialization
    String serializedHobby = new ObjectMapper.writeValueAsString(exercise)
    /**
    serializedHobby looks like this ->
    {
        "hobbyType": "exercise",
        "exerciseName": "swimming",
        "place": "swimmingPool"
    }
    */
    
    // deserialization
    Hobby deserializedObject = new ObjectMapper.readValue(jsonString, Hobby.class)
    // deserializedObject.getClass() would return Exercise.java or Music.java based on the hobbyType
    
    

    参考:https://www.baeldung.com/jackson-inheritance

    【讨论】:

    • 如果您的课程是“oneOf”或“allOf”而不是“anyOf”,您的课程会是什么样子?
    • @aeberhart 我认为这取决于模式的结构。如果它需要以多态方式反序列化/序列化,你或许可以尝试这种方法。
    • 好吧有道理。所以我猜你的问题更多的是关于多态性,而不是 allOf、anyOf、oneOf 之间的差异,对吗?
    • 我猜你可以这么说。在我的情况下使用anyOf 的方式最好通过多态编组/解组来解决
    猜你喜欢
    • 2021-08-22
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 2021-01-24
    • 2019-06-23
    相关资源
    最近更新 更多