如何为含anyOf字段的JSON Schema生成Java Record对象?
用Java Record结合Jackson实现JSON Schema的anyOf混合类型
核心思路
因为你的数组元素同时支持Mammal对象和纯字符串(Bird),直接用单一类型无法满足,我们可以通过「接口统一类型 + 自定义序列化/反序列化器」的方式,用Java Record实现需求:
- 定义统一的
AnimalItem接口作为数组元素的类型 - 用Record实现Mammal对象和字符串的包装类
- 自定义序列化/反序列化器,让字符串包装类在JSON中呈现为纯字符串,而非对象结构
步骤1:定义基础类型
首先创建Mammal Record,对应你的mammal.json结构:
public record Mammal(String species, int averageLifespan) implements AnimalItem {}
然后创建字符串包装的Record,实现统一接口:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; // 指定序列化器,让这个Record序列化为纯字符串 @JsonSerialize(using = StringAnimalSerializer.class) public record StringAnimal(String value) implements AnimalItem {}
再定义统一的密封接口(限制实现类范围,避免无关类型混入):
public sealed interface AnimalItem permits Mammal, StringAnimal {}
步骤2:自定义序列化/反序列化器
字符串序列化器(让StringAnimal输出为纯字符串)
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; public class StringAnimalSerializer extends JsonSerializer<StringAnimal> { @Override public void serialize(StringAnimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException { // 直接写入字符串值,而非对象结构 gen.writeString(value.value()); } }
混合类型反序列化器(自动识别对象/字符串)
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; public class AnimalItemDeserializer extends JsonDeserializer<AnimalItem> { @Override public AnimalItem deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); if (node.isObject()) { // 遇到对象时反序列化为Mammal return p.getCodec().treeToValue(node, Mammal.class); } else if (node.isTextual()) { // 遇到字符串时包装为StringAnimal return new StringAnimal(node.asText()); } throw new IOException("不支持的AnimalItem类型"); } }
步骤3:定义包含数组的顶层Record
在你的animals.json对应的Record中,指定数组元素的反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.util.List; public record Animals(@JsonDeserialize(contentUsing = AnimalItemDeserializer.class) List<AnimalItem> animals) {}
效果验证
示例JSON输入
{ "animals": [ {"species": "Tiger", "averageLifespan": 20}, "Bald Eagle", {"species": "Elephant", "averageLifespan": 60}, "Penguin" ] }
反序列化后,animals列表中会包含Mammal和StringAnimal实例;序列化时,StringAnimal会输出为纯字符串,完全符合你的JSON Schema要求。
内容的提问来源于stack exchange,提问作者Djoust
相关产品推荐
相关产品推荐

