将json格式的字符串转为对象,其中key-value有将String的日期转为Date类型,怪现象就是,转出来的Date类型的值是当前的系统时间。

网上有许多答案,在反序列化之前需要注册Date解析类型,也就是这段代码:

JSONUtils.getMorpherRegistry().registerMorpher(new DateMorpher(new String[]{"yyyy-MM-dd"}));

发现并没啥用,最后发现一切的原因都是因为这个方法用错了。

仔细看源码,原来在json-lib中一个MorpherRegistry类,所有的转化类型都存在Map morphers中。

在第一次使用JSONObject静态方法时,就会自动注册默认的类型,JSONObject.java中调用了JSONUtils.java,JSONUtils.java源码中有这么一段:

static {
MorphUtils.registerStandardMorphers(morpherRegistry);
}

在MorphUtils.java代码是:

 public class MorphUtils {
public static final BigDecimal BIGDECIMAL_ONE = new BigDecimal("1");
public static final BigDecimal BIGDECIMAL_ZERO = new BigDecimal("0"); public static void registerStandardMorphers(MorpherRegistry morpherRegistry) {
morpherRegistry.clear();
registerStandardPrimitiveMorphers(morpherRegistry);
registerStandardPrimitiveArrayMorphers(morpherRegistry);
registerStandardObjectMorphers(morpherRegistry);
registerStandardObjectArrayMorphers(morpherRegistry);
} public static void registerStandardObjectArrayMorphers(MorpherRegistry morpherRegistry) {
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new BooleanObjectMorpher(Boolean.FALSE)));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new CharacterObjectMorpher(new Character('\u0000'))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(StringMorpher.getInstance()));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Byte.class, new Byte((byte)0))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Short.class, new Short((short)0))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Integer.class, new Integer(0))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Long.class, new Long(0L))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Float.class, new Float(0.0F))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Double.class, new Double(0.0D))));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(BigInteger.class, BigInteger.ZERO)));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(BigDecimal.class, BIGDECIMAL_ZERO)));
morpherRegistry.registerMorpher(new ObjectArrayMorpher(ClassMorpher.getInstance()));
} public static void registerStandardObjectMorphers(MorpherRegistry morpherRegistry) {
morpherRegistry.registerMorpher(new BooleanObjectMorpher(Boolean.FALSE));
morpherRegistry.registerMorpher(new CharacterObjectMorpher(new Character('\u0000')));
morpherRegistry.registerMorpher(StringMorpher.getInstance());
morpherRegistry.registerMorpher(new NumberMorpher(Byte.class, new Byte((byte)0)));
morpherRegistry.registerMorpher(new NumberMorpher(Short.class, new Short((short)0)));
morpherRegistry.registerMorpher(new NumberMorpher(Integer.class, new Integer(0)));
morpherRegistry.registerMorpher(new NumberMorpher(Long.class, new Long(0L)));
morpherRegistry.registerMorpher(new NumberMorpher(Float.class, new Float(0.0F)));
morpherRegistry.registerMorpher(new NumberMorpher(Double.class, new Double(0.0D)));
morpherRegistry.registerMorpher(new NumberMorpher(BigInteger.class, BigInteger.ZERO));
morpherRegistry.registerMorpher(new NumberMorpher(BigDecimal.class, BIGDECIMAL_ZERO));
morpherRegistry.registerMorpher(ClassMorpher.getInstance());
} public static void registerStandardPrimitiveArrayMorphers(MorpherRegistry morpherRegistry) {
morpherRegistry.registerMorpher(new BooleanArrayMorpher(false));
morpherRegistry.registerMorpher(new CharArrayMorpher('\u0000'));
morpherRegistry.registerMorpher(new ByteArrayMorpher((byte)0));
morpherRegistry.registerMorpher(new ShortArrayMorpher((short)0));
morpherRegistry.registerMorpher(new IntArrayMorpher(0));
morpherRegistry.registerMorpher(new LongArrayMorpher(0L));
morpherRegistry.registerMorpher(new FloatArrayMorpher(0.0F));
morpherRegistry.registerMorpher(new DoubleArrayMorpher(0.0D));
} public static void registerStandardPrimitiveMorphers(MorpherRegistry morpherRegistry) {
morpherRegistry.registerMorpher(new BooleanMorpher(false));
morpherRegistry.registerMorpher(new CharMorpher('\u0000'));
morpherRegistry.registerMorpher(new ByteMorpher((byte)0));
morpherRegistry.registerMorpher(new ShortMorpher((short)0));
morpherRegistry.registerMorpher(new IntMorpher(0));
morpherRegistry.registerMorpher(new LongMorpher(0L));
morpherRegistry.registerMorpher(new FloatMorpher(0.0F));
morpherRegistry.registerMorpher(new DoubleMorpher(0.0D));
} private MorphUtils() {
}
}

因此,在JSONUtils初始化的时候,就将默认类型放在了MorpherRegistry的morphs中。从上面的代码可以看出来,Date不属于默认的类型。因此,这里可以看出来,在做json反序列化时,如果有需要转成Date类型的String,就需要自己手动注册一个DateMorpher。

怎么加是一个问题了。其实在文章最前面提到的网上的解决方案也并没有错,看下源码就知道了,为啥这个方法却在我使用的时候不起作用了。

在MorpherRegistry.java中Morpher注册源码:

 public class MorpherRegistry implements Serializable {
private static final long serialVersionUID = -3894767123320768419L;
private Map morphers = new HashMap(); public MorpherRegistry() {
} public synchronized Morpher[] getMorphersFor(Class clazz) {
List registered = (List)this.morphers.get(clazz);
if(registered != null && !registered.isEmpty()) {
Morpher[] morphs = new Morpher[registered.size()];
int k = 0; for(Iterator i = registered.iterator(); i.hasNext(); morphs[k++] = (Morpher)i.next()) {
;
} return morphs;
} else {
return new Morpher[]{IdentityObjectMorpher.getInstance()};
}
} public Object morph(Class target, Object value) {
if(value == null) {
Morpher var9 = this.getMorpherFor(target);
if(var9 instanceof ObjectMorpher) {
return ((ObjectMorpher)var9).morph(value);
} else {
try {
Method var10 = var9.getClass().getDeclaredMethod("morph", new Class[]{class$java$lang$Object == null?(class$java$lang$Object = class$("java.lang.Object")):class$java$lang$Object});
return var10.invoke(var9, new Object[]{value});
} catch (Exception var7) {
throw new MorphException(var7);
}
}
} else {
Morpher[] morphers = this.getMorphersFor(target); for(int i = 0; i < morphers.length; ++i) {
Morpher morpher = morphers[i];
if(morpher.supports(value.getClass())) {
if(morpher instanceof ObjectMorpher) {
return ((ObjectMorpher)morpher).morph(value);
} try {
Method e = morpher.getClass().getDeclaredMethod("morph", new Class[]{class$java$lang$Object == null?(class$java$lang$Object = class$("java.lang.Object")):class$java$lang$Object});
return e.invoke(morpher, new Object[]{value});
} catch (Exception var8) {
throw new MorphException(var8);
}
}
} return value;
}
} public synchronized void registerMorpher(Morpher morpher, boolean override) {
Object registered = (List)this.morphers.get(morpher.morphsTo());
if(override || registered == null) {
registered = new ArrayList();
this.morphers.put(morpher.morphsTo(), registered);
} if(!((List)registered).contains(morpher)) {
((List)registered).add(morpher);
} }
}

在registerMorpher()中,可以看出来morpher事实上是一个Map<Object.class, List<Morpher>>的结构,而在使用morph()将String转为对象时取得是最先符合的类型。因此,前文中提到提到的网络解决方法,在morpher.get(Object.class)不为空时,只是对List<Morpher> registered进行add操作。由此,在进行转化操作时,就不一定获取到正确的对应类型。因此从registerMorpher()方法中可以看出,我们只需要override设置为false,这个问题也就解决了。

假如我们在调试的时候,需要修改这个注册类型,且又不想重启服务的时候,这样写就很方便了。

JSONUtils.getMorpherRegistry().registerMorpher(new DateMorpher(new String[]{"yyyy-MM-dd"}), true);

这样就能获取到正确的转化类型。

前文还提到一个问题,就是时间转化,变成了当前系统的时间。在MorpherRegistry进行反序列时,morph()中

((ObjectMorpher)morpher).morph(value)

调用的方法是BeanMorpher.morph方法,在BeanMorpher.morp()方法中

 public Object morph(Object sourceBean) {
if(sourceBean == null) {
return null;
} else if(!this.supports(sourceBean.getClass())) {
throw new MorphException("unsupported class: " + sourceBean.getClass().getName());
} else {
Object targetBean = null; try {
targetBean = this.beanClass.newInstance();
PropertyDescriptor[] e = PropertyUtils.getPropertyDescriptors(this.beanClass); for(int i = 0; i < e.length; ++i) {
PropertyDescriptor targetPd = e[i];
String name = targetPd.getName();
if(targetPd.getWriteMethod() == null) {
log.info("Property \'" + this.beanClass.getName() + "." + name + "\' has no write method. SKIPPED.");
} else {
Class sourceType = null;
if(sourceBean instanceof DynaBean) {
DynaBean targetType = (DynaBean)sourceBean;
DynaProperty value = targetType.getDynaClass().getDynaProperty(name);
if(value == null) {
log.warn("DynaProperty \'" + name + "\' does not exist. SKIPPED.");
continue;
} sourceType = value.getType();
} else {
PropertyDescriptor var12 = PropertyUtils.getPropertyDescriptor(sourceBean, name);
if(var12 == null) {
log.warn("Property \'" + sourceBean.getClass().getName() + "." + name + "\' does not exist. SKIPPED.");
continue;
} if(var12.getReadMethod() == null) {
log.warn("Property \'" + sourceBean.getClass().getName() + "." + name + "\' has no read method. SKIPPED.");
continue;
} sourceType = var12.getPropertyType();
} Class var13 = targetPd.getPropertyType();
Object var14 = PropertyUtils.getProperty(sourceBean, name);
this.setProperty(targetBean, name, sourceType, var13, var14);
}
} return targetBean;
} catch (MorphException var10) {
throw var10;
} catch (Exception var11) {
throw new MorphException(var11);
}
}
}

 sourceBean不属于DynaBean,且var12的值也为null,因此返回的值就是targetBean,时间的一个实例,即当前时间。

json-lib json反序列化——日期转换的更多相关文章

  1. java中json和字符串互转及日期转换 练习

    一:以下是用到的jar名称: commons-beanutils-1.6.jar commons-collections-3.2.1.jar commons-lang-2.6.jar commons- ...

  2. 转:Json序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍 ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介 ...

  3. Net中JSON序列化和反序列化处理(日期时间特殊处理)

    0  缘由 笔者最近在web api端使用Json.Net进行序列化处理,而在调用端使用DataContractSerializer进行反序列化,遇到日期时间处理反序列化不成功[备注:笔者使用Net ...

  4. json日期转换

    //调用 ChangeDateFormat(CreatTime) //json日期转换 function ChangeDateFormat(jsondate) { jsondate = jsondat ...

  5. Newtonsoft.Json日期转换

    在使用EasyUI做后台时,使用表格datagrid,用Newtonsoft.Json转换为Json格式后,时间显示为2013-06-15 T00:00:00形式. 后来研究了一下Newtonsoft ...

  6. Json序列化与反序列化(对象与Json字符串的转换)--C#

    public class JsonHelper { #region Json序列化与反序列化 /// <summary> /// 将json转化为对象 /// (需要提前构造好结构一致的M ...

  7. 05-06 Flutter JSON和序列化反序列化、创建模型类转换Json数据、轮播图数据渲染:Flutter创建商品数据模型 、请求Api接口渲染热门商品 推荐商品

    Config.dart class Config{ static String domain='http://jd.itying.com/'; } FocusModel.dart class Focu ...

  8. 使用JsonConfig控制JSON lib序列化

    将对象转换成字符串,是非常常用的功能,尤其在WEB应用中,使用 JSON lib 能够便捷地完成这项工作.JSON lib能够将Java对象转成json格式的字符串,也可以将Java对象转换成xml格 ...

  9. Newtonsoft.Json高级用法,json序列号,model反序列化,支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity,字符串

    原文地址:https://www.cnblogs.com/yanweidie/p/4605212.html 手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口 ...

随机推荐

  1. 面向对象相关概念与在python中的面向对象知识(魔法方法+反射+元类+鸭子类型)

    面向对象知识 封装 封装的原理是,其成员变量代表对象的属性,方法代表这个对象的动作真正的封装是,经过深入的思考,做出良好的抽象(设计属性时用到),给出“完整且最小”的接口,并使得内部细节可以对外透明( ...

  2. TCP保活定时器

    TCP有Keepalive功能,它和HTTP的Keepalive功能目的不一样.TCP服务器希望知道客户端是否崩溃.重新启动或者中间路由不通.保活定时器就提供这种功能. 在进一步介绍TCP的保活定时器 ...

  3. 微信小程序开发(一)创建一个小程序Hello World!

    开发微信小程序并不是很难,网上有很多小程序开发资料,尤其是微信官方的<小程序开发指南>最详细. 下面是我开发小程序的历程: 第一步,请前往https://mp.weixin.qq.com/ ...

  4. 6.高性能NIO框架netty

    1.Netty简介: Netty是基于Java NIO的网络应用框架 Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议 ...

  5. nagios-调用脚本

    在自已编写监控插件之前我们首先需要对nagios监控原理有一定的了解 Nagios的功能是监控服务和主机,但是他自身并不包括这部分功能,所有的监控.检测功能都是通过各种插件来完成的. 启动Nagios ...

  6. 8.Canny边缘检测

    #导入工具包 from imutils import * image = imread('image/school.jpg') show(image) def edge_detection(image ...

  7. 【SDOI2018】反回文串(【ARC064 F】Rotated Palindromes 加强版)

    题意 给你一个正整数 \(n\),求有多少字符集为 \(1\) 到 \(k\) 之间整数的字符串,使得该字符串可以由一个长度为 \(n\) 的回文串循环移位得到. ARC原题 \(100\%\) 的数 ...

  8. unittest 详解

      内容总括 一. 初始化 setUp 与 tearDown setUpClass 与 tearDownClass unittest.main(verbosity=0/1/2) 二. 执行顺序 按顺序 ...

  9. PAT乙级1013

    题目链接 https://pintia.cn/problem-sets/994805260223102976/problems/994805309963354112 题解一 从第一个素数开始找起,输出 ...

  10. DNS如何工作

    上一篇文章(什么是DNS)中,我们解释了 DNS 所涉及到的一些术语,接下来我们来看看 DNS 这个系统是如何工作的? 从高层次上看,这个系统非常简单,但是当你关注细节时,它又非常复杂.总的来说,它是 ...