Rev*_*ech 5 java serialization date gson retrofit
据我所知,gson不会自动将java.util.Date对象序列化和反序列化为ISO字符串,如"yyyy-MM-ddTHH:mm:ssZ"或例如"2014-04-15T18:22:00-05" :00" .因此,为了让我在我的客户端(使用Retrofit和gson)和服务器之间正确地交换日期,我需要将DateFormat指定为gson.这就是我所做的:
// code defining the creation of a RestAdapter
// ...
new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create()
Run Code Online (Sandbox Code Playgroud)
添加.setDateFormat行足以让gson将时间戳字符串正确反序列化为Date对象.但是,它没有将Date对象序列化为时间戳字符串.所以我假设我必须像这样创建一个自定义序列化器:
// code defining the creation of a RestAdapter
// ...
new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.registerTypeAdapter(Date.class, new DateSerializer())
.create()
Run Code Online (Sandbox Code Playgroud)
和DateSerializer类:
class DateSerializer implements JsonSerializer<Date> {
@Override
public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
return new JsonPrimitive(df.format(arg0));
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,序列化函数被忽略了.相反,gson将日期格式化为字符串,如"Tues Mar 15 18:22:00 EST 2014".所以为了测试,我尝试用以下代码替换serialize函数:
public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) {
throw new RuntimeException("Serialize function called!");
}
Run Code Online (Sandbox Code Playgroud)
但是当然永远不会抛出RuntimeException.
有谁知道为什么我的序列化函数被忽略了?我想我在某处阅读过,对于某些类型,如果为超类定义了一个,则会忽略registerTypeAdapter,但由于这是java.util.Date,如果这是问题,我会感到困惑.我可能只是在做一些愚蠢的事情,但我可能不知道Date或gson足以实现它.
编辑:提供了以下代码的更多上下文:
MyApplication.java
public class MyApplication extends Application {
public static RestAdapter restAdapter;
public static The1Api the1Api;
public static void createRestAdapter(String server_url){
// enable cookies
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);
// create rest adapter
restAdapter = new RestAdapter.Builder()
.setEndpoint(server_url)
.setConverter(new GsonConverter(new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.registerTypeAdapter(Date.class, new DateSerializer())
.create()))
.setLogLevel(LogLevel.FULL)
.setLog(new ResponseInterceptor())
.build();
// create API
the1Api = restAdapter.create(The1Api.class);
}
}
Run Code Online (Sandbox Code Playgroud)
The1Api.java
public interface The1Api {
/* Chat */
public class PublicMessage {
String from_user;
String message;
Date time;
Integer microsecond;
Boolean in_1_percent;
}
public class PublicMessageList {
Integer last_message_id;
ArrayList<PublicMessage> messages;
}
@GET("/chat/get_public_messages/")
public PublicMessageList getPublicMessages(
@Query("last_message_id") Integer last_message_id, // optional
@Query("since") Date since, // optional
@Query("max") Integer max // optional
);
// ...
}
Run Code Online (Sandbox Code Playgroud)
LoginActivity.java
public class LoginActivity extends Activity {
// ...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Crashlytics.start(this);
MyApplication.createRestAdapter(getString(R.string.server_url));
setContentView(R.layout.activity_login);
}
@Override
protected void onPostCreate(Bundle savedInstanceState){
super.onPostCreate(savedInstanceState);
Thread thread = new Thread(){
@Override
public void run(){
ArrayList<The1Api.PublicMessage> publicMessages = MyApplication.the1Api.getPublicMessages(null, null, null).messages;
for (The1Api.PublicMessage m : publicMessages){
Log.d("The1", "[" + m.time.toString() + "] " + m.from_user + ": " + m.message);
}
// when the following line gets executed, my server receives a request including the date below,
// but the server does not understand the format of the date because it does not get serialized properly
MyApplication.the1Api.getPublicMessages(null, new Date(1000000000), null);
}
};
thread.start();
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
DateSerializer.java
class DateSerializer implements JsonSerializer<Date> {
@Override
public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
return new JsonPrimitive(df.format(arg0));
}
}
Run Code Online (Sandbox Code Playgroud)
编辑2:尚未解决方案,但作为一种解决方法,您可以在发送之前手动将日期转换为其他格式.在评论中,Kalel建议将其转换为String,我将其转换为Long(自UNIX纪元以来的秒数).
您还能重现这个问题吗?我看到 Gson 序列化和反序列化正确。这可能是一个改造问题(我以前没有使用过它),但是查看文档,GsonConverter我发现除了委托给Gson对象中提供的对象之外,没有理由它会执行任何其他操作。
这是一个 SSCCE:
public class GsonDateDemo {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.registerTypeAdapter(Date.class, new DateSerializer())
.create();
Date d = new Date(1438806977000L);
System.out.println("Serializing "+d);
String json = gson.toJson(d);
System.out.println("JSON: "+json);
Date d2 = gson.fromJson(json, Date.class);
System.out.println("Deserialized: "+d2);
System.out.println("Equal? "+d.equals(d2));
}
static class DateSerializer implements JsonSerializer<Date> {
@Override
public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2) {
System.out.println("Serializer received "+arg0);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
return new JsonPrimitive(df.format(arg0));
}
}
}
Run Code Online (Sandbox Code Playgroud)
这输出:
Calling: local.GsonDateDemo.main[]
Serializing Wed Aug 05 16:36:17 EDT 2015
Serializer received Wed Aug 05 16:36:17 EDT 2015
JSON: "2015-08-05T16:36:17-0400"
Deserialized: Wed Aug 05 16:36:17 EDT 2015
Equal? true
Run Code Online (Sandbox Code Playgroud)
如果可以,请修改此 SSCCE 以使用 Retrofit,并查看是否可以通过这种方式复制故障。
| 归档时间: |
|
| 查看次数: |
2161 次 |
| 最近记录: |