Retrofit 2 및 Gson을 사용하고 있으며 API에서 응답을 역 직렬화하는 데 문제가 있습니다. 내 시나리오는 다음과 같습니다.
나는라는 이름의 모델 객체가 Employee
세 개의 필드가 있습니다 : id
, name
, age
.
다음 Employee
과 같은 단일 객체 를 반환하는 API가 있습니다 .
{
"status": "success",
"code": 200,
"data": {
"id": "123",
"id_to_name": {
"123" : "John Doe"
},
"id_to_age": {
"123" : 30
}
}
}
그리고 다음 Employee
과 같은 객체 목록 :
{
"status": "success",
"code": 200,
"data": [
{
"id": "123",
"id_to_name": {
"123" : "John Doe"
},
"id_to_age": {
"123" : 30
}
},
{
"id": "456",
"id_to_name": {
"456" : "Jane Smith"
},
"id_to_age": {
"456" : 35
}
},
]
}
여기서 고려해야 할 세 가지 주요 사항이 있습니다.
data
필드 내부의 중요한 부분과 함께 일반 래퍼로 반환됩니다 .id_to_age
의 age
필드에 매핑해야 함 ).data
API 응답 의 필드는 단일 객체 또는 객체 목록 일 수 있습니다.Gson
이 세 가지 경우를 우아하게 처리하도록 deserialization을 어떻게 구현 합니까?
이상적으로 는 성능 패널티를 지불 TypeAdapter
하거나 TypeAdapterFactory
지불하는 대신 이 작업을 완전히 수행하는 것이 좋습니다 JsonDeserializer
. 궁극적 으로이 인터페이스를 충족하는 Employee
or 인스턴스로 끝내고 싶습니다 List<Employee>
.
public interface EmployeeService {
@GET("/v1/employees/{employee_id}")
Observable<Employee> getEmployee(@Path("employee_id") String employeeId);
@GET("/v1/employees")
Observable<List<Employee>> getEmployees();
}
내가 게시 한이 이전 질문은 이에 대한 첫 번째 시도에 대해 설명하지만 위에서 언급 한 몇 가지 문제를 고려하지 못했습니다. Retrofit 및 RxJava를 사용하여 JSON이 모델 객체에 직접 매핑되지 않을 때 어떻게 역 직렬화합니까?
편집 : 관련 업데이트 : 사용자 지정 변환기 공장을 만드는 작업은 작동합니다.의 무한 루프를 방지하는 핵심 ApiResponseConverterFactory
은 nextResponseBodyConverter
건너 뛸 공장을 지정할 수있는 Retrofit을 호출 하는 것입니다. 핵심은 이것이 Gson이 Converter.Factory
아닌 Retrofit에 등록하는 것 TypeAdapterFactory
입니다. 이것은 ResponseBody의 이중 역 직렬화를 방지하기 때문에 실제로 바람직합니다 (본문을 역 직렬화 한 다음 다른 응답으로 다시 패키징 할 필요가 없음).
원래 답변 :
ApiResponseAdapterFactory
당신이 모든 서비스 인터페이스를 감싸 기꺼이하지 않는 방법이 작동하지 않습니다 ApiResponse<T>
. 그러나 OkHttp 인터셉터라는 또 다른 옵션이 있습니다.
우리의 전략은 다음과 같습니다.
Response
Response#body()
로 deserialize되고 우리가 원하는 콘텐츠가 있는 곳에 ApiResponse
new를 반환합니다 .Response
ResponseBody
그래서 ApiResponse
다음과 같이 보입니다.
public class ApiResponse {
String status;
int code;
JsonObject data;
}
ApiResponseInterceptor :
public class ApiResponseInterceptor implements Interceptor {
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public static final Gson GSON = new Gson();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
final ResponseBody body = response.body();
ApiResponse apiResponse = GSON.fromJson(body.string(), ApiResponse.class);
body.close();
// TODO any logic regarding ApiResponse#status or #code you need to do
final Response.Builder newResponse = response.newBuilder()
.body(ResponseBody.create(JSON, apiResponse.data.toString()));
return newResponse.build();
}
}
OkHttp 및 Retrofit 구성 :
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new ApiResponseInterceptor())
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.build();
그리고 Employee
하고 EmployeeResponse
따라야 내가 앞의 질문에 쓴 어댑터 공장 구조를 . 이제 모든 ApiResponse
필드는 인터셉터에서 사용되어야하며 모든 Retrofit 호출은 관심있는 JSON 콘텐츠 만 반환해야합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다