json-lib json反序列化——日期转换
将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代码是:
1 public class MorphUtils { 2 public static final BigDecimal BIGDECIMAL_ONE = new BigDecimal("1"); 3 public static final BigDecimal BIGDECIMAL_ZERO = new BigDecimal("0"); 4 5 public static void registerStandardMorphers(MorpherRegistry morpherRegistry) { 6 morpherRegistry.clear(); 7 registerStandardPrimitiveMorphers(morpherRegistry); 8 registerStandardPrimitiveArrayMorphers(morpherRegistry); 9 registerStandardObjectMorphers(morpherRegistry); 10 registerStandardObjectArrayMorphers(morpherRegistry); 11 } 12 13 public static void registerStandardObjectArrayMorphers(MorpherRegistry morpherRegistry) { 14 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new BooleanObjectMorpher(Boolean.FALSE))); 15 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new CharacterObjectMorpher(new Character('\u0000')))); 16 morpherRegistry.registerMorpher(new ObjectArrayMorpher(StringMorpher.getInstance())); 17 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Byte.class, new Byte((byte)0)))); 18 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Short.class, new Short((short)0)))); 19 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Integer.class, new Integer(0)))); 20 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Long.class, new Long(0L)))); 21 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Float.class, new Float(0.0F)))); 22 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(Double.class, new Double(0.0D)))); 23 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(BigInteger.class, BigInteger.ZERO))); 24 morpherRegistry.registerMorpher(new ObjectArrayMorpher(new NumberMorpher(BigDecimal.class, BIGDECIMAL_ZERO))); 25 morpherRegistry.registerMorpher(new ObjectArrayMorpher(ClassMorpher.getInstance())); 26 } 27 28 public static void registerStandardObjectMorphers(MorpherRegistry morpherRegistry) { 29 morpherRegistry.registerMorpher(new BooleanObjectMorpher(Boolean.FALSE)); 30 morpherRegistry.registerMorpher(new CharacterObjectMorpher(new Character('\u0000'))); 31 morpherRegistry.registerMorpher(StringMorpher.getInstance()); 32 morpherRegistry.registerMorpher(new NumberMorpher(Byte.class, new Byte((byte)0))); 33 morpherRegistry.registerMorpher(new NumberMorpher(Short.class, new Short((short)0))); 34 morpherRegistry.registerMorpher(new NumberMorpher(Integer.class, new Integer(0))); 35 morpherRegistry.registerMorpher(new NumberMorpher(Long.class, new Long(0L))); 36 morpherRegistry.registerMorpher(new NumberMorpher(Float.class, new Float(0.0F))); 37 morpherRegistry.registerMorpher(new NumberMorpher(Double.class, new Double(0.0D))); 38 morpherRegistry.registerMorpher(new NumberMorpher(BigInteger.class, BigInteger.ZERO)); 39 morpherRegistry.registerMorpher(new NumberMorpher(BigDecimal.class, BIGDECIMAL_ZERO)); 40 morpherRegistry.registerMorpher(ClassMorpher.getInstance()); 41 } 42 43 public static void registerStandardPrimitiveArrayMorphers(MorpherRegistry morpherRegistry) { 44 morpherRegistry.registerMorpher(new BooleanArrayMorpher(false)); 45 morpherRegistry.registerMorpher(new CharArrayMorpher('\u0000')); 46 morpherRegistry.registerMorpher(new ByteArrayMorpher((byte)0)); 47 morpherRegistry.registerMorpher(new ShortArrayMorpher((short)0)); 48 morpherRegistry.registerMorpher(new IntArrayMorpher(0)); 49 morpherRegistry.registerMorpher(new LongArrayMorpher(0L)); 50 morpherRegistry.registerMorpher(new FloatArrayMorpher(0.0F)); 51 morpherRegistry.registerMorpher(new DoubleArrayMorpher(0.0D)); 52 } 53 54 public static void registerStandardPrimitiveMorphers(MorpherRegistry morpherRegistry) { 55 morpherRegistry.registerMorpher(new BooleanMorpher(false)); 56 morpherRegistry.registerMorpher(new CharMorpher('\u0000')); 57 morpherRegistry.registerMorpher(new ByteMorpher((byte)0)); 58 morpherRegistry.registerMorpher(new ShortMorpher((short)0)); 59 morpherRegistry.registerMorpher(new IntMorpher(0)); 60 morpherRegistry.registerMorpher(new LongMorpher(0L)); 61 morpherRegistry.registerMorpher(new FloatMorpher(0.0F)); 62 morpherRegistry.registerMorpher(new DoubleMorpher(0.0D)); 63 } 64 65 private MorphUtils() { 66 } 67 }
因此,在JSONUtils初始化的时候,就将默认类型放在了MorpherRegistry的morphs中。从上面的代码可以看出来,Date不属于默认的类型。因此,这里可以看出来,在做json反序列化时,如果有需要转成Date类型的String,就需要自己手动注册一个DateMorpher。
怎么加是一个问题了。其实在文章最前面提到的网上的解决方案也并没有错,看下源码就知道了,为啥这个方法却在我使用的时候不起作用了。
在MorpherRegistry.java中Morpher注册源码:
1 public class MorpherRegistry implements Serializable { 2 private static final long serialVersionUID = -3894767123320768419L; 3 private Map morphers = new HashMap(); 4 5 public MorpherRegistry() { 6 } 7 8 public synchronized Morpher[] getMorphersFor(Class clazz) { 9 List registered = (List)this.morphers.get(clazz); 10 if(registered != null && !registered.isEmpty()) { 11 Morpher[] morphs = new Morpher[registered.size()]; 12 int k = 0; 13 14 for(Iterator i = registered.iterator(); i.hasNext(); morphs[k++] = (Morpher)i.next()) { 15 ; 16 } 17 18 return morphs; 19 } else { 20 return new Morpher[]{IdentityObjectMorpher.getInstance()}; 21 } 22 } 23 24 public Object morph(Class target, Object value) { 25 if(value == null) { 26 Morpher var9 = this.getMorpherFor(target); 27 if(var9 instanceof ObjectMorpher) { 28 return ((ObjectMorpher)var9).morph(value); 29 } else { 30 try { 31 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}); 32 return var10.invoke(var9, new Object[]{value}); 33 } catch (Exception var7) { 34 throw new MorphException(var7); 35 } 36 } 37 } else { 38 Morpher[] morphers = this.getMorphersFor(target); 39 40 for(int i = 0; i < morphers.length; ++i) { 41 Morpher morpher = morphers[i]; 42 if(morpher.supports(value.getClass())) { 43 if(morpher instanceof ObjectMorpher) { 44 return ((ObjectMorpher)morpher).morph(value); 45 } 46 47 try { 48 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}); 49 return e.invoke(morpher, new Object[]{value}); 50 } catch (Exception var8) { 51 throw new MorphException(var8); 52 } 53 } 54 } 55 56 return value; 57 } 58 } 59 60 public synchronized void registerMorpher(Morpher morpher, boolean override) { 61 Object registered = (List)this.morphers.get(morpher.morphsTo()); 62 if(override || registered == null) { 63 registered = new ArrayList(); 64 this.morphers.put(morpher.morphsTo(), registered); 65 } 66 67 if(!((List)registered).contains(morpher)) { 68 ((List)registered).add(morpher); 69 } 70 71 } 72 }
在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()方法中
1 public Object morph(Object sourceBean) { 2 if(sourceBean == null) { 3 return null; 4 } else if(!this.supports(sourceBean.getClass())) { 5 throw new MorphException("unsupported class: " + sourceBean.getClass().getName()); 6 } else { 7 Object targetBean = null; 8 9 try { 10 targetBean = this.beanClass.newInstance(); 11 PropertyDescriptor[] e = PropertyUtils.getPropertyDescriptors(this.beanClass); 12 13 for(int i = 0; i < e.length; ++i) { 14 PropertyDescriptor targetPd = e[i]; 15 String name = targetPd.getName(); 16 if(targetPd.getWriteMethod() == null) { 17 log.info("Property \'" + this.beanClass.getName() + "." + name + "\' has no write method. SKIPPED."); 18 } else { 19 Class sourceType = null; 20 if(sourceBean instanceof DynaBean) { 21 DynaBean targetType = (DynaBean)sourceBean; 22 DynaProperty value = targetType.getDynaClass().getDynaProperty(name); 23 if(value == null) { 24 log.warn("DynaProperty \'" + name + "\' does not exist. SKIPPED."); 25 continue; 26 } 27 28 sourceType = value.getType(); 29 } else { 30 PropertyDescriptor var12 = PropertyUtils.getPropertyDescriptor(sourceBean, name); 31 if(var12 == null) { 32 log.warn("Property \'" + sourceBean.getClass().getName() + "." + name + "\' does not exist. SKIPPED."); 33 continue; 34 } 35 36 if(var12.getReadMethod() == null) { 37 log.warn("Property \'" + sourceBean.getClass().getName() + "." + name + "\' has no read method. SKIPPED."); 38 continue; 39 } 40 41 sourceType = var12.getPropertyType(); 42 } 43 44 Class var13 = targetPd.getPropertyType(); 45 Object var14 = PropertyUtils.getProperty(sourceBean, name); 46 this.setProperty(targetBean, name, sourceType, var13, var14); 47 } 48 } 49 50 return targetBean; 51 } catch (MorphException var10) { 52 throw var10; 53 } catch (Exception var11) { 54 throw new MorphException(var11); 55 } 56 } 57 }
sourceBean不属于DynaBean,且var12的值也为null,因此返回的值就是targetBean,时间的一个实例,即当前时间。