2016-12-16 2 views
3

Мне нужно разобрать ответ от API Flickr.
http://api.flickr.com/services/feeds/photos_public.gne?tagmode=any&format=jsonКак справиться с ответом JSONP через Retrofit и GsonConverter?

который возвращает ответ в jsonFlickrFeed JQuery функции обратного вызова (который не является правильным ответом JSON).

Я знаю, что мы можем удалить метод обратного вызова JSON для API Flickr, используя запрос nojsoncallback=1.

Но есть ли лучший подход для обработки ответа JSONP, если обязательно использовать JSON с Padding (JSONP)?

Вместо получения ответа в виде строки, затем обрезки JSON padding и последующего анализа оставшихся данных JSON.

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": "[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 одновременно.

Смежные вопросы