将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. 如何判断kbmMWClientQuery当前记录的增改状态?

    有朋友问我,客户端使用了kbmMWClientQuery,对其进行了编辑后,对于指定的记录,如何判断是否是增加的记录,或者是被修改后的记录? 下面这个函数,返回aDataSet当前记录的修改状态: f ...

  2. WLW模板插件Text Templat的应用举例

    WLW的模板插件:WLWTextTemplates 安装之后,如下图所示: 点击这个按键之后,出现下图: 按上图提示点击"Add new Template",出现下图:   举个例 ...

  3. mybatis框架中 动态代理的问题

    在配置文件时候 id唯一性 所以不允许重载 <select id=" querydemo"   resultType="pojo"> sql 语句  ...

  4. 使用metamask钱包

    一.安装火狐浏览器metamask插件 打开火狐浏览器的附件组件,搜索metamask 点击第一个 点击“添加到Firefox” 添加成功后,浏览器右上角有一个狐狸标志 点击这个标志,打开插件 二.创 ...

  5. 1.opencv_画图

    #导入工具包 import numpy as np import cv2 import matplotlib.pyplot as plt # 定义显示图片 def show(image): plt.i ...

  6. 解决mysql提示服务无法启动问题

    1.管理员权限打开命令,进入mysql下bin文件夹 删除根目录下data文件夹没有不用管,重新安装 2. ---------------------------------------------- ...

  7. 解决使用vue打包时vendor文件过大或者是app.js文件很大的问题

    这篇文章主要介绍了使用vue打包时vendor文件过大或者是app.js文件很大问题的解决方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下 第一次使用vue2.0开发,之前都是用的angu ...

  8. VUE: 移动端长按弹出确认删除地址(2)

    之前有一篇文章也写了长按弹出确认框的功能,在android机上测试过完全没问题,到后面整体测试时发现IOS这个功能长按移除就消失了, 除非长按不松手,用另外一只手点击确定才能完成操作,所以这次做了修改 ...

  9. C/C++ - malloc/free和new/delete的区分

    new/delete与malloc/free的区别主要表现在以下几个方面: 注意:最主要的区别,new/delete是运算符,而malloc/free是函数 (1).new能够自动计算需要分配的内存空 ...

  10. K8S中的Job和CronJob

    Job Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束. Kubernetes支持以下几种J ...