RETROFIT如何解析此响应 [英] RETROFIT how to parse this response

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

问题描述

我正在尝试解析此json响应

I'm trying to parse this json response yahoo yql with Retrofit,but the problem is that the response begins(as you can see in the link above) with the following characters: "finance_charts_json_callback(".

因此,我得到以下错误: com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:预期为BEGIN_OBJECT,但位于第1行第1列路径$ 上.

Therefore i get the following error: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $ .

是否可以使用Retrofit解析此json文件? 预先感谢

Is posible to parse this json file with Retrofit? Thanks in advance

推荐答案

它返回由回调函数(jsonp)调用的json.剥离函数包装并对其进行解析,或者调用一个不基于jsonp的端点(如果有).

It returns a json that's invoked by a callback function(jsonp). Strip out the function wrapper and parse it or invoke an endpoint that's not jsonp based if one available.

更新1:

以下是我们如何使用正则表达式将jsonp响应转换为json的示例:

The following is a sample of how we can convert the jsonp response to json using regex:

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);
    }
}

更新2:

我已经扩展了现有的GsonConverterFactory以支持jsonp.

I have extended the existing GsonConverterFactory to support jsonp.

//JsonpGsonResponseBodyConverter.java

//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

//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);
  }
}

现在,在构建服务时,将上述转换器注册为新的转换器,如下所示:

Now while building the service, register the above converter to retrofit as converter like below:

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

更新3:

"GsonRequestBodyConverter"类已经具有以下依赖关系,但是出于完整性考虑,我在此处添加了它:

The class "GsonRequestBodyConverter" already comes with the following dependency, but I am adding it here for the sake of completeness:

"com.squareup.retrofit"%"converter-gson"%"2.0.0-beta2"

"com.squareup.retrofit" % "converter-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());
  }
}

最后是丢失的部分实用程序":

And finally the missing piece '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) {
        }
    }
}

这篇关于RETROFIT如何解析此响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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