gpt4 book ai didi

Android - GSon + RetroFit 中的继承和抽象类

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:27:23 24 4
gpt4 key购买 nike

我有以下类层次结构

public abstract class SyncModel {
@Expose
@SerializedName("id")
private Long globalId;

@Expose
protected DateTime lastModified;

/* Constructor, methods... */
}

public class Event extends SyncModel {
@Expose
private String title;

/* Other fields, constructor, methods... */
}

我需要向后端发送一个事件实例。

案例一。@Body

当我在请求正文中发布事件实例时,它被很好地序列化了。

RetroFit Java 接口(interface):

public interface EventAPI {
@POST("/event/create")
void sendEvent(@Body Event event, Callback<Long> cbEventId);
}

改造日志:

D   Retrofit    ---> HTTP POST http://hostname:8080/event/createD   Retrofit    Content-Type: application/json; charset=UTF-8D   Retrofit    Content-Length: 297D   Retrofit    {"title":"Test Event 01",...,"id":null,"lastModified":"2015-07-09T14:17:08.860+03:00"}D   Retrofit    ---> END HTTP (297-byte body)

Case 2. @Field

But when I post the Event instance in a request parameter, only abstract class is serialized.

RetroFit Java interface:

@FormUrlEncoded
@POST("/event/create")
void sendEvent(@Field("event") Event event, Callback<Long> cbEventId);

改造日志:

D   Retrofit    ---> HTTP POST http://hostname:8080/event/createD   Retrofit    Content-Type: application/x-www-form-urlencoded; charset=UTF-8D   Retrofit    Content-Length: 101D   Retrofit    event=SyncModel%28globalId%3Dnull%2C+lastModified%3D2015-07-09T13%3A36%3A33.510%2B03%3A00%29D   Retrofit    ---> END HTTP (101-byte body)

Notice the difference.

Questions

Why?
How can I send a serialized Event instance to backend in a request parameter?
Do I need to write a custom JSON serializer for abstract class? (example: Polymorphism with JSON)
Or is it a RetroFit specific feature (to ignore child classes)?

I've also noticed that in the 2nd case globalId field serialized name is globalId, but it should be id! It makes me think that RetroFit uses a different GsonConverter for @Field than for @Body parameters...


Configuration

Gradle dependencies

compile 'com.squareup.retrofit:retrofit:1.9.+'
compile 'com.squareup.okhttp:okhttp:2.3.+'
compile 'net.danlew:android.joda:2.8.+'
compile ('com.fatboyindustrial.gson-jodatime-serialisers:gson-jodatime-serialisers:1.1.0') { // GSON + Joda DateTime
exclude group: 'joda-time', module: 'joda-time'
}

REST 客户端

public final class RESTClient {

// Not a real server URL
public static final String SERVER_URL = "http://hostname:8080";

// one-time initialization
private static GsonBuilder builder = new GsonBuilder()
.serializeNulls()
.excludeFieldsWithoutExposeAnnotation()
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'");
// Joda DateTime type support
private static Gson gson = Converters.registerDateTime(builder).create();

private static RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL) // for development
.setEndpoint(SERVER_URL)
.setConverter(new GsonConverter(gson)) // custom converter
.build();

private static final EventAPI eventService = restAdapter.create(EventAPI.class);
/* + Getter for eventService */

static {
// forget them
restAdapter = null;
gson = null;
builder = null;
}

}

打电话

RESTClient.getEventService().sendEvent(event, new Callback<Long>() {/* ... */});

最佳答案

看看@Field's documentation .它说:

Values are converted to strings using String#valueOf(Object) and then form URL encoded.

String#valueOf(Object) 在内部调用 Object#toString()。我想您的 SyncModel 有一个 toString() 方法而 Event 没有。当 Retrofit 调用 String.valueOf(event) 时,将调用 SyncModel#toString() 而不是 Event#toString()。这就是为什么您在 Retrofit 日志中看不到 title 的原因。

Gson 在转换@Field 参数时根本不起任何作用。可以——你可以让你的 toString() 方法看起来像这样:

@Override
public String toString() {
return GsonProvider.getInstance().toJson(this);
}

将其放入您的抽象 SyncModel 类中,它也应该适用于 Event

关于Android - GSon + RetroFit 中的继承和抽象类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31317291/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com