南小爵

站在巨人肩膀上看风景。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

需求:

在我们的项目里希望JsonString传入日期类型值为空时,JSONObject.toBean时可以将Java对象的该日期属性设为null。

解决过程:

json-lib反序列化Json字符串为Java对象,可以通过以下代码处理日期字段:

1 public static <T> T JsonToBean(Class<T> clazz, String JsonString) {
2         JSONUtils.getMorpherRegistry().registerMorpher(
3                 new DateMorpher(new String[] { "yyyy-MM-dd HH:mm:ss",
4                         "yyyy-MM-dd", "yyyy-MM-dd't'HH:mm:ss" }));
5         JSONObject jsonObject = JSONObject.fromObject(JsonString);
6         T entity = (T) JSONObject.toBean(jsonObject, clazz);
7         return entity;
8     }
View Code

但如果JsonString传入{"createDate":""}时,则会在“T entity = (T) JSONObject.toBean(jsonObject, clazz)”时报以下错误:

net.sf.json.JSONException: Error while setting property=createDate type class java.lang.String

 

查看net.sf.ezmorph.object.DateMorpher方法的源码,关于字符串转时间的代码如下:

 1       public Object morph(Object value)
 2        {
 3          if (value == null) {
 4            return null;
 5          }
 6  
 7          if (Date.class.isAssignableFrom(value.getClass())) {
 8            return (Date)value;
 9          }
10  
11          if (!supports(value.getClass())) {
12            throw new MorphException(value.getClass() + " is not supported");
13          }
14  
15          String strValue = (String)value;
16          SimpleDateFormat dateParser = null;
17  
18          for (int i = 0; i < this.formats.length; ++i) {
19            if (dateParser == null)
20              dateParser = new SimpleDateFormat(this.formats[i], this.locale);
21            else {
22              dateParser.applyPattern(this.formats[i]);
23            }
24            dateParser.setLenient(this.lenient);
25            try {
26              return dateParser.parse(strValue.toLowerCase());
27            }
28            catch (ParseException localParseException)
29            {
30            }
31          }
32  
33          if (super.isUseDefault()) {
34            return this.defaultValue;
35          }
36          throw new MorphException("Unable to parse the date " + value);
37        }
View Code

 

可以看到,在18~32行会使用我们传入的formats循环进行字符串转换,如果转换成功则返回Date,如果全部失败则在37行处抛出异常,最后导致toBean方法失败。

可以看到DateMorpher类有这个构造函数可以传入Date defaultValue,在morph方法的第34行如果之前的转换均失败即返回defaultValue。但使用(Date)null作为defaultValue,在初始化DateMorpher对象时会报空指针异常,原因是DateMorpher类中有如下方法:

1   public void setDefaultValue(Date defaultValue)
2       {
3           this.defaultValue = ((Date)defaultValue.clone());
4       }
5 
6       public Date getDefaultValue()
7       {
8           return (Date)this.defaultValue.clone();
9       }
View Code

“this.defaultValue.clone();”中defaultValue 为null所以报异常。

解决方法:

重新实现DateMorpher方法,修改setDefaultValue(Date defaultValue)和getDefaultValue()方法,对null进行处理

(当然也可是修改net.sf.ezmorph.object.DateMorpher方法,重新打包ezmorph-1.0.6.jar)。

以下是重新实现的DateMorpherEx方法:

  1 import net.sf.ezmorph.object.AbstractObjectMorpher;
  2 import java.text.DateFormat;
  3 import java.text.ParseException;
  4 import java.text.SimpleDateFormat;
  5 import java.util.Date;
  6 import java.util.Locale;
  7 import net.sf.ezmorph.MorphException;
  8 import org.apache.commons.lang.builder.EqualsBuilder;
  9 import org.apache.commons.lang.builder.HashCodeBuilder;
 10 
 11 public class DateMorpherEx extends AbstractObjectMorpher {
 12 
 13     private Date defaultValue;
 14       private String[] formats;
 15       private boolean lenient;
 16       private Locale locale;
 17 
 18       public DateMorpherEx(String[] formats)
 19       {
 20         this(formats, Locale.getDefault(), false);
 21       }
 22 
 23       public DateMorpherEx(String[] formats, boolean lenient)
 24       {
 25         this(formats, Locale.getDefault(), lenient);
 26       }
 27 
 28       public DateMorpherEx(String[] formats, Date defaultValue)
 29       {
 30         this(formats, defaultValue, Locale.getDefault(), false);
 31       }
 32 
 33       public DateMorpherEx(String[] formats, Date defaultValue, Locale locale, boolean lenient)
 34       {
 35         super(true);
 36         if ((formats == null) || (formats.length == 0)) {
 37           throw new MorphException("invalid array of formats");
 38         }
 39 
 40         this.formats = formats;
 41 
 42         if (locale == null)
 43           this.locale = Locale.getDefault();
 44         else {
 45           this.locale = locale;
 46         }
 47 
 48         this.lenient = lenient;
 49         setDefaultValue(defaultValue);
 50       }
 51 
 52       public DateMorpherEx(String[] formats, Locale locale)
 53       {
 54         this(formats, locale, false);
 55       }
 56 
 57       public DateMorpherEx(String[] formats, Locale locale, boolean lenient)
 58       {
 59         if ((formats == null) || (formats.length == 0)) {
 60           throw new MorphException("invalid array of formats");
 61         }
 62 
 63         this.formats = formats;
 64 
 65         if (locale == null)
 66           this.locale = Locale.getDefault();
 67         else {
 68           this.locale = locale;
 69         }
 70 
 71         this.lenient = lenient;
 72       }
 73 
 74       public boolean equals(Object obj)
 75       {
 76         if (this == obj) {
 77           return true;
 78         }
 79         if (obj == null) {
 80           return false;
 81         }
 82 
 83         if (!(obj instanceof DateMorpherEx)) {
 84           return false;
 85         }
 86 
 87         DateMorpherEx other = (DateMorpherEx)obj;
 88         EqualsBuilder builder = new EqualsBuilder();
 89         builder.append(this.formats, other.formats);
 90         builder.append(this.locale, other.locale);
 91         builder.append(this.lenient, other.lenient);
 92         if ((super.isUseDefault()) && (other.isUseDefault())) {
 93           builder.append(getDefaultValue(), other.getDefaultValue());
 94           return builder.isEquals();
 95         }if ((!super.isUseDefault()) && (!other.isUseDefault())) {
 96           return builder.isEquals();
 97         }
 98         return false;
 99       }
100 
101       public Date getDefaultValue()
102       {
103           if(this.defaultValue!=null)
104               return (Date)this.defaultValue.clone();
105           else
106               return this.defaultValue;
107       }
108 
109       public int hashCode()
110       {
111         HashCodeBuilder builder = new HashCodeBuilder();
112         builder.append(this.formats);
113         builder.append(this.locale);
114         builder.append(this.lenient);
115         if (super.isUseDefault()) {
116           builder.append(getDefaultValue());
117         }
118         return builder.toHashCode();
119       }
120 
121       public Object morph(Object value)
122       {
123         if (value == null) {
124           return null;
125         }
126 
127         if (Date.class.isAssignableFrom(value.getClass())) {
128           return (Date)value;
129         }
130 
131         if (!supports(value.getClass())) {
132           throw new MorphException(value.getClass() + " is not supported");
133         }
134 
135         String strValue = (String)value;
136         SimpleDateFormat dateParser = null;
137 
138         for (int i = 0; i < this.formats.length; ++i) {
139           if (dateParser == null)
140             dateParser = new SimpleDateFormat(this.formats[i], this.locale);
141           else {
142             dateParser.applyPattern(this.formats[i]);
143           }
144           dateParser.setLenient(this.lenient);
145           try {
146             return dateParser.parse(strValue.toLowerCase());
147           }
148           catch (ParseException localParseException)
149           {
150           }
151 
152         }
153 
154         if (super.isUseDefault()) {
155           return this.defaultValue;
156         }
157         throw new MorphException("Unable to parse the date " + value);
158       }
159 
160       public Class morphsTo()
161       {
162         return Date.class;
163       }
164 
165       public void setDefaultValue(Date defaultValue)
166       {
167           if(defaultValue!=null)
168               this.defaultValue = ((Date)defaultValue.clone());
169           else
170               this.defaultValue = null;
171       }
172 
173       public boolean supports(Class clazz)
174       {
175         return String.class.isAssignableFrom(clazz);
176       }
177 }
View Code

修改原 JsonToBean 方法,调用DateMorpherEx:

1 public static <T> T JsonToBean(Class<T> clazz, String JsonString) {
2         JSONUtils.getMorpherRegistry().registerMorpher(
3                 new DateMorpherEx(new String[] { "yyyy-MM-dd HH:mm:ss",
4                         "yyyy-MM-dd", "yyyy-MM-dd't'HH:mm:ss" }, (Date) null));//调用DateMorpherEx,defaultValue为null
5         JSONObject jsonObject = JSONObject.fromObject(JsonString);
6         T entity = (T) JSONObject.toBean(jsonObject, clazz);
7         return entity;
8     }
View Code