2016-12-16 41 views
3

我需要解析來自Flickr API的響應。
http://api.flickr.com/services/feeds/photos_public.gne?tagmode=any&format=json如何通過Retrofit和GsonConverter處理JSONP響應?

它返回jsonFlickrFeed中的響應jQuery回調函數(這不是有效的JSON響應)。

我知道我們可以使用nojsoncallback=1查詢來移除Flickr API的JSON回調方法。

但是,有沒有更好的方法來處理JSONP響應,如果它是必須使用JSON與填充(JSONP)?

而不是獲取作爲字符串的響應,然後修剪JSON填充,然後解析剩餘的JSON數據。

樣品Flickr的API響應 -

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": "[email protected] (\"kimsworldofart\")", 
    "author_id": "[email protected]", 
    "tags": "otisstreetartsproject gatewayartsdistrict mountrainier princegeorgescounty maryland" 
}]}) 

如何覆蓋GSON轉換修剪這些額外的功能語法,然後分析剩餘的有效JSON?

回答

2

使用標準GsonConverterFactory作爲指導,我們可以構建一個從該流的前部移除JSONP,從而避免必須閱讀整個事情和修剪 -

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元素留在流中。

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工廠 -

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

注:使用此轉換器將要求所有的反應是在JSONP。它會在常規的JSON響應中失敗,並且不能同時使用Gson和GsonP轉換器。