java - Json to Java POJO with Jackson API Hangouts

标签 java json google-api jackson google-hangouts

我在网上找不到任何帮助,所以我在这里问。我想用 java 类创建一个 Google 卡片。所以,我要创建的 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"
   }
}

我已经设置了大量参数,但没有读取任何内容,所以我需要帮助。

最佳答案

Google API 构建结构化数据模型通常并不容易。在 Card Formatting Messages在页面中,我们可以看到针对不同类型卡片的许多不同的 JSON 有效负载。在 Github 上我们可以找到 Hangouts Chat code samples项目介绍CardResponseBuilder类,它提供了一些构建器方法来构建不同类型的卡片。我认为,这是一个很好的方法。如果可以,你可以尝试使用这个类。它依赖于 javax.json 库。使用此类并知道 JacksonMap 序列化为 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);
    }
}

我只是根据 MapJsonObjectBuilder 替换为 ObjectBuilder 并将 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 属性的方法,因为我没有在文档中找到它,但您应该能够自己完成。

关于java - Json to Java POJO with Jackson API Hangouts,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54888686/

相关文章:

java - 如何评估java版本升级的风险?

java - 删除数组中的重复项 - Java

javascript - 使用输入范围缩放谷歌地图

php - 获取数百个地址的 lat lng

java - Selenium Java Webdriver : Adding a string to an Xpath

java - 如何使用 volley 库访问 restful web 服务方法

python - 带有坐标的推文 Tweepy python

json - 从返回类型为 JSON 的方法返回两个记录集?

android - 无法使用 android JellyBean 启动接收器 : android. os.NetworkOnMainThreadException

python - 使用 google bigquery API 时避免 DefaultCredentialsError