[android] retrofit2 JSONP 데이터 파싱
구글 API 적용 중 일반 JSON 이 아닌 JSONP 형식의 데이터 파싱할 상황 발생 GsonConverterFactory 적용하면 JSON 형식이 아니라며 오류 발생함 일반적인 JSON 형식 { "cursor": { "currentPageIndex": 0, "estimatedResultCount": "0" }, "context": { "title": "aaa", "total_results": "0" }, "google…
구글 API 적용 중 일반 JSON 이 아닌 JSONP 형식의 데이터 파싱할 상황 발생
GsonConverterFactory 적용하면 JSON 형식이 아니라며 오류 발생함
일반적인 JSON 형식
{
"cursor": {
"currentPageIndex": 0,
"estimatedResultCount": "0"
},
"context": {
"title": "aaa",
"total_results": "0"
},
"google": {
"url": "https://www.xxx.com?client=xxxxxxxxx"
}
}
JSONP 형식 : callback 함수명이 감싸고 있는 형태
google({
"cursor": {
"currentPageIndex": 0,
"estimatedResultCount": "0"
},
"context": {
"title": "aaa",
"total_results": "0"
},
"google": {
"url": "https://www.xxx.com?client=xxxxxxxxx"
}
});
정상적으로 파싱 하려면 콜백 관련 문자열은 제거해줘야 함
커스텀 컨버터 생성 후 레트로핏에 적용
- GsonPConverterFactory.java 생성
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
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%3C%3E(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
}
- GsonPResponseBodyConverter.java 생성
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import java.io.IOException;
import java.io.Reader;
import okhttp3.ResponseBody;
import retrofit2.Converter;
final public class GsonPResponseBodyConverter implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter adapter;
GsonPResponseBodyConverter(Gson gson, TypeAdapter 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 = new GsonBuilder()
.setLenient()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(new GsonPConverterFactory(gson))
.build();