gpt4 book ai didi

java - 使用 Jackson @JsonDeserializer 将一个自定义 Java 字段映射到多个 JSON 字段

转载 作者:行者123 更新时间:2023-12-02 10:02:14 27 4
gpt4 key购买 nike

我有一个使用 Jackson 表示 JSON 的 java 类。除一处异常(exception)外,所有字段都可以完全不使用注释进行翻译。一对一的简单翻译(尽管其中一些是嵌套的 POJO)。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyPojo {
private String someString;
private AnotherPojo someOtherPojo;
//The problem child:
private Object value;
}

字段value这是此规则的一个异常(exception),可以表示匹配 value* 的任何 JSON 字段哪里*是不定长度的通配符。这意味着valueStringvalueReference JSON 中的格式将被分配给该字段,并断言只能存在一个。

{
"someString": "asdasdadasdsa",
"someOtherPojo": {
"someOtherProperty": "whatever"
},
"valueCodeableConcept": {
"text": "text value",
"coding": [
{
"code": "my-code"
}
]
}
}

在顶级类上使用自定义反序列化器,我可以从根节点(以下示例中的 baseNode )中抓取以 value 开头的所有字段。并适当设置值字段。效果很好!然而,这样做时,我现在必须设置此 MyPojo 中的所有其他字段。在我的反序列化器中手动创建类,并且我必须在每个使用类似 value* 的字段的 POJO 上放置此反序列化器的自定义副本。

private Object parseValueX(JsonNode baseNode, DeserializationContext context) throws IOException {
//Find the concrete implementation referred to by the value[x] field
Set<String> concreteNames = new HashSet<>();
baseNode.fieldNames().forEachRemaining(name -> {
if (name.startsWith("value")) {
concreteNames.add(name);
}});

if (concreteNames.isEmpty()) {
return null;
}

if (concreteNames.size() > 1) {
throw JsonMappingException.from(context, "The field value[x] must have no more than one concrete " +
"implementation, ex: valueCode, valueCodeableConcept, valueReference");
}

String concreteName = concreteNames.stream().findFirst().orElseThrow(() -> new RuntimeException(""));
JsonNode jsonSource = baseNode.get(concreteName);

//...deserialize from jsonSource, solved, but not relevant to question...
}

使其适用于任何 value*任何 POJO 上的属性,我尝试将解串器移动到 value POJO 中的属性(而现在它位于顶级资源上)。第一个缺陷是,除非 JSON 属性完全匹配 value,否则解串器甚至不会被调用。 。我实际上需要的是将整个父 JSON 资源传递给特定于字段的反序列化器,以便我可以找到匹配的字段并分配它 - 或者 - 我需要能够将反序列化器放在 MyPojo 上。 分配一个字段 value并允许自动反序列化来处理其他问题。我该怎么做?

<小时/>

对于那些对我的动机感到好奇的人,我正在实现 HL7 FHIR 规范,该规范指定了名为 value[x] 的通用属性(这里是一个示例: https://www.hl7.org/fhir/extensibility.html#Extension ),其中 [x] 成为资源的类型。

最佳答案

我认为最适合您的问题是 @JsonAnySetter 。此方法注释告诉 Jackson 将未知属性路由到它。 arg(在您的情况下)是一个包含未知属性的 json 树的 Map。如果我正确理解你的代码,value属性的名称包含目标Pojo的类名。因此,一旦有了类名,您就可以告诉 Jackson 如何将映射“反序列化”为目标类的实例。

这是一个基于问题代码的示例

public class MyPojo {
public String someString; // made properties into public for this example...
public AnotherPojo someOtherPojo;
public Object value;

@JsonAnySetter
public void setValue(String name, Object value) {
System.out.println(name + " " + value.getClass());
System.out.println(value);

// basic validation
if (name.startsWith("value") && value instanceof Map) {
String className = "com.company." + name.substring("value".length());
System.out.println(name + " " + value.getClass() + " " + className);
System.out.println(value);
try {
// nice of Jackson to be able to deserialize Map into Pojo :)
ObjectMapper mapper = new ObjectMapper();
this.value = mapper.convertValue(value, Class.forName(className));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(this.value + " " + this.value.getClass());
}

}
}

public class AnotherPojo {
public String someOtherProperty;
}

public class CodeableConcept {
public String text;
public Code[] coding;
}

public class Code {
public String code;
}

关于java - 使用 Jackson @JsonDeserializer 将一个自定义 Java 字段映射到多个 JSON 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55543190/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com