#java #json #jackson
Вопрос:
В настоящее время я борюсь с десериализацией структуры данных JSON, которая выглядит примерно так:
Пример 1:
{
"condition": "AND",
"rules": [
{
"id": "FIELD1",
"field": "FIELD1",
"type": "string",
"input": "select",
"operator": "equal",
"value": [
"a1"
]
},
{
"id": "FIELD2",
"field": "FIELD2",
"type": "string",
"input": "select",
"operator": "in",
"value": [
"b1"
]
}
]
}
Пример 2:
{
"condition": "AND",
"rules": [
{
"id": "FIELD1",
"field": "FIELD1",
"type": "string",
"input": "select",
"operator": "equal",
"value": [
"a1"
]
},
{
"id": "FIELD2",
"field": "FIELD2",
"type": "string",
"input": "select",
"operator": "in",
"value": [
"b1",
"b2",
"b3"
]
},
{
"id": "FIELD3",
"field": "FIELD3",
"type": "string",
"input": "select",
"operator": "in",
"value": [
"c1",
"c2",
"c3"
]
},
{
"id": "FIELD4",
"field": "FIELD4",
"type": "string",
"input": "select",
"operator": "in",
"value": [
"d1",
"d2",
"d3"
]
},
{
"condition": "AND",
"rules": [
{
"id": "FIELD5",
"field": "FIELD5",
"type": "string",
"input": "select",
"operator": "equal",
"value": [
"e1"
]
},
{
"id": "FIELD6",
"field": "FIELD6",
"type": "string",
"input": "select",
"operator": "in",
"value": [
"f1",
"f1",
"f3",
"f4",
"f5",
"f6"
]
},
{
"condition": "AND",
"rules": [
{
"id": "FIELD7",
"field": "FIELD7",
"type": "string",
"input": "select",
"operator": "in",
"value": [
"g1",
"g2",
"g3"
]
}
]
}
]
}
]
}
Есть много примеров такой структуры, которые я должен обработать. Это результат работы построителя правил. Я не могу изменить формат JSON, я должен работать с тем, что у меня есть. Структура рекурсивна, может быть несколько уровней.
Я использую ObjectMapper от Джексона и создаю некоторые внутренние классы для отображения данных.
static class Wrapper {
public Condition condition;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
@JsonSubTypes.Type(RuleGroup.class),
@JsonSubTypes.Type(Rule.class) })
public List<AbstractRuleObject> rules;
}
static abstract class AbstractRuleObject {
public Condition condition;
public List<Rule> rules;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
@JsonSubTypes.Type(RuleGroup.class),
@JsonSubTypes.Type(Rule.class) })
public List<AbstractRuleObject> ruleGroups;
}
static class RuleGroup extends AbstractRuleObject {
public Condition condition;
public List<Rule> rules;
}
static class Rule extends AbstractRuleObject {
public String id;
public String field;
public String type;
public String input;
public Operator operator;
public List<String> value;
}
Большинство примеров выглядят как Пример 1, и для тех, кто уже работает нормально, но есть более сложные, такие как Пример 2, на самом деле даже более сложные и глубокие, чем пример 2, но структура всегда одна и та же:
Всегда существует «Группа правил» с одним «Условием» и одним списком «Правил», правила могут быть либо «Правилом», либо снова «Группой правил», нет ограничений на то, насколько глубоко вы можете зайти, но я считаю, что это не глубже 4 или 5 уровней. На каждом уровне может быть несколько «групп правил»
Я не могу проанализировать эти более глубокие примеры, с текущим кодом и примером 2 я получаю следующую ошибку:
Не удалось разрешить подтип [простой тип, класс MyClass$AbstractRuleObject]: Не удается вывести уникальный подтип
MyClass$AbstractRuleObject
(совпадают 2 кандидата)
Ответ №1:
Правило и группа правил не имеют ничего общего, за исключением того, что они оба могут отображаться в списке, поэтому AbstractRuleObject
не должны иметь condition
и rules
в нем-a Rule
не имеет этих свойств.
Мы тоже можем избавиться от Wrapper
него, так как он идентичен RuleGroup
.
Это работает для меня:
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
public class ParseExample {
static class RuleObject {
}
static class RuleGroup extends RuleObject {
public String condition;
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
@JsonSubTypes.Type(RuleGroup.class),
@JsonSubTypes.Type(Rule.class)})
public List<RuleObject> rules;
}
static class Rule extends RuleObject{
public String id;
public String field;
public String type;
public String input;
public String operator;
public List<String> value;
}
public static void main(String... args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.createParser(ParseExample.class.getClassLoader().getResourceAsStream("test2.json"));
RuleGroup w = parser.readValueAs(new TypeReference<RuleGroup>() {});
}
}
Версия Джексона:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
Результат:
args = {String[0]@1361} []
mapper = {ObjectMapper@1362}
parser = {UTF8StreamJsonParser@1363}
w = {ParseExample$RuleGroup@1364}
condition = "AND"
rules = {ArrayList@1366} size = 5
0 = {ParseExample$Rule@1368}
1 = {ParseExample$Rule@1369}
2 = {ParseExample$Rule@1370}
3 = {ParseExample$Rule@1371}
4 = {ParseExample$RuleGroup@1372}
condition = "AND"
rules = {ArrayList@1380} size = 3
0 = {ParseExample$Rule@1382}
1 = {ParseExample$Rule@1383}
2 = {ParseExample$RuleGroup@1384}
condition = "AND"
rules = {ArrayList@1386} size = 1
0 = {ParseExample$Rule@1388}