java - una - Requisito de campo condicional basado en otro valor de campo en Jackson?
formulas condicionales en excel=si y (2)
Considere una representación JSON con una cadena y dos matrices. Por ejemplo,
{
"type" : "A",
"ListA" : []
"ListB" : [3, 4, 5]
}
En el caso anterior, type
es un campo obligatorio, pero ListA
y ListB
se requieren condicionalmente para la deserialización en función del valor del type
. En otras palabras, ListA
solo es obligatorio si el type
tiene el valor A
y el ListB
solo es obligatorio si el type
tiene un valor B
Actualmente, estoy trabajando en Jackson y en Java, y he podido implementar la obligatoriedad de hacer que el type
campo sea obligatorio creando POJO
siguiente manera:
public class Example {
@JsonProperty(required = true)
String type;
// getter and setter auto-generated
Pero no puedo adjuntar otra @JsonProperty(required = true)
a ListA
o ListB
ya que depende del valor de type
.
¿Cómo puedo exigir condicionalmente ListA
y ListB
para la deserialización basada en el valor del type
?
Además, realizaré comprobaciones adicionales, como si ListA
o ListB
es una matriz vacía ( size == 0
) o no.
Con Jackson puede crear su propio deserializador personalizado para su POJO de ejemplo, extender la clase StdDeserializer y anular el método deserialize () con su lógica. Aquí puede verificar el tipo y el tamaño de la lista.
Luego, para usar su deserializador personalizado, debe agregarlo a un SimpleModule y registrar este último con su Jackson ObjectMapper.
Hace un par de artículos escribí sobre este tema, donde puedes encontrar un ejemplo concreto sobre Serialización / Deserialización personalizada con Jackson:
Jackson: crea un deserializador JSON personalizado con las clases StdDeserializer y JsonToken
Puede usar un deserializador personalizado para lograrlo.
Definiendo tu modelo
Tu clase de Example
sería como:
public class Example {
private String type;
private List<Integer> listA;
private List<Integer> listB;
// Getters and setters omitted
}
Creando un deserializador personalizado
Su deserializador personalizado podría ser lo siguiente:
public class ExampleDeserializer extends StdDeserializer<Example> {
private static final String TYPE_A = "A";
private static final String TYPE_B = "B";
public ExampleDeserializer() {
super(Example.class);
}
@Override
public Example deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) p.getCodec();
JsonNode tree = mapper.readTree(p);
Example example = new Example();
JsonNode typeNode = tree.get("type");
if (typeNode == null || typeNode.asText().isEmpty()) {
throw ctxt.mappingException("/"type/" is required");
}
example.setType(typeNode.asText());
switch (typeNode.asText()) {
case TYPE_A:
ArrayNode listANode = (ArrayNode) tree.get("ListA");
if (listANode == null || listANode.size() == 0) {
throw ctxt.mappingException(
"/"ListA/" is required when /"type/" is /"" + TYPE_A + "/"");
}
example.setListA(createList(listANode));
break;
case TYPE_B:
ArrayNode listBNode = (ArrayNode) tree.get("ListB");
if (listBNode == null || listBNode.size() == 0) {
throw ctxt.mappingException(
"/"ListB/" is required when /"type/" is /"" + TYPE_B + "/"");
}
example.setListB(createList(listBNode));
break;
default:
throw ctxt.mappingException(
"/"type/" must be /"" + TYPE_A + "/" or /"" + TYPE_B + "/"");
}
return example;
}
private List<Integer> createList(ArrayNode arrayNode) {
List<Integer> list = new ArrayList<Integer>();
for (JsonNode node : arrayNode) {
list.add(node.asInt());
}
return list;
}
}
Registrar el deserializador personalizado
Registre el deserializador personalizado definido anteriormente en su ObjectMapper
:
SimpleModule module = new SimpleModule("ExampleDeserializer",
new Version(1, 0, 0, null, "com.example", "example-deserializer"));
ExampleDeserializer exampleDeserializer = new ExampleDeserializer();
module.addDeserializer(Example.class, exampleDeserializer);
ObjectMapper mapper = new ObjectMapper()
.registerModule(module)
.enable(SerializationFeature.INDENT_OUTPUT);
Probando su deserializador personalizado
Use el serializador personalizado:
String json = "{/"type/":/"A/",/"ListA/":[1,2,3]}";
Example example = mapper.readValue(json, Example.class);