json-lib反序列化Date类型问题
好久没有写过博客,记录一下最近遇到的坑吧
项目有人使用了 json-lib 库进行反序列化对象,其他的值是能正确的反序列化,但是 long 类型的时间戳却不能被反序列化,虽然 Date 类型的字段会有值,但它的值是当前时间,我们来看一段代码。
假设有一个类 Response
有一个 Date
类型的字段 date :
public class Response {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
有了这个类我们来尝试讲一段 json 串反序列化一下:
public static void main(String[] args) {
// 这里一个时间戳,为 2011-01-01 01:01:01
String json = "{\"date\":1293814861000}";
JSONObject jsonObject = JSONObject.fromObject(json);
Response o = (Response) JSONObject.toBean(jsonObject, Response.class);
System.out.println(o.getDate());
}
我们运行一下这段代码,预期控制台应该打印 Sat Jan 01 01:01:01 CST 2011
,然而它并没有,它打印了当前时间。这是为什么呢?因为 json-lib 库默认无法实现从 long
类型转为 Date
类型,它把 Date
当成了普通Java对象来处理了,通过默认的构造方法创建了实例,却没有做任何操作,导致 Date
类型的字段值错误。
如何解决这个问题呢?我们需要注册一个 Morpher
对象,这个对象描述如何将 long
类型值转为 Date
类型值,就是一个转换器的功能。来看一下这个类是怎样实现的:
import java.util.Date;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import net.sf.ezmorph.MorphException;
import net.sf.ezmorph.object.AbstractObjectMorpher;
import net.sf.json.util.JSONUtils;
/**
* @author
*/
@Slf4j
@Component
public class SimpleDateMorpher extends AbstractObjectMorpher {
static {
JSONUtils.getMorpherRegistry().registerMorpher(new SimpleDateMorpher());
}
/**
* 标注 Morpher 支持哪种类型的转换
*/
@Override
public Class morphsTo() {
return Date.class;
}
/**
* 将 json 值转为 Date 类型的值
* @param value json中的值
*/
@Override
public Object morph(Object value) {
if (value == null) {
return null;
}
if (Date.class.isAssignableFrom(value.getClass())) {
return value;
}
if (!supports(value.getClass())) {
throw new MorphException(value.getClass() + " is not supported");
}
try {
if (value instanceof Long) {
return new Date((Long) value);
} else if (value instanceof String) {
return DateUtils.formatToDate((String) value, "yyyy-MM-dd hh:mm:ss");
}
} catch (Exception e) {
log.error("转换错误 {}", value, e);
}
// unable to parse the date
throw new MorphException("Unable to parse the date " + value);
}
}
这是一个很简单的功能,就是识别 long
类型和 String
类型值转为 Date
类型的值,其中 String
转的还限定了日期字符串的格式。
只要有了这个类,我们便可以让 json-lib 正确获取 Date 的值。
可能有的同学已经发现了,我在这个类中使用 @Component
和 static 块,这是用于在 Spring 环境下,进行自动的初始化 SimpleDateMorpher
类,注册只需要一次即可,不需要每次使用重新注册。
JSONUtils.getMorpherRegistry().registerMorpher(new SimpleDateMorpher());
这一串代码即表示在 json-lib 中注册 Date 类型的转换器。实际上 json-lib 也是有实现 Date 类型的 Morpher 类的,它就是 DateMorpher
,它这个类相比较我们的是复杂一点,它支持字符串形式的转换,完整的包括了国际化的问题,相比我们的而言,它只有不支持数值类型的转换一个缺点。
我们再来试一下反序列化的代码,我们增加一行注册的代码:
public static void main(String[] args) {
// 这里一个时间戳,为 2011-01-01 01:01:01
String json = "{\"date\":1293814861000}";
DateMorpher dateMorpherClass = new DateMorpher();
JSONObject jsonObject = JSONObject.fromObject(json);
Response o = (Response) JSONObject.toBean(jsonObject, Response.class);
System.out.println(o.getDate());
}
如此便可以实现 long 和 String 值转为 Date 的功能,如有需要可自行扩展功能。
这个坑还是相对隐蔽的,一般比较难发现,希望对各位有所帮助,如果文章有不当之处,欢迎指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。