如何通过Retrofit和GsonConverter处理JSONP响应? [英] How to handle JSONP response through Retrofit and GsonConverter?

查看:158
本文介绍了如何通过Retrofit和GsonConverter处理JSONP响应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要解析Flickr API的响应.
http://api.flickr.com/services/feeds/photos_public.gne?tagmode = any& format = json

I need to parse a response from the Flickr API.
http://api.flickr.com/services/feeds/photos_public.gne?tagmode=any&format=json

在jsonFlickrFeed jQuery回调函数中返回响应(这不是有效的JSON响应).

which returns a response in jsonFlickrFeed jQuery call back function (which is not a valid JSON response).

我知道我们可以使用nojsoncallback=1查询删除Flickr API的JSON回调方法.

I know we can remove JSON callback method for Flickr API using nojsoncallback=1 query.

但是,如果强制使用带有填充的JSON(JSONP),是否有更好的方法来处理JSONP响应?

But is there any better approach to handle JSONP response if it is mandatory to use JSON with Padding (JSONP)?

而不是将响应作为字符串获取,而是修剪JSON填充,然后解析剩余的JSON数据.

Instead of getting the response as a String, then trimming of the JSON padding and then parse the remaining JSON data.

示例Flickr API响应-

Sample Flickr API response-

jsonFlickrFeed({
"title": "Recent Uploads tagged mountrainier",
"link": "http:\/\/www.flickr.com\/photos\/tags\/mountrainier\/",
"description": "",
"modified": "2016-12-15T16:56:42Z",
"generator": "http:\/\/www.flickr.com",
"items": [ {
    "title": "Gateway Arts District Open Studio Tour, December 10, 2016",
    "link": "http:\/\/www.flickr.com\/photos\/kimsworldofart\/31274762970\/",
    "media": {
        "m": "http:\/\/farm1.staticflickr.com\/381\/31274762970_c40599d623_m.jpg"
    },
    "date_taken": "2016-12-10T15:49:03-08:00",
    "description": " <p><a href=\"http:\/\/www.flickr.com\/people\/kimsworldofart\/\">kimsworldofart<\/a> posted a photo:<\/p> <p><a href=\"http:\/\/www.flickr.com\/photos\/kimsworldofart\/31274762970\/\" title=\"Gateway Arts District Open Studio Tour, December 10, 2016\"><img src=\"http:\/\/farm1.staticflickr.com\/381\/31274762970_c40599d623_m.jpg\" width=\"240\" height=\"135\" alt=\"Gateway Arts District Open Studio Tour, December 10, 2016\" \/><\/a><\/p> <p>This photo was taken at the Otis Street Art Project in Mount Rainier, Maryland.<\/p>",
    "published": "2016-12-14T20:25:11Z",
    "author": "nobody@flickr.com (\"kimsworldofart\")",
    "author_id": "8508061@N02",
    "tags": "otisstreetartsproject gatewayartsdistrict mountrainier princegeorgescounty maryland"
}]})

如何重写GSON Converter以修剪这些额外的函数语法,然后解析剩余的有效JSON?

How to override GSON Converter to trim of these extra function syntax and then parse the remaining valid JSON?

推荐答案

使用标准的GsonConverterFactory作为指导,我们可以构造一个从流的开头删除JSONP的对象,从而避免必须阅读整个内容并修剪-

Using the standard GsonConverterFactory as guide, we can construct one that removes the JSONP from the front of the stream, thus avoid having to read the whole thing and trim --

public final class GsonPConverterFactory extends Converter.Factory {

  Gson gson;

  public GsonPConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                          Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonPResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                        Annotation[] parameterAnnotations,
                                                        Annotation[] methodAnnotations,
                                                        Retrofit retrofit) {
    return null;
  }
}

和转换器主体.通过创建自己的json阅读器,我们避免断言该流已被完全消耗.这使我们在关闭流时将关闭的JSONP元素保留在流中.

and the converter body. By creating our own json reader, we avoid the assertion that the stream was fully consumed. This allows us to leave the closing JSONP elements in the stream when we close it.

final public class GsonPResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonPResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    Reader reader = value.charStream();
    int item = reader.read();
    while(item != '(' && item != -1) {
      item = reader.read();
    }
    JsonReader jsonReader = gson.newJsonReader(reader);
    try {
      return adapter.read(jsonReader);
    } finally {
      reader.close();
    }
  }
}

像普通的Gson工厂一样添加到您的改造中-

add to your retrofit like you would the regular Gson factory --

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(/* you base url */)
    .addConverterFactory(new GsonPConverterFactory(new Gson()))
    .build();

注意:使用此转换器将要求所有响应都使用JSONP.在常规的JSON响应上它将失败,并且您不能同时使用Gson和GsonP转换器.

Note: using this converter will require all responses to be in JSONP. It will fail on regular JSON responses, and you cannot use the Gson and GsonP converters at the same time.

这篇关于如何通过Retrofit和GsonConverter处理JSONP响应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆