將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,時間的一個實例,即當前時間。