2015-12-22 1 views
1

J'essaye d'analyser cette réponse json yahoo yql avec Retrofit, mais le problème est que la réponse commence (comme vous pouvez le voir dans le lien ci-dessus) avec les caractères suivants: "finance_charts_json_callback (" .RETROFIT comment analyser cette réponse

donc j'obtiens l'erreur suivante: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: BEGIN_OBJECT attendu, mais était STRING à la ligne 1 colonne 1 chemin $

est-es posible pour analyser. ce fichier json avec Retrofit? Merci d'avance

+0

Je pense qu'il ya un point final de requête directe pour obtenir uniquement les données JSON. Je n'arrive pas à le trouver, cependant. –

Répondre

2

Il renvoie un fichier json qui est appelé par une fonction de rappel (jsonp). Supprimez le wrapper de fonction et analysez-le ou appelez un point de terminaison qui n'est pas basé sur jsonp s'il est disponible.

Update1:

Voici un exemple de la façon dont nous pouvons convertir la réponse jsonp à JSON utilisant l'expression rationnelle:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

/** 
* Created by jamesanto on 12/22/15. 
*/ 
public class JsonpParser { 

    private static final Pattern JSONP = Pattern.compile("(?s)\\w+\\((.*)\\).*"); 

    public static String jsonpToJson(String jsonStr) { 
     Matcher matcher = JSONP.matcher(jsonStr); 
     if(matcher.find()) { 
      return matcher.group(1); 
     } else { 
      throw new IllegalArgumentException("Unknown jsonp format"); 
     } 
    } 

    public static void main(String[] args) { 
     String sampleJson = "finance_charts_json_callback({\n" + 
       " \"base\": \"cmc stations\",\n" + 
       " \"clouds\": {\n" + 
       "  \"all\": 75\n" + 
       " },\n" + 
       " \"cod\": 200,\n" + 
       " \"coord\": {\n" + 
       "  \"lat\": 51.51,\n" + 
       "  \"lon\": -0.13\n" + 
       " },\n" + 
       " \"dt\": 1450807548,\n" + 
       " \"id\": 2643743,\n" + 
       " \"main\": {\n" + 
       "  \"humidity\": 82,\n" + 
       "  \"pressure\": 1011,\n" + 
       "  \"temp\": 286.94,\n" + 
       "  \"temp_max\": 287.59,\n" + 
       "  \"temp_min\": 286.15\n" + 
       " },\n" + 
       " \"name\": \"London\",\n" + 
       " \"sys\": {\n" + 
       "  \"country\": \"GB\",\n" + 
       "  \"id\": 5091,\n" + 
       "  \"message\": 0.0136,\n" + 
       "  \"sunrise\": 1450771468,\n" + 
       "  \"sunset\": 1450799652,\n" + 
       "  \"type\": 1\n" + 
       " },\n" + 
       " \"weather\": [\n" + 
       "  {\n" + 
       "   \"description\": \"light rain\",\n" + 
       "   \"icon\": \"10n\",\n" + 
       "   \"id\": 500,\n" + 
       "   \"main\": \"Rain\"\n" + 
       "  },\n" + 
       "  {\n" + 
       "   \"description\": \"light intensity drizzle rain\",\n" + 
       "   \"icon\": \"09n\",\n" + 
       "   \"id\": 310,\n" + 
       "   \"main\": \"Drizzle\"\n" + 
       "  }\n" + 
       " ],\n" + 
       " \"wind\": {\n" + 
       "  \"deg\": 210,\n" + 
       "  \"gust\": 14.9,\n" + 
       "  \"speed\": 9.8\n" + 
       " }\n" + 
       "});"; 


     String json = jsonpToJson(sampleJson); 
     System.out.println(json); 
    } 
} 

Mise à jour 2:

J'ai prolongé la GsonConverterFactory existant pour prendre en charge jsonp.

//JsonpGsonResponseBodyConverter.java

package retrofit; 

import com.google.gson.Gson; 
import com.squareup.okhttp.ResponseBody; 
import java.io.IOException; 
import java.io.Reader; 
import java.lang.reflect.Type; 

final class JsonpGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { 
    private final Gson gson; 
    private final Type type; 

    JsonpGsonResponseBodyConverter(Gson gson, Type type) { 
    this.gson = gson; 
    this.type = type; 
    } 

    private static String readerToString(Reader reader) throws IOException { 
    StringBuilder builder = new StringBuilder(); 
    int charsRead = -1; 
    char[] chars = new char[100]; 
    do{ 
     charsRead = reader.read(chars,0,chars.length); 
     //if we have valid chars, append them to end of string. 
     if(charsRead>0) 
     builder.append(chars,0,charsRead); 
    }while(charsRead>0); 
    return builder.toString(); 
    } 

    @Override public T convert(ResponseBody value) throws IOException { 
    Reader reader = value.charStream(); 
    try { 
     String jsonp = readerToString(reader); 
     String json = JsonpParser.jsonpToJson(jsonp); 
     return gson.fromJson(json, type); 
    } finally { 
     Utils.closeQuietly(reader); 
    } 
    } 
} 

//JsonpGsonConverterFactory.java

package retrofit; 

import com.google.gson.Gson; 
import com.squareup.okhttp.RequestBody; 
import com.squareup.okhttp.ResponseBody; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.Type; 

/** 
* A {@linkplain Converter.Factory converter} which uses Gson for JSON. 
* <p> 
* Because Gson is so flexible in the types it supports, this converter assumes that it can handle 
* all types. If you are mixing JSON serialization with something else (such as protocol buffers), 
* you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this instance} 
* last to allow the other converters a chance to see their types. 
*/ 
public final class JsonpGsonConverterFactory extends Converter.Factory { 
    /** 
    * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and 
    * decoding from JSON (when no charset is specified by a header) will use UTF-8. 
    */ 
    public static JsonpGsonConverterFactory create() { 
    return create(new Gson()); 
    } 

    /** 
    * Create an instance using {@code gson} for conversion. Encoding to JSON and 
    * decoding from JSON (when no charset is specified by a header) will use UTF-8. 
    */ 
    public static JsonpGsonConverterFactory create(Gson gson) { 
    return new JsonpGsonConverterFactory(gson); 
    } 

    private final Gson gson; 

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

    @Override 
    public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) { 
    return new JsonpGsonResponseBodyConverter<>(gson, type); 
    } 

    @Override public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) { 
    return new GsonRequestBodyConverter<>(gson, type); 
    } 
} 

Maintenant tout en construisant le service, l'enregistrement du convertisseur ci-dessus pour rénover comme convertisseur comme ci-dessous:

Retrofit retrofit = new Retrofit.Builder() 
        .setEndpoint("<yahoo api url>").setConverter(JsonpGsonConverterFactory.create()) 
        .build(); 

Mise à jour 3:

La classe « GsonRequestBodyConverter » vient déjà avec la dépendance suivante, mais j'ajoute ici par souci d'exhaustivité:

« com.squareup.retrofit » % « convertisseur gson » % « 2.0. 0-beta2"

package retrofit; 

import com.google.gson.Gson; 
import com.squareup.okhttp.MediaType; 
import com.squareup.okhttp.RequestBody; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.io.Writer; 
import java.lang.reflect.Type; 
import java.nio.charset.Charset; 
import okio.Buffer; 

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> { 
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); 
    private static final Charset UTF_8 = Charset.forName("UTF-8"); 

    private final Gson gson; 
    private final Type type; 

    GsonRequestBodyConverter(Gson gson, Type type) { 
    this.gson = gson; 
    this.type = type; 
    } 

    @Override public RequestBody convert(T value) throws IOException { 
    Buffer buffer = new Buffer(); 
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8); 
    try { 
     gson.toJson(value, type, writer); 
     writer.flush(); 
    } catch (IOException e) { 
     throw new AssertionError(e); // Writing to Buffer does no I/O. 
    } 
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString()); 
    } 
} 

Et enfin la pièce manquante '' Utils:

package retrofit; 

import java.io.Closeable; 
import java.io.IOException; 

/** 
* Created by jamesanto on 12/23/15. 
*/ 
public final class Utils { 
    static void closeQuietly(Closeable closeable) { 
     if (closeable == null) return; 
     try { 
      closeable.close(); 
     } catch (IOException ignored) { 
     } 
    } 
} 
+0

C'est le problème pour moi, je ne sais pas comment dépouiller le wrapper de fonction et c'est le point de terminaison unique pour obtenir des données historiques de Yahoo. –

+0

Pouvez-vous essayer la réponse mise à jour? – James

+0

Un grand merci, votre solution supprime correctement la chaîne "finance_charts_json_callback (", mais ne peut toujours pas utiliser Retrofit –