Retrofit无法自动解析内部JSON对象问题求助
Retrofit自动解析嵌套JSON对象失败的解决问题
问题说明
原本定义的ProfileResponse类中,header、tests、entries字段对应嵌套对象/数组,但Retrofit无法自动解析导致请求失败;将这些字段改为String类型后,手动用Gson解析可正常工作,希望实现Retrofit自动完整解析ProfileResponse对象。
相关代码片段
原问题模型类(解析失败版本)
public class ProfileResponse { @SerializedName("result") private int result; @SerializedName("comment") private String comment; @SerializedName("time") private String time; @SerializedName("header") private Header header; @SerializedName("tests") private Test[] tests; @SerializedName("entries") private Entry[] entries; }
临时可行模型类(需手动解析)
public class ProfileResponse { @SerializedName("result") private int result; @SerializedName("comment") private String comment; @SerializedName("time") private String time; @SerializedName("header") private String header; @SerializedName("tests") private String tests; @SerializedName("entries") private String entries; }
手动解析代码片段
String testString = profileDataString.getTests(); Test[] tests = gson.fromJson(testString, Test[].class);
嵌套对象模型类
public class Test { @SerializedName("date") private String date; @SerializedName("lessonNo") private int lessonNo; @SerializedName("testNo") private int testNo; @SerializedName("correct") private int correctAnswers; @SerializedName("wrong") private int wrongAnswers; // getters } public class Entry { @SerializedName("subjectID") private int subjectID; @SerializedName("commentID") private int commentID; @SerializedName("comment") private String comment; @SerializedName("dateTS") private String dateTime; @SerializedName("usercode") private int userCode; @SerializedName("nickname") private String nickName; @SerializedName("likepoint") private int likePoint; @SerializedName("dislikepoint") private int dislikePoint; @SerializedName("subjectName") private String subjectName; // getters } public class Header { @SerializedName("nickname") private String nickName; @SerializedName("profilephoto") private String profilePhoto; @SerializedName("totalTests") private int totalTests; @SerializedName("totalChallenges") private int totalChallenges; @SerializedName("totalpoints") private int totalPoints; @SerializedName("socialearned") private int socialEarned; // getters }
Retrofit单例类
public class ApiClientRetrofit { private static Retrofit retrofit = null; public static Retrofit getInstance() { if (retrofit == null) { HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(httpLoggingInterceptor) .build(); retrofit = new Retrofit.Builder() .baseUrl(SERVER_URL) .addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient) .build(); } return retrofit; } }
请求代码
Retrofit retrofit=ApiClientRetrofit.getInstance(); ServerApiInterface service=retrofit.create(ServerApiInterface.class); Call<ProfileResponse> call = service.loadProfile(101,0,0,10,10,1); call.enqueue(new Callback<ProfileResponse>() { @Override public void onResponse(Call<ProfileResponse> call, Response<ProfileResponse> response) { if(response.isSuccessful()){ Log.i(TAG, "onResponse: response is successful"); } } @Override public void onFailure(Call<ProfileResponse> call, Throwable t) { Log.i(TAG, "onFailure: "); } });
请求接口定义
public interface ServerApiInterface { @FormUrlEncoded @POST(ServerAdress.PROFILE_PHP) Call<ProfileResponse> loadProfile(@Field("usercode") int userCode, @Field("testStart") int testStart, @Field("entryStart") int entryStart, @Field("entryCount") int entryCount, @Field("testCount") int testCount, @Field("header") int header); }
解决方法
问题根源是服务器返回的header、tests、entries字段是JSON字符串格式(而非直接的JSON对象/数组),默认Gson无法自动将JSON字符串解析为对应对象,需自定义TypeAdapter处理:
步骤1:创建自定义TypeAdapterFactory
public class StringToObjectAdapterFactory implements TypeAdapterFactory { @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); final TypeAdapter<String> stringAdapter = gson.getAdapter(String.class); return new TypeAdapter<T>() { @Override public void write(JsonWriter out, T value) throws IOException { delegate.write(out, value); } @Override public T read(JsonReader in) throws IOException { if (in.peek() == JsonToken.STRING) { String jsonStr = stringAdapter.read(in); return gson.fromJson(jsonStr, type.getType()); } return delegate.read(in); } }; } }
步骤2:配置Retrofit使用自定义Gson
修改ApiClientRetrofit类,初始化带自定义Adapter的Gson:
public class ApiClientRetrofit { private static Retrofit retrofit = null; public static Retrofit getInstance() { if (retrofit == null) { Gson customGson = new GsonBuilder() .registerTypeAdapterFactory(new StringToObjectAdapterFactory()) .create(); HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(httpLoggingInterceptor) .build(); retrofit = new Retrofit.Builder() .baseUrl(SERVER_URL) .addConverterFactory(GsonConverterFactory.create(customGson)) .client(okHttpClient) .build(); } return retrofit; } }
步骤3:恢复原ProfileResponse类
将ProfileResponse改回最初版本,字段类型使用Header、Test[]、Entry[]即可,无需手动解析。
内容的提问来源于stack exchange,提问作者yusufff
相关产品推荐
相关产品推荐

