Преобразование JSON в POJO, имеющее свойство Json, как jsonObject, имеющее другое свойство

У меня есть новое требование, я создаю REST API с динамическим запросом (действиями), и я хочу преобразовать этот запрос JSON в POJO, я знаю, как преобразовать JSON в POJO, где ключи одинаковы, но не уверен, что делать, когда есть различное содержимое на объектах.

Мой Json выглядит следующим образом.

{
  "name":"Workflow",
  "actions": [
    {
      "name": "EDIT_PROPERTY",
      "payload": {
        "name": "city",
        "value": "Pune"
      }
    },
    {
      "name":"SEND_EMAIL",
      "payload":{
        "from":"[email protected]",
        "to":"[email protected]",
        "subject":"Try email",
        "body":"content"
      }
    },
    {
      "name":"CREATE_TASK",
      "payload":{
        "user":1,
        "type":"call",
        "status":"open",
        "note":"This is  note content"
      }
    }
  ]
}

Как вы можете видеть, действия представляют собой набор объектов, у которых есть имя и полезная нагрузка, теперь полезная нагрузка имеет разные поля, у меня есть предопределенные имена. и каждая полезная нагрузка в действии имеет предопределенные ключи, как вы видите.

Я хочу преобразовать это в POJO что-то вроде

class Workflow{
    String name;
    Set<Action> actions;
}

class Action {
    String name;
    //What to add as payload
}

Спасибо

Алпеш


person Alpesh Jikadra    schedule 08.10.2020    source источник
comment
Может быть хранить полезную нагрузку как Map‹String, Object›?   -  person SKumar    schedule 08.10.2020
comment
Но когда я использую Object, он небезопасен для типов.   -  person Alpesh Jikadra    schedule 08.10.2020
comment
@Alpesh Jikadra Какую библиотеку JSON вы использовали? Я протестировал его с помощью Jackson (JDK 1.8) для десериализации поля payload в Map<String, Object>, как прокомментировал @SKumar, и он отлично работает без каких-либо ошибок.   -  person LHCHIN    schedule 08.10.2020
comment
У вас все в порядке с Map‹String,String› или вы хотите сохранить типы данных?   -  person SKumar    schedule 08.10.2020
comment
@SKumar, да, я хочу сохранить типы данных.   -  person Alpesh Jikadra    schedule 08.10.2020


Ответы (3)


Вот что вы можете сделать:

JSON в модель POJO:

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Event {
    public String name;
    public List<Action> actions;


    @Data
    public static class Action {
        public String name;
        Map<String, Object> payload;
    }


}

public class TestJson {

    private static String json = "{\n" +
            "  \"name\":\"Workflow\",\n" +
            "  \"actions\": [\n" +
            "    {\n" +
            "      \"name\": \"EDIT_PROPERTY\",\n" +
            "      \"payload\": {\n" +
            "        \"name\": \"city\",\n" +
            "        \"value\": \"Pune\"\n" +
            "      }\n" +
            "    },\n" +
            "    {\n" +
            "      \"name\":\"SEND_EMAIL\",\n" +
            "      \"payload\":{\n" +
            "        \"from\":\"[email protected]\",\n" +
            "        \"to\":\"[email protected]\",\n" +
            "        \"subject\":\"Try email\",\n" +
            "        \"body\":\"content\"\n" +
            "      }\n" +
            "    },\n" +
            "    {\n" +
            "      \"name\":\"CREATE_TASK\",\n" +
            "      \"payload\":{\n" +
            "        \"user\":1,\n" +
            "        \"type\":\"call\",\n" +
            "        \"status\":\"open\",\n" +
            "        \"note\":\"This is  note content\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";

    @SneakyThrows
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        Event event = objectMapper.readValue(json, Event.class);
        System.out.println(event);

    }


}

При отладке вы заметите, что наши объекты были заполнены соответствующим образом:

[1]: https://i.stack.imgur.com/wbGLT.png

person anurag saxena    schedule 08.10.2020
comment
При этом я мог бы добавить слишком много полей в класс полезной нагрузки, что не требуется для других сущностей. то есть тип EDIT_PROPERTY. в будущем у меня также может быть новый тип полезной нагрузки для нового действия. - person Alpesh Jikadra; 08.10.2020
comment
@AlpeshJikadra хорошо, в этом случае я обновил полезную нагрузку как карту, то есть полезную нагрузку Map‹String, Object›; также обновил ответ, и он работает без проблем. - person anurag saxena; 08.10.2020
comment
Вместо Map‹String, Object›, Могу ли я использовать какое-то наследование, чтобы я мог использовать базовый класс вместо Map? - person Alpesh Jikadra; 08.10.2020

В общем, я предпочитаю любое решение, не использующее Аннотации компонентов. Это мое личное предпочтение, потому что устранение constructors и метода parameters обычно вызывает огромную головную боль. Это основано на опыте программирования на Java с 1999 по 2006 год. Если вам нужно динамически генерировать классы и constructors или getters, вы можете легко проигнорировать или удалить этот ответ. Для меня Синтаксический анализ JSON сейчас является практикой.

В этом опубликованном ответе я использовал более старую Java JSON Library, чей JavaDoc можно посмотреть здесь: javax.json.*. Вот мое решение. Требуется/ожидается, что вы напишете:

  • Ваши собственные toString() методы для ваших классов данных JSON
  • Ваши собственные операции извлечения

Следующий код имеет вывод, и он включен в конце этого поста. Обычно я включаю много документации по коду. Однако, когда код строго анализирует данные, сам код обычно настолько разборчив, что дополнительные комментарии загромождают операции извлечения и toString(), поэтому я оставил их как есть.

import java.util.*;
import javax.json.*;
import java.io.*;

public class Messages
{
    public abstract static class Action
    {
        public final String name;
        public Action(String name) { this.name=name; }
    }

    public static class EditProperty extends Action
    {
        public final String propName, propValue;

        public EditProperty(String name, String value)
        { super("EDIT_PROPERTY"); this.propName=name; this.propValue=value; }

        public String toString()
        { 
            return 
                "Action:   " + name         + '\n' + 
                "Name:     " + propName     + '\n' +
                "Value:    " + propValue    + '\n';
        }
    }

    public static class SendEmail extends Action
    {
        public final String from, to, subject, body;

        public SendEmail(String from, String to, String subject, String body)
        { super("SEND_EMAIL"); this.from=from; this.to=to; this.subject=subject; this.body=body; }

        public String toString()
        {
            return
                "Action:   "    + name      + '\n' +
                "From:     "    + from      + '\n' +
                "To:       "    + to        + '\n' +
                "Subject:  "    + subject   + '\n' +
                "Body:     "    + body      + '\n';
        }
    }

    public static class CreateTask extends Action
    {
        public final int user;
        public final String type, status, note;

        public CreateTask(int user, String type, String status, String note)
        { super("CREATE_TASK"); this.user=user; this.type=type; this.status=status; this.note=note; }

        public String toString()
        {
            return
                "Action:   " + name     + '\n' +
                "User:     " + user     + '\n' +
                "Type:     " + type     + '\n' +
                "Status:   " + status   + '\n' +
                "Note:     " + note     + '\n';
        }
    }

    public static void main(String[] argv) throws IOException
    {
        Vector<Action>  actions     = new Vector<>();
        Reader          r           = new FileReader("in.json");

        JsonArray       actionList  = Json
            .createReader(r)
            .readObject()
            .getJsonArray("actions");

        for (JsonObject actionObj : actionList.getValuesAs(JsonObject.class))
        {
            JsonObject  payload = actionObj.getJsonObject("payload");
            Action      action  = null;

            switch (actionObj.getString("name"))
            {
                case "EDIT_PROPERTY"    :   action = new EditProperty(
                                                payload.getString("name"),
                                                payload.getString("value")
                                            ); break;
                case "SEND_EMAIL"       :   action = new SendEmail(
                                                payload.getString("from"),
                                                payload.getString("to"),
                                                payload.getString("subject"),
                                                payload.getString("body")
                                            ); break;
                case "CREATE_TASK"      :   action = new CreateTask(
                                                payload.getInt("user"),
                                                payload.getString("type"),
                                                payload.getString("status"),
                                                payload.getString("note")
                                            ); break;
            }
            
            actions.add(action);
        }
        
        for (Action action : actions) System.out.println(action);
    }
}

Приведенный выше класс и внутренние классы будут выдавать этот вывод при вызове из командной строки:

@cloudshell:~$ java Messages 
Action:   EDIT_PROPERTY
Name:     city
Value:    Pune

Action:   SEND_EMAIL
From:     [email protected]
To:       [email protected]
Subject:  Try email
Body:     content

Action:   CREATE_TASK
User:     1
Type:     call
Status:   open
Note:     This is  note content
person Y2020-09    schedule 09.10.2020

Показанный вами JSON на самом деле представляет собой список объектов одного типа; в частности, полезная нагрузка — это просто карта строки в объект.

После того, как вы проанализируете JSON, ваш код должен будет обрабатывать каждый тип полезной нагрузки в зависимости от типа полезной нагрузки.

Вот пример кода:

public class BlamMessage
{
    private String name;
    private Map<String, Object> payload;

    ...
}

public class MessageHolder
{
    @JsonProperty("actions")
    private List<BlamMessage> messageList;

    private String name;

    ...
}
person DwB    schedule 09.10.2020