我有一个Android应用程序,它从web服务接收Json响应。其中一个响应是一个包含日期的json字符串。我得到的日期是一个类似"1476399300000"的数字。当我尝试使用GSON
创建一个对象时,我会得到以下错误:
无法分析日期["1476399300000']:时区指示符'0'无效(偏移量为0)
双方都在使用java.util.Date
如何解决此问题?
值1476399300000
看起来像Unix epoch开始时的ms。只需在Gson中添加一个类型适配器:
final class UnixEpochDateTypeAdapter
extends TypeAdapter<Date> {
private static final TypeAdapter<Date> unixEpochDateTypeAdapter = new UnixEpochDateTypeAdapter();
private UnixEpochDateTypeAdapter() {
}
static TypeAdapter<Date> getUnixEpochDateTypeAdapter() {
return unixEpochDateTypeAdapter;
}
@Override
public Date read(final JsonReader in)
throws IOException {
// this is where the conversion is performed
return new Date(in.nextLong());
}
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final Date value)
throws IOException {
// write back if necessary or throw UnsupportedOperationException
out.value(value.getTime());
}
}
配置您的Gson实例:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, getUnixEpochDateTypeAdapter())
.create();
Gson
实例和UnixEpochDateTypeAdapter
实例一样是线程安全的,并且可以作为一个实例全局存在。示例:
final class Mapping {
final Date date = null;
}
final String json = "{"date":1476399300000}";
final Mapping mapping = gson.fromJson(json, Mapping.class);
System.out.println(mapping.date);
System.out.println(gson.toJson(mapping));
将给出以下输出:
2016年10月14日星期五欧洲经济标准时间01:55:00
{"日期":1476399300000}
请注意,类型适配器被配置为覆盖默认的Gson日期类型适配器。因此,您可能需要使用更复杂的分析来检测是否只是Unix时代的毫秒。还要注意,您可以使用JsonDeserializer
,但后者以JSON树的方式工作,而类型适配器以流的方式工作——这在一定程度上更高效——可能不会累积中间结果。
编辑:
此外,它看起来可能令人困惑,但Gson可以对基元进行值转换。尽管有效负载有一个字符串值,但JsonReader.nextLong()
可以将字符串基元读取为长值。因此,为了不修改JSON文本,UnixEpochDateTypeAdapter.write
应该是out.value(String.valueOf(value.getTime()));
。
编辑
还有一个较短的解决方案(在内存树中使用JSON,而不是数据流),它只是:
final Gson builder = new GsonBuilder()
.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
public Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
return new Date(jsonElement.getAsJsonPrimitive().getAsLong());
}
})
.create();