Как создать POJO для обработки JSON данных, имеющих массив элементов, а также массив массивов элементов - PullRequest
1 голос
/ 12 марта 2020

У нас есть сценарий, где у нас есть JSON s с 2 различными значениями для поля. Мы хотели бы проанализировать все jsons, используя один и тот же POJO. Ниже вы можете найти эти 2 JSON полезные нагрузки:

{
  "values": [
    [
      {
        "name": "item_name",
        "value": "pool"
      }
    ],
    [
      {
        "name": "item_name",
        "value": "Mob"
      }
    ]
  ],
  "name": "lines"
}

И:

{
  "values": [
    {
      "name": "pack",
      "value": "Enter, HD"
    }
  ],
  "name": "lines"
}

В настоящее время, если я укажу POJO, как показано ниже, 2-е json выдает исключение

class ValuesModel extends Serializable {

  @BeanProperty
  var values: List[List[ValueModel]] = _

}

если я укажу POJO, как показано ниже, 1-е json выдает исключение

class ValuesModel extends Serializable {

  @BeanProperty
  var values: List[ValueModel] = _

}

Есть ли способ создать один POJO для синтаксического анализа обоих jsons вместо того, чтобы перехватывать исключение и анализировать с другим схема? Я использую Jackson для разбора.

1 Ответ

2 голосов
/ 12 марта 2020

В подобных случаях, когда вы хотите обрабатывать более одной схемы JSON и иметь возможность десериализовать ее в одну и ту же модель POJO, вам необходимо реализовать собственный десериализатор и реализовать все необходимые сценарии ios.

Ниже вы можете найти пример в Java как десериализовать обе JSON полезные нагрузки:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.fasterxml.jackson.databind.type.SimpleType;
import com.fasterxml.jackson.databind.util.TokenBuffer;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./src/main/resources/test.json");

        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.readValue(jsonFile, ValuesModel.class));
    }
}

class ValuesModelJsonDeserializer extends JsonDeserializer<List<ValueModel>> {

    @Override
    public List<ValueModel> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        final JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(SimpleType.constructUnsafe(ValueModel.class));
        final JsonNode root = p.readValueAsTree();
        // If node is a JSON object
        if (root.isObject()) {
            return Collections.singletonList(deserialize(p.getCodec(), root, deserializer, ctxt));
        }
        if (!root.isArray()) {
            // value is null or primitive
            return Collections.emptyList();
        }

        return StreamSupport.stream(root.spliterator(), false)
                .map(this::unwrap)
                .filter(node -> !node.isMissingNode())
                .map(node -> deserialize(p.getCodec(), node, deserializer, ctxt))
                .collect(Collectors.toList());
    }

    private JsonNode unwrap(JsonNode node) {
        if (node.isArray()) {
            if (node.isEmpty()) {
                return MissingNode.getInstance();
            }

            return node.iterator().next();
        }

        return node;
    }

    private ValueModel deserialize(ObjectCodec codec, JsonNode value, JsonDeserializer<Object> valueDeser, DeserializationContext ctxt) {
        try (JsonParser jsonParser = createNestedParser(codec, value)) {
            return (ValueModel) valueDeser.deserialize(jsonParser, ctxt);
        } catch (IOException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private JsonParser createNestedParser(ObjectCodec codec, JsonNode value) throws IOException {
        TokenBuffer buffer = new TokenBuffer(codec, false);
        codec.writeTree(buffer, value);

        JsonParser parser = buffer.asParser();
        parser.nextToken();

        return parser;
    }
}

Чтобы зарегистрировать пользовательский десериализатор, вы можете использовать @JsonDeserialize аннотацию:

@JsonDeserialize(using = ValuesModelJsonDeserializer.class)
private List<ValueModel> values;
...