У меня есть класс Java, представляющий JSON с использованием Джексона. Все поля, за одним исключением, могут быть переведены без каких-либо аннотаций. 1-к-1, простые переводы (хотя некоторые из них являются вложенными POJO).
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyPojo {
private String someString;
private AnotherPojo someOtherPojo;
//The problem child:
private Object value;
}
Поле value
, которое является исключением из этого правила, может представлять любое поле JSON, соответствующее value*
, где *
- это подстановочный знак неопределенной длины. Это означает, что valueString
или valueReference
в JSON будут присвоены этому полю с утверждением, что может присутствовать только один.
{
"someString": "asdasdadasdsa",
"someOtherPojo": {
"someOtherProperty": "whatever"
},
"valueCodeableConcept": {
"text": "text value",
"coding": [
{
"code": "my-code"
}
]
}
}
Используя пользовательский десериализатор в классе верхнего уровня, я могу очистить все поля корневого узла (baseNode
в следующем примере), которые начинаются с value
, и соответствующим образом установить поле значения. Это прекрасно работает! Однако при этом мне теперь нужно вручную установить все остальные поля в этом классе MyPojo
в моем десериализаторе, и я должен поместить пользовательскую копию этого десериализатора в каждый POJO, который использует поле типа value*
.
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] становится типом ресурса.