在java开发环境中, 事件过程: LocalDateTime直接作为k-v对的value存储到JSONObject对象,然后直接toJSONString入库处理了,当在别的地方直接引用k,取出对应的value,转为LocalDateTime时候出现了格式异常,大体的demo代码是这样的
LocalDateTime myDateTime = LocalDateTime.of(LocalDateTime.now().getYear(),
LocalDateTime.now().getMonth(), LocalDateTime.now().getDayOfMonth(), 16, 30, 00);
JSONObject josn = new JSONObject();
josn.put("K", myDateTime);
//入库处理
LocalDateTime referenceDatetime = LocalDateTime.parse(json.getString("K"), DateTimeFormatter.
ofPattern("yyyy-MM-dd HH:mm:ss"));
代码逻辑跑了很长一段没有出现任何异常,在fastJSON的jar版本升级后,出现了异常,为啥会这样呢?
再看一下fastJSON -> toJSONString 实现 v1.2.45 和 v1.2.49
toJSONString -> JSONSerializer -> MapSerializer ->Jdk8DateCodec::write 关注一下源码,容易理解 v1.2.45
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
} else {
if (fieldType == null) {
fieldType = object.getClass();
}
if (fieldType == LocalDateTime.class) {
final int mask = SerializerFeature.UseISO8601DateFormat.getMask();
LocalDateTime dateTime = (LocalDateTime) object;
String format = serializer.getDateFormatPattern();
if (format == null && (features & mask) != 0 || serializer.isEnabled(SerializerFeature.UseISO8601DateFormat)) {
format = formatter_iso8601_pattern;
}
//这是v1.2.45版本的逻辑,问题出在这里dateTime.getNano()=0
if (dateTime.getNano() == 0 || format != null) {
if (format == null) {
format = JSON.DEFFAULT_DATE_FORMAT;
}
write(out, dateTime, format);
} else if (out.isEnabled(SerializerFeature.WriteDateUseDateFormat)) {
//使用固定格式转化时间
write(out, dateTime, JSON.DEFFAULT_DATE_FORMAT);
} else {
out.writeLong(dateTime.atZone(JSON.defaultTimeZone.toZoneId()).toInstant().toEpochMilli());
}
} else {
out.writeString(object.toString());
}
}
}
紧跟这在分析一下v1.2.49代码逻辑
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
} else {
if (fieldType == null) {
fieldType = object.getClass();
}
if (fieldType == LocalDateTime.class) {
final int mask = SerializerFeature.UseISO8601DateFormat.getMask();
LocalDateTime dateTime = (LocalDateTime) object;
String format = serializer.getDateFormatPattern();
if (format == null) {
if ((features & mask) != 0 || serializer.isEnabled(SerializerFeature.UseISO8601DateFormat)) {
format = formatter_iso8601_pattern;
} else {
int nano = dateTime.getNano();
//v1.2.49版本,很明显变化很大,默认日期格式
if (nano == 0) {
format = formatter_iso8601_pattern;
} else if (nano % 1000000 == 0) {
format = formatter_iso8601_pattern_23;
} else {
format = formatter_iso8601_pattern_29;
}
}
}
if (format != null) {
write(out, dateTime, format);
} else if (out.isEnabled(SerializerFeature.WriteDateUseDateFormat)) {
//使用固定格式转化时间
write(out, dateTime, JSON.DEFFAULT_DATE_FORMAT);
} else {
out.writeLong(dateTime.atZone(JSON.defaultTimeZone.toZoneId()).toInstant().toEpochMilli());
}
} else {
out.writeString(object.toString());
}
}
}
当然我上述编码不规范,造成了日期格式转换错误,我把它拿出来说事,第一,组件基础原理的研究可以让我们更好的使用它,第二,我们在做开发或者其他事情的时候,不要强依赖第三方组件提供可靠的保障,数据存储和提取一定要严格而明确指定统一的格式,而不管组件默认是什么样的格式!