我正在对我的REST调用使用Retrofit库。我所做的大部分工作都像黄油一样顺利,但是由于某些原因,我在将JSON时间戳字符串转换为java.util.Date
对象时遇到了问题。传入的JSON如下所示。
{
"date": "2013-07-16",
"created_at": "2013-07-16T22:52:36Z",
}
如何告诉Retrofit或Gson将这些字符串转换成java.util.Date objects
?
我正在对我的REST调用使用Retrofit库。我所做的大部分工作都像黄油一样顺利,但是由于某些原因,我在将JSON时间戳字符串转换为java.util.Date
对象时遇到了问题。传入的JSON如下所示。
{
"date": "2013-07-16",
"created_at": "2013-07-16T22:52:36Z",
}
如何告诉Retrofit或Gson将这些字符串转换成java.util.Date objects
?
Answers:
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setConverter(new GsonConverter.create(gson))
.build();
或等效的Kotlin:
val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create()
RestAdapter restAdapter = Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(T::class.java)
您可以将自定义的Gson解析器设置为可改进。更多内容:改造网站
查看Ondreju的回复,以了解如何在改造2中实施此操作。
ServiceGenerator
?
2016-02-11T13:42:14.401Z
反序列化为13:42:14
在我的语言环境中使用的日期对象。
@gderaco的答案已更新为翻新版2.0:
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
Retrofit retrofitAdapter = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
这是我的做法:
创建扩展Date的DateTime类,然后编写一个自定义反序列化器:
public class DateTime extends java.util.Date {
public DateTime(long readLong) {
super(readLong);
}
public DateTime(Date date) {
super(date.getTime());
}
}
现在,对于反序列化器部分,我们将同时注册Date和DateTime转换器:
public static Gson gsonWithDate(){
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return df.parse(json.getAsString());
} catch (final java.text.ParseException e) {
e.printStackTrace();
return null;
}
}
});
builder.registerTypeAdapter(DateTime.class, new JsonDeserializer<DateTime>() {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return new DateTime(df.parse(json.getAsString()));
} catch (final java.text.ParseException e) {
e.printStackTrace();
return null;
}
}
});
return builder.create();
}
在创建RestAdapter时,请执行以下操作:
new RestAdapter.Builder().setConverter(gsonWithDate());
您的Foo应该如下所示:
class Foo {
Date date;
DateTime created_at;
}
return df.parse(json.getAsString());
为 long timeStamp = Long.parseLong(json.getAsString()); return new java.util.Date(timeStamp);
如果无法使用自定义格式进行解析,那么Gson只能处理一种日期时间格式(在Builder中指定的格式),还可以处理iso8601。因此,一种解决方案是编写您的自定义解串器。为了解决您的问题,我定义了:
package stackoverflow.questions.q18473011;
import java.util.Date;
public class Foo {
Date date;
Date created_at;
public Foo(Date date, Date created_at){
this.date = date;
this.created_at = created_at;
}
@Override
public String toString() {
return "Foo [date=" + date + ", created_at=" + created_at + "]";
}
}
使用此反序列化器:
package stackoverflow.questions.q18473011;
import java.lang.reflect.Type;
import java.text.*;
import java.util.Date;
import com.google.gson.*;
public class FooDeserializer implements JsonDeserializer<Foo> {
public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String a = json.getAsJsonObject().get("date").getAsString();
String b = json.getAsJsonObject().get("created_at").getAsString();
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdfDateWithTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
Date date, created;
try {
date = sdfDate.parse(a);
created = sdfDateWithTime.parse(b);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return new Foo(date, created);
}
}
最后一步是Gson
使用正确的适配器创建一个实例:
package stackoverflow.questions.q18473011;
import com.google.gson.*;
public class Question {
/**
* @param args
*/
public static void main(String[] args) {
String s = "{ \"date\": \"2013-07-16\", \"created_at\": \"2013-07-16T22:52:36Z\"}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Foo.class, new FooDeserializer());
Gson gson = builder.create();
Foo myObject = gson.fromJson(s, Foo.class);
System.out.println("Result: "+myObject);
}
}
我的结果:
Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]
您可以这样定义两个新类:
import java.util.Date;
public class MyDate extends Date {
}
和
import java.util.Date;
public class CreatedAtDate extends Date {
}
您的POJO将如下所示:
import MyDate;
import CreatedAtDate;
public class Foo {
MyDate date;
CreatedAtDate created_at;
}
最后设置您的自定义解串器:
public class MyDateDeserializer implements JsonDeserializer<Date> {
public static final SimpleDateFormat sServerDateDateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public MyDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json != null) {
final String jsonString = json.getAsString();
try {
return (MyDate) sServerDateDateFormat.parse(jsonString);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}
和
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MyDate.class, new MyDateDeserializer());
这并不能直接回答所提出的问题,但是在我看来,如果编码人员对于如何解决问题具有完全的选择自由,那么这就是“最新技术”。
首先,使用java.util.Date不是最佳解决方案。原因是这些类在某些极端情况下没有理想的行为,因此在Java Instant类等的超级种子的情况下。请在以下SO问题中检查Basil Bourque的答案:在Kotlin中为API级别创建小于或等于16的Date对象
因此,我在Android上使用了ThreeTenABP的Instant类,并使用了Kotlin:
val gson = GsonBuilder().registerTypeAdapter(Instant::class.java,
JsonDeserializer<Instant> { json: JsonElement, _: Type?, _: JsonDeserializationContext? ->
ZonedDateTime.parse(
json.asJsonPrimitive.asString
).toInstant()
}
).create()
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()