View Javadoc

1   /*
2    * Copyright 2006-2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package net.sf.ezmorph.object;
18  
19  import java.text.ParseException;
20  import java.text.SimpleDateFormat;
21  import java.util.Date;
22  import java.util.Locale;
23  
24  import net.sf.ezmorph.MorphException;
25  
26  import org.apache.commons.lang.builder.EqualsBuilder;
27  import org.apache.commons.lang.builder.HashCodeBuilder;
28  
29  /**
30   * Morphs a String to a Date.<br>
31   * <p>
32   * This morpher will iterate through the supplied formats until one succeeds or
33   * the default value is returned (if default value is configured).
34   * </p>
35   *
36   * @author Andres Almiray <aalmiray@users.sourceforge.net>
37   */
38  public final class DateMorpher extends AbstractObjectMorpher
39  {
40     private Date defaultValue;
41     private String[] formats;
42     private boolean lenient;
43     private Locale locale;
44  
45     /**
46      * @param formats a list of formats this morpher supports.
47      */
48     public DateMorpher( String[] formats )
49     {
50        this( formats, Locale.getDefault(), false );
51     }
52  
53     /**
54      * @param formats a list of formats this morpher supports.
55      * @param lenient if the parsing should be lenient or not.
56      */
57     public DateMorpher( String[] formats, boolean lenient )
58     {
59        this( formats, Locale.getDefault(), lenient );
60     }
61  
62     /**
63      * @param formats a list of formats this morpher supports.
64      * @param defaultValue return value if the value to be morphed is null.
65      */
66     public DateMorpher( String[] formats, Date defaultValue )
67     {
68        this( formats, defaultValue, Locale.getDefault(), false );
69     }
70  
71     /**
72      * @param formats a list of formats this morpher supports.
73      * @param defaultValue return value if the value to be morphed is null.
74      * @param locale the Locale used to parse each format.
75      * @param lenient if the parsing should be lenient or not.
76      */
77     public DateMorpher( String[] formats, Date defaultValue, Locale locale, boolean lenient )
78     {
79        super( true );
80        if( formats == null || formats.length == 0 ){
81           throw new MorphException( "invalid array of formats" );
82        }
83        // should use defensive copying ?
84        this.formats = formats;
85  
86        if( locale == null ){
87           this.locale = Locale.getDefault();
88        }else{
89           this.locale = locale;
90        }
91  
92        this.lenient = lenient;
93        setDefaultValue( defaultValue );
94     }
95  
96     /**
97      * @param formats a list of formats this morpher supports.
98      * @param locale the Locale used to parse each format.
99      */
100    public DateMorpher( String[] formats, Locale locale )
101    {
102       this( formats, locale, false );
103    }
104 
105    /**
106     * @param formats a list of formats this morpher supports.
107     * @param locale the Locale used to parse each format.
108     * @param lenient if the parsing should be lenient or not.
109     */
110    public DateMorpher( String[] formats, Locale locale, boolean lenient )
111    {
112       if( formats == null || formats.length == 0 ){
113          throw new MorphException( "invalid array of formats" );
114       }
115       // should use defensive copying ?
116       this.formats = formats;
117 
118       if( locale == null ){
119          this.locale = Locale.getDefault();
120       }else{
121          this.locale = locale;
122       }
123 
124       this.lenient = lenient;
125    }
126 
127    public boolean equals( Object obj )
128    {
129       if( this == obj ){
130          return true;
131       }
132       if( obj == null ){
133          return false;
134       }
135 
136       if( !(obj instanceof DateMorpher) ){
137          return false;
138       }
139 
140       DateMorpher other = (DateMorpher) obj;
141       EqualsBuilder builder = new EqualsBuilder();
142       builder.append( formats, other.formats );
143       builder.append( locale, other.locale );
144       builder.append( lenient, other.lenient );
145       if( isUseDefault() && other.isUseDefault() ){
146          builder.append( getDefaultValue(), other.getDefaultValue() );
147          return builder.isEquals();
148       }else if( !isUseDefault() && !other.isUseDefault() ){
149          return builder.isEquals();
150       }else{
151          return false;
152       }
153    }
154 
155    /**
156     * Returns the default value for this Morpher.
157     */
158    public Date getDefaultValue()
159    {
160       return (Date) defaultValue.clone();
161    }
162 
163    public int hashCode()
164    {
165       HashCodeBuilder builder = new HashCodeBuilder();
166       builder.append( formats );
167       builder.append( locale );
168       builder.append( lenient );
169       if( isUseDefault() ){
170          builder.append( getDefaultValue() );
171       }
172       return builder.toHashCode();
173    }
174 
175    public Object morph( Object value )
176    {
177       if( value == null ){
178          return null;
179       }
180 
181       if( Date.class.isAssignableFrom( value.getClass() ) ){
182          return (Date) value;
183       }
184 
185       if( !supports( value.getClass() ) ){
186          throw new MorphException( value.getClass() + " is not supported" );
187       }
188 
189       String strValue = (String) value;
190       SimpleDateFormat dateParser = null;
191 
192       for( int i = 0; i < formats.length; i++ ){
193          if( dateParser == null ){
194             dateParser = new SimpleDateFormat( formats[i], locale );
195          }else{
196             dateParser.applyPattern( formats[i] );
197          }
198          dateParser.setLenient( lenient );
199          try{
200             return dateParser.parse( strValue.toLowerCase() );
201          }
202          catch( ParseException pe ){
203             // ignore exception, try the next format
204          }
205       }
206 
207       // unable to parse the date
208       if( isUseDefault() ){
209          return defaultValue;
210       }else{
211          throw new MorphException( "Unable to parse the date " + value );
212       }
213    }
214 
215    public Class morphsTo()
216    {
217       return Date.class;
218    }
219 
220    /**
221     * Sets the defaultValue to use if the value to be morphed is null.
222     *
223     * @param defaultValue return value if the value to be morphed is null
224     */
225    public void setDefaultValue( Date defaultValue )
226    {
227       this.defaultValue = (Date) defaultValue.clone();
228    }
229 
230    public boolean supports( Class clazz )
231    {
232       return String.class.isAssignableFrom( clazz );
233    }
234 }