Как не создавать много классов только для сериализации вложенной полезной нагрузки JSON? - PullRequest
0 голосов
/ 20 октября 2019

Я получил сообщение JSON от rabbitmq и имеет следующий формат:

{
   messageId: 123,
   content: {
      id: "P123456",
      status: false,
      error: {
         description: "Something has gone wrong",
         id: 'E400'
      }
   }
}

Как видите, в сообщении есть несколько вложенных объектов.

Когда придет это сообщение, я сериализую его, используя Джексона. Однако сейчас мне нужно создать несколько классов только для одного сообщения.

В приведенном выше примере сообщения я должен создать 3 класса только для сериализации и преобразования его в класс MainMessage, например так:

public class MainMessage {
   private int messageId;
   private MessageContentObject content;

   // getters/setters...
}

public class MessageContentObject {
   private String id;
   private boolean status;
   private MessageErrorObject error;

   // getters/setters...
}


public class MessageErrorObject {
   private String description;
   private string id;

   // getters/setters...
}

Это кажется очень громоздким, поскольку в некоторыхиз сообщений, вложение может быть довольно глубоким, и мне придется создать множество классов только для того, чтобы преобразовать полезную нагрузку JSON в объект класса MainMessage. MessageContentObject и MessageErrorObject в основном избыточны, потому что я никогда не буду использовать классы напрямую где-либо еще в коде. Я бы по-прежнему значения в них через MainMessage хотя, например:

@RabbitListener
public void consumeMessage(MainMessage msg) {
   System.out.println(msg.getContent().getError().getDescription());
}

Я использую Spring с Spring Boot. Действительно ли это единственный способ, который я могу сделать, когда дело доходит до работы с вложенными полезными нагрузками JSON?

Ответы [ 3 ]

1 голос
/ 20 октября 2019

, если вы не хотите создавать всю структуру данных или вам нужна только небольшая часть ответа, полученного за раз, вы можете использовать Jackson JsonNode

import com.fasterxml.jackson.databind.JsonNode;
public class Message {
    private JsonNode messageDetails;

    /**
     * Constructor used to transform your object into jsonNode.
     *
     * @param messageDetailsResponse
     */
    public Message(Object messageDetailsResponse) {
      this.messageDetails = JsonUtils.getNode(messageDetailsResponse);
    }

    //Simply create getters for accessing the data you want when you want it
    public String getId() {
      return messageDetails.findValue("messageId").asText();
    }

    //You can also use it later to map a portion of response to an model class
        public Content getContent(){
        return JsonUtils.fromJsonNode(messageDetails.get("content"),Content.class)
        }
  }

Код для JsonUtils

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

   @Slf4j
    final public class JsonUtils {
      /**
       * The Object Mapper constant to deal with JSON to/from conversion activities.
       */
      private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

      public static JsonNode getNode(Object anyObject) {

        try {
          return OBJECT_MAPPER.readTree(OBJECT_MAPPER.writeValueAsBytes(anyObject));
        } catch (IOException e) {
          log.error(e.getMessage(), e);
        }
      }

      public static <T> T fromJsonNode(final JsonNode node, final Class<T> clazz)
          throws JsonProcessingException {
        return OBJECT_MAPPER.treeToValue(node, clazz);
      }
0 голосов
/ 20 октября 2019

Некоторые предложения:

  1. Подумайте об использовании Lombok для сокращения кода, который вам нужно написать (методы получения, установки и т. Д.) - это сделает создание классов менее проблемным.

  2. Подумайте об использовании статических внутренних классов - это будет означать, что вам нужно меньше файлов.

  3. Если вы все еще предпочитаете не записывать свои классы, вы можете отменить их преобразование в строку иПройдите через Gson или подобные библиотеки.

0 голосов
/ 20 октября 2019

Во-первых, когда в вас приходит сообщение Десериализуйте это.

Теперь, если вы не хотите создавать всю структуру данных, похожую на ваш входящий JSON, вы можете выбрать Map, как это

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonCreator;

import java.util.Collections;
import java.util.Map;

public class Message {

    private final Map<String, Object> details;

    @JsonCreator // Deserialize the JSON using this creator
    public Message(final Map<String, Object> details) {

      super();
      this.details = details;
    }

    @JsonAnyGetter // Serialize this class using the data from the map
    public Map<String, Object> getDetails() {

      return Collections.unmodifiableMap(details);
    }
}

Таким образом,вам не нужно будет менять класс Message каждый раз, когда изменяется входящий JSON.

Однако этот подход полезен только тогда, когда вы не будете слишком много манипулировать данными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...