【问题标题】:Why is JsonHttpContent's output empty?为什么 JsonHttpContent 的输出是空的?
【发布时间】:2016-04-24 15:50:56
【问题描述】:

我在 Google App Engine (1.9.30) 上使用 Google Http 客户端库 (1.20) 向 Google Cloud Messaging (GCM) 服务器提交 POST 请求。代码如下:

public static HttpRequestFactory getGcmRequestFactory() {
    if (null == gcmFactory) {
        gcmFactory = (new UrlFetchTransport())
                .createRequestFactory(new HttpRequestInitializer() {
                    @Override
                    public void initialize(HttpRequest request) throws IOException {
                        request.getHeaders().setAuthorization(
                                "key=" + Config.get(Config.Keys.GCM_SERVER_API_KEY).orNull());
                        request.getHeaders().setContentType("application/json");
                        request.getHeaders().setAcceptEncoding(null);
                    }
                });
    }
    return gcmFactory;
}

public static JsonFactory getJsonFactory() {
    return jacksonFactory;
}

public static String sendGcmMessage(GcmDownstreamDto message) {
    HttpRequestFactory factory = getGcmRequestFactory();
    JsonHttpContent content = new JsonHttpContent(getJsonFactory(), message);
    String response = EMPTY;
    try {
        HttpRequest req = factory.buildPostRequest(gcmDownstreamUrl, content);
        log.info("req headers = " + req.getHeaders());
        System.out.print("req content = ");
        content.writeTo(System.out); // prints out "{}"
        System.out.println(EMPTY);
        HttpResponse res = req.execute(); // IOException here
        response = IOUtils.toString(res.getContent());
    } catch (IOException e) {
        log.log(Level.WARNING, "IOException...", e);
    }
    return response;
}

现在content.writeTo() 总是打印出空的 JSON。这是为什么?我究竟做错了什么? GcmDownstreamDto 类(使用 Lombok 生成 getter 和 setter):

@Data
@Accessors(chain = true)
public class GcmDownstreamDto {

    private String to;

    private Object data;

    private List<String> registration_ids;

    private GcmNotificationDto notification;

    public GcmDownstreamDto addRegistrationId(String regId) {
        if (null == this.registration_ids) {
            this.registration_ids = new ArrayList<>();
        }
        if (isNotBlank(regId)) {
            this.registration_ids.add(regId);
        }
        return this;
    }
}

近期目标是生成与(来自Checking the validity of an API key)相同的响应:

api_key=YOUR_API_KEY

curl --header "Authorization: key=$api_key" \
       --header Content-Type:"application/json" \
       https://gcm-http.googleapis.com/gcm/send \
       -d "{\"registration_ids\":[\"ABC\"]}"

{"multicast_id":6782339717028231855,"success":0,"failure":1,
"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}

我已经使用curl 进行了测试,所以我知道 API 密钥是有效的,我只想在 Java 代码中做同样的事情来构建我的基类。

sendGcmMessage() 被调用如下:

@Test
public void testGcmDownstreamMessage() {
    GcmDownstreamDto message = new GcmDownstreamDto().addRegistrationId("ABC");
    System.out.println("message = " + message);
    String response = NetCall.sendGcmMessage(message);
    System.out.println("Response: " + response);
}

感谢所有帮助。

【问题讨论】:

    标签: java json jackson google-http-client


    【解决方案1】:

    你需要用@Key注释POJO字段:

    import com.google.api.client.util.Key;
    
    // ...
    
    @Key private String to;
    @Key private Object data;
    @Key private List<String> registration_ids;
    
    // ...
    

    【讨论】:

      【解决方案2】:

      发现问题:这是JacksonFactory().createJsonGenerator().searialize() 的工作方式(我期待它以ObjectMapper 的方式序列化)。这是JsonHttpContent.writeTo() 的代码(来自JsonHttpContent.java in google-http-java-client):

      public void writeTo(OutputStream out) throws IOException {
          JsonGenerator generator = jsonFactory.createJsonGenerator(out, getCharset());
          generator.serialize(data);
          generator.flush();
      }
      

      Jackson JsonGenerator 需要一个键值对(在 Java 中表示为 Map),这在 JsonHttpContent 构造函数的构造函数签名中并不明显:JsonHttpContent(JsonFactory, Object)

      因此,如果不是传递GcmDownstreamDto(如问题中所定义,这将与ObjectMapper 一起使用),我将执行以下操作:

      Map<String, Object> map = new HashMap<>();
      List<String> idList = Arrays.asList("ABC");
      map.put("registration_ids", idList);
      

      一切都按预期工作,输出是:

      {"registration_ids":["ABC"]}
      

      所以只要记住将Map&lt;String, Object&gt; 作为第二个参数传递给JsonHttpContent(JsonFactory, Object) 构造函数,一切都会如你所愿。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-18
        • 1970-01-01
        • 2021-12-11
        • 2022-10-05
        相关资源
        最近更新 更多