JSON в Java POJO с помощью джексоновских API Hangaouts - PullRequest
0 голосов
/ 26 февраля 2019

Не могу найти никакой помощи в интернете, поэтому спрашиваю здесь.Я хочу создать карту Google с классами Java.Итак, JSON, который я хочу создать:

{
   "thread":{
      "name":"some url here"
   },
   "cards":[
      {
         "sections":[
            {
               "widgets":[
                  {
                     "textParagraph":{
                        "text":"bla bla"
                     }
                  },
                  {
                     "buttons":[
                        {
                           "textButton":{
                              "text":"reminder in 10",
                              "onClick":{
                                 "openLink":{
                                    "url":"some Method"
                                 }
                              }
                           }
                        }
                     ]
                  }
               ]
            }
         ]
      }
   ]
}

Я пробовал несколько вещей.Я даже обнаружил сайт для генерации POJO, но я не могу этого понять.Моя попытка выглядит следующим образом:

 Cards cards = new Cards();
 Sections sections = new Sections();
 Widgets widgets = new Widgets();
 TextParagraph textParagraph = new TextParagraph();
 Text text = new Text();
 Buttons button = new Buttons();
 TextButton textButton = new TextButton();
 OnClick onClick = new OnClick();
 OpenLink openLink = new OpenLink();
 NoNameClass haha = new NoNameClass();
 ThreadX threadx = new ThreadX();

 threadx.name = "spaces/" + reminder.getSpaceId() + "/threads/" + reminder.getThreadId();
 text.text = "<" + reminder.getSenderDisplayName() + "> " + reminder.getWhat();
 openLink.url = "https://media0.giphy.com/media/QNnKbtl03OGsM/giphy.gif?cid=3640f6095c5851de3064736a2ef2345a";
 onClick.openLink = openLink;
 textButton.onClick = onClick;
 textButton.text = "se 10";
 haha.textButton = textButton;
 textParagraph.textParagraph = text;
 button.buttons = Lists.newArrayList(haha);
 widgets.widgets = Lists.newArrayList(textParagraph, button);
 sections.sections = Lists.newArrayList(widgets);
 cards.thread = threadx;
 cards.cards = Lists.newArrayList(sections);

и для отправки этого запроса я создал JsonHttpContent

private String send(GenericUrl url, Cards message, String httpMethod) {
    HttpContent content = new JsonHttpContent(new JacksonFactory(),message);

    HttpRequest request;
    try {
        if (httpMethod.equals("POST")) {
            request = requestFactory.buildPostRequest(url, content);
        } else {
            request = requestFactory.buildGetRequest(url);
        }
    } catch (Exception e) {
        logger.error("Error creating request using url: {}", url, e);
        return null;
    }

    String response = "";
    try {
        HttpResponse httpResponse = request.execute();
        response = httpResponse.parseAsString();
    } catch (IOException e) {
        logger.error("Error creating request using url: {}", url, e);
    }

    return response;
}

Но это не работает вообще, и у меня JsonIgnoreProperties в trueно я получаю эту ошибку

{
   "error":{
      "code":400,
      "message":"Message cannot be empty. Discarding empty create message request in spaces/AAAADvB8eGY.",
      "errors":[
         {
            "message":"Message cannot be empty. Discarding empty create message request in spaces/AAAADvB8eGY.",
            "domain":"global",
            "reason":"badRequest"
         }
      ],
      "status":"INVALID_ARGUMENT"
   }
}

Я установил тонну параметров, но это ничего не читает, поэтому мне нужна помощь.

1 Ответ

0 голосов
/ 27 февраля 2019

Google API обычно нелегко построить модель структурированных данных.На странице Сообщения о форматировании карт мы видим множество различных JSON полезных нагрузок для разных типов карт.На Github мы можем найти примеров кода чата Hangouts проектов, в которых представлен класс CardResponseBuilder, который предоставляет некоторые методы построения для создания карт различного типа.Я думаю, это хороший подход для этого.Если вы можете, вы можете попробовать использовать этот класс.Имеет зависимость от javax.json библиотеки.Используя этот класс и зная, что Jackson сериализует Map до JSON Object и List до JSON Array, мы можем создать очень похожий класс:

class CardResponseBuilder {

    private interface Builder {
        Object get();
    }

    private ObjectBuilder createObjectBuilder() {
        return new ObjectBuilder();
    }

    private static class ObjectBuilder implements Builder {
        Map<String, Object> map = new HashMap<>(5);

        ObjectBuilder add(String key, Object value) {
            map.put(key, value);
            return this;
        }

        ObjectBuilder add(String key, Builder builder) {
            return add(key, builder.get());
        }

        @Override
        public Map<String, Object> get() {
            return map;
        }
    }

    private ArrayBuilder createArrayBuilder() {
        return new ArrayBuilder();
    }

    private static class ArrayBuilder implements Builder {
        List<Object> list = new ArrayList<>(4);

        ArrayBuilder add(Builder builder) {
            list.add(builder.get());
            return this;
        }

        @Override
        public List<Object> get() {
            return list;
        }
    }

    public static final String UPDATE_MESSAGE = "UPDATE_MESSAGE";
    public static final String NEW_MESSAGE = "NEW_MESSAGE";

    private ObjectBuilder headerNode;
    private ObjectBuilder responseNode;
    private ArrayBuilder widgetsArray;
    private ArrayBuilder cardsArray;

    /**
     * Default public constructor.
     */
    public CardResponseBuilder() {
        this.responseNode = createObjectBuilder();
        this.cardsArray = createArrayBuilder();
        this.widgetsArray = createArrayBuilder();
    }

    /**
     * Creates a new CardResponseBuilder object for responding to an interactive card click.
     *
     * @param updateType the update type, either UPDATE_MESSAGE or NEW_MESSAGE.
     */
    public CardResponseBuilder(String updateType) {
        this();
        responseNode.add("actionResponse",
                createObjectBuilder().add("type", updateType));
    }

    /**
     * Adds a header to the card response.
     *
     * @param title    the header title
     * @param subtitle the header subtitle
     * @param imageUrl the header image
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder header(String title, String subtitle, String imageUrl) {
        this.headerNode = createObjectBuilder()
                .add("header", createObjectBuilder()
                        .add("title", title)
                        .add("subtitle", subtitle)
                        .add("imageUrl", imageUrl)
                        .add("imageStyle", "IMAGE"));
        return this;
    }

    /**
     * Adds a TextParagraph widget to the card response.
     *
     * @param message the message in the text paragraph
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder textParagraph(String message) {
        this.widgetsArray.add(
                createObjectBuilder()
                        .add("textParagraph",
                                createObjectBuilder().add("text", message)));
        return this;
    }

    /**
     * Adds a KeyValue widget to the card response.
     * <p>
     * For a list of icons that can be used, see:
     * https://developers.google.com/hangouts/chat/reference/message-formats/cards#builtinicons
     *
     * @param key         the key or top label
     * @param value       the value or content
     * @param bottomLabel the content below the key/value pair
     * @param iconName    a specific icon
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder keyValue(String key, String value,
                                        String bottomLabel, String iconName) {
        this.widgetsArray.add(createObjectBuilder()
                .add("keyValue", createObjectBuilder()
                        .add("topLabel", key)
                        .add("content", value)
                        .add("bottomLabel", bottomLabel)
                        .add("icon", iconName)));
        return this;
    }

    /**
     * Adds an Image widget to the card response.
     *
     * @param imageUrl    the URL of the image to display
     * @param redirectUrl the URL to open when the image is clicked.
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder image(String imageUrl, String redirectUrl) {
        this.widgetsArray.add(createObjectBuilder()
                .add("image", createObjectBuilder()
                        .add("imageUrl", imageUrl)
                        .add("onClick", createObjectBuilder()
                                .add("openLink", createObjectBuilder()
                                        .add("url", redirectUrl)))));
        return this;
    }

    /**
     * Adds a Text Button widget to the card response.
     * <p>
     * When clicked, the button opens a link in the user's browser.
     *
     * @param text        the text on the button
     * @param redirectUrl the link to open
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder textButton(String text, String redirectUrl) {
        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("textButton", createObjectBuilder()
                                        .add("text", text)
                                        .add("onClick", createObjectBuilder()
                                                .add("openLink", createObjectBuilder()
                                                        .add("url", redirectUrl)))))));
        return this;
    }

    /**
     * Adds an Image Button widget to the card response.
     * <p>
     * When clicked, the button opens a link in the user's browser.
     *
     * @param iconName    the icon to display
     * @param redirectUrl the link to open
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder imageButton(String iconName, String redirectUrl) {
        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("imageButton", createObjectBuilder()
                                        .add("icon", iconName)
                                        .add("onClick", createObjectBuilder()
                                                .add("openLink", createObjectBuilder()
                                                        .add("url", redirectUrl)))))));
        return this;
    }

    /**
     * Adds an interactive Text Button widget to the card response.
     * <p>
     * When clicked, the button sends a new request to the bot, passing along the custom actionName
     * and parameter values. The actionName and parameter values are defined by the developer when the
     * widget is first declared (as shown below).
     *
     * @param text                   the text to display
     * @param actionName             the custom action name
     * @param customActionParameters the custom key value pairs
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder interactiveTextButton(String text, String actionName,
                                                     Map<String, String> customActionParameters) {

        // Define the custom action name and parameters for the interactive button.
        ObjectBuilder actionNode = createObjectBuilder()
                .add("actionMethodName", actionName);

        if (customActionParameters != null && customActionParameters.size() > 0) {
            addCustomActionParameters(actionNode, customActionParameters);
        }

        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("textButton", createObjectBuilder()
                                        .add("text", text)
                                        .add("onClick", createObjectBuilder()
                                                .add("action", actionNode))))));
        return this;
    }

    /**
     * Adds an interactive Image Button widget to the card response.
     * <p>
     * When clicked, the button sends a new request to the bot, passing along the custom actionName
     * and parameter values. The actionName and parameter values are defined by the developer when the
     * widget is first declared (as shown below).
     *
     * @param iconName               the pre-defined icon to display.
     * @param actionName             the custom action name
     * @param customActionParameters the custom key value pairs
     * @return this CardResponseBuilder
     */
    public CardResponseBuilder interactiveImageButton(String iconName, String actionName,
                                                      Map<String, String> customActionParameters) {

        // Define the custom action name and parameters for the interactive button.
        ObjectBuilder actionNode = createObjectBuilder()
                .add("actionMethodName", actionName);

        if (customActionParameters != null && customActionParameters.size() > 0) {
            addCustomActionParameters(actionNode, customActionParameters);
        }

        this.widgetsArray.add(createObjectBuilder()
                .add("buttons", createArrayBuilder()
                        .add(createObjectBuilder()
                                .add("imageButton", createObjectBuilder()
                                        .add("icon", iconName)
                                        .add("onClick", createObjectBuilder()
                                                .add("action", actionNode))))));
        return this;
    }

    /**
     * Builds the card response and returns a JSON object node.
     *
     * @return card response as JSON-formatted string
     */
    public Object build() {

        // If you want your header to appear before all other cards,
        // you must add it to the `cards` array as the first / 0th item.
        if (this.headerNode != null) {
            this.cardsArray.add(this.headerNode);
        }

        return responseNode.add("cards", this.cardsArray
                .add(createObjectBuilder()
                        .add("sections", createArrayBuilder()
                                .add(createObjectBuilder()
                                        .add("widgets", this.widgetsArray)))))
                .get();
    }

    /**
     * Applies sets of custom parameters to the parameter field of an action.
     *
     * @param actionNode             the JSON action node
     * @param customActionParameters the parameters to apply to the custom action
     */
    private void addCustomActionParameters(ObjectBuilder actionNode,
                                           Map<String, String> customActionParameters) {
        ArrayBuilder parametersArray = createArrayBuilder();

        customActionParameters.forEach((k, v) -> {
            parametersArray.add(createObjectBuilder()
                    .add("key", k)
                    .add("value", v));
        });

        actionNode.add("parameters", parametersArray);
    }
}

Я только что заменил JsonObjectBuilder на ObjectBuilder на основе Map и JsonArrayBuilder на ArrayBuilder на List.Ниже приведено простое использование этого компоновщика:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        Object response = new CardResponseBuilder()
                .textParagraph("bla bla")
                .textButton("reminder in 10", "some Method")
                .build();
        System.out.println(mapper.writeValueAsString(response));
    }
}

Над отпечатками кода:

{
  "cards" : [ {
    "sections" : [ {
      "widgets" : [ {
        "textParagraph" : {
          "text" : "bla bla"
        }
      }, {
        "buttons" : [ {
          "textButton" : {
            "onClick" : {
              "openLink" : {
                "url" : "some Method"
              }
            },
            "text" : "reminder in 10"
          }
        } ]
      } ]
    } ]
  } ]
}

Я не добавил методы для обработки свойства thread, потому что не нашел его в документациино вы должны быть в состоянии сделать это самостоятельно.

...