问题描述
我正在使用的API以平坦格式返回对象(及其包含的对象),我无法使用Retrofit和RxJava优雅地工作。
考虑针对 / employees / {id}
端点的此JSON响应:
{
id:123,
id_to_name:{
123:John Doe
},
id_to_age:{
123:30
}
}
使用Retrofit和RxJava,我如何反序列化为名称
和 age
?
理想情况下,我希望RxJava的 onNext
方法用 Employee
对象调用。这可能吗?这可能是用某种类型的自定义反序列化器子类(我现在使用Gson)?
我意识到我可以创建一个 EmployeeResponse
直接映射到JSON响应的对象,但必须将 EmployeeResponse
映射到 Employee $ c $>每次我在一个活动中使用这个对象似乎都是一种不幸。当平面响应也包含需要反序列化并设置为
Employee
中的字段的其他对象时,它也变得更加复杂。
有没有更好的方法?
完整的解决方案这看起来好像很多,但这会让你用 Employee
而不是 EmployeeResponse
编写Retrofit接口。以下是游戏计划:
- 您仍然需要
EmployeeResponse
和Employee
对象,其中EmployeeResponse
恰好映射到您从API获得的内容。将响应视为Employee
的构建器,并编写一个静态工厂方法,该方法从<$ c $返回Employee
c> EmployeeResponse ,即。Employee employee = Employee.newInstance(response);
- 您将创建一个自定义
TypeAdapterFactory
为Gson。当Gson看到你请求一个Employee
对象时,我们将使TypeAdapter实际创建一个EmployeeResponse
,然后返回Employee
通过上面描述的静态工厂方法。
TypeAdapterFactory看起来像这样:
public class EmployeeAdapterFactory实现TypeAdapterFactory {
@Override public< T> TypeAdapter< T> create(Gson gson,TypeToken< T> type){
return type.getRawType()== Employee.class
? (TypeAdapter< T>)employeeAdapter(gson,(TypeToken< Employee>)类型)
:null;
}
Private TypeAdapter< Employee> employeeAdapter(Gson gson,TypeToken< Employee> type){
return new TypeAdapter< Employee>(){
@Override public void write(JsonWriter out,Employee value)throws IOException {
//如果需要,TODO序列化逻辑从Employee返回EmployeeResponse结构
}
$ b @Override public Employee read(JsonReader in)throws IOException {
return Employee.newInstance(gson .fromJson(in,EmployeeResponse.class));
}
};
$ / code>
在制作Gson时注册工厂:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new EmployeeAdapterFactory())
.build();
Retrofit retrofit = new Retrofit.Builder()。baseUrl(https://foo.bar)
.addConverterFactory(GsonConverterFactory.create(gson))
.. 。/ /您的其他Retrofit配置,如RxJava调用适配器工厂
.build();
现在您可以安全地定义您的所有Retrofit界面, Employee
而不是 EmployeeResponse
。
The API I'm working with returns objects (and their containing objects) in a "flat" format and I'm having trouble getting this to work elegantly with Retrofit and RxJava.
Consider this JSON response for an /employees/{id}
endpoint:
{
"id": "123",
"id_to_name": {
"123" : "John Doe"
},
"id_to_age": {
"123" : 30
}
}
Using Retrofit and RxJava, how do I deserialize this to a Employee
object with fields for name
and age
?
Ideally I'd like RxJava's onNext
method to be called with an Employee
object. Is this possible? Could this perhaps be done with some type of custom deserializer subclass (I'm using Gson at the moment)?
I realize I could create an EmployeeResponse
object that maps directly to the JSON response, but having to map the EmployeeResponse
to the Employee
object every time I use this in an activity seems kind of unfortunate. It also gets much more complicated when the flat response also contains other objects that need to get deserialized and set as fields on the Employee
.
Is there a better way?
The complete solution to this will seem like a lot, but this will let you write Retrofit interfaces with Employee
instead of EmployeeResponse
. Here's the game plan:
- You will still need both
EmployeeResponse
andEmployee
objects, whereEmployeeResponse
just maps exactly to what you'd get from the API. Treat the response as a builder forEmployee
and write a static factory method that returns anEmployee
from anEmployeeResponse
, ie.Employee employee = Employee.newInstance(response);
- You will be creating a custom
TypeAdapterFactory
for Gson. When Gson sees you request aEmployee
object, we will have the TypeAdapter actually create anEmployeeResponse
, then return theEmployee
via the static factory method described above.
Your TypeAdapterFactory will look something like this:
public class EmployeeAdapterFactory implements TypeAdapterFactory {
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == Employee.class
? (TypeAdapter<T>) employeeAdapter(gson, (TypeToken<Employee>) type)
: null;
}
private TypeAdapter<Employee> employeeAdapter(Gson gson, TypeToken<Employee> type) {
return new TypeAdapter<Employee>() {
@Override public void write(JsonWriter out, Employee value) throws IOException {
// TODO serialization logic to go from an Employee back to EmployeeResponse structure, if necessary
}
@Override public Employee read(JsonReader in) throws IOException {
return Employee.newInstance(gson.fromJson(in, EmployeeResponse.class));
}
};
}
}
Register the factory when you make Gson:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new EmployeeAdapterFactory())
.build();
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://foo.bar")
.addConverterFactory(GsonConverterFactory.create(gson))
... // your other Retrofit configs, like RxJava call adapter factory
.build();
And now you can safely define all your Retrofit interfaces with Employee
instead of EmployeeResponse
.
这篇关于使用Retrofit和RxJava,当它不直接映射到模型对象时,如何反序列化JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!