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.math.BigDecimal;
20  import java.math.BigInteger;
21  
22  import net.sf.ezmorph.MorphException;
23  import net.sf.ezmorph.primitive.ByteMorpher;
24  import net.sf.ezmorph.primitive.DoubleMorpher;
25  import net.sf.ezmorph.primitive.FloatMorpher;
26  import net.sf.ezmorph.primitive.IntMorpher;
27  import net.sf.ezmorph.primitive.LongMorpher;
28  import net.sf.ezmorph.primitive.ShortMorpher;
29  
30  import org.apache.commons.lang.builder.EqualsBuilder;
31  import org.apache.commons.lang.builder.HashCodeBuilder;
32  
33  /**
34   * Morphs to a subclass of Number.<br>
35   * Supported types are - Byte, Short, Integer, Long, Float, BigInteger,
36   * BigtDecimal.
37   *
38   * @author Andres Almiray <aalmiray@users.sourceforge.net>
39   */
40  public final class NumberMorpher extends AbstractObjectMorpher
41  {
42     private Number defaultValue;
43     private Class type;
44  
45     /**
46      * Creates a new morpher for the target type.
47      *
48      * @param type must be a primitive or wrapper type. BigDecimal and BigInteger
49      *        are also supported.
50      */
51     public NumberMorpher( Class type )
52     {
53        super( false );
54  
55        if( type == null ){
56           throw new MorphException( "Must specify a type" );
57        }
58  
59        if( type != Byte.TYPE && type != Short.TYPE && type != Integer.TYPE && type != Long.TYPE
60              && type != Float.TYPE && type != Double.TYPE && !Byte.class.isAssignableFrom( type )
61              && !Short.class.isAssignableFrom( type ) && !Integer.class.isAssignableFrom( type )
62              && !Long.class.isAssignableFrom( type ) && !Float.class.isAssignableFrom( type )
63              && !Double.class.isAssignableFrom( type ) && !BigInteger.class.isAssignableFrom( type )
64              && !BigDecimal.class.isAssignableFrom( type ) ){
65           throw new MorphException( "Must specify a Number subclass" );
66        }
67  
68        this.type = type;
69     }
70  
71     /**
72      * Creates a new morpher for the target type with a default value.<br>
73      * The defaultValue should be of the same class as the target type.
74      *
75      * @param type must be a primitive or wrapper type. BigDecimal and BigInteger
76      *        are also supported.
77      * @param defaultValue return value if the value to be morphed is null
78      */
79     public NumberMorpher( Class type, Number defaultValue )
80     {
81        super( true );
82  
83        if( type == null ){
84           throw new MorphException( "Must specify a type" );
85        }
86  
87        if( type != Byte.TYPE && type != Short.TYPE && type != Integer.TYPE && type != Long.TYPE
88              && type != Float.TYPE && type != Double.TYPE && !Byte.class.isAssignableFrom( type )
89              && !Short.class.isAssignableFrom( type ) && !Integer.class.isAssignableFrom( type )
90              && !Long.class.isAssignableFrom( type ) && !Float.class.isAssignableFrom( type )
91              && !Double.class.isAssignableFrom( type ) && !BigInteger.class.isAssignableFrom( type )
92              && !BigDecimal.class.isAssignableFrom( type ) ){
93           throw new MorphException( "Must specify a Number subclass" );
94        }
95  
96        if( defaultValue != null && !type.isInstance( defaultValue ) ){
97           throw new MorphException( "Default value must be of type " + type );
98        }
99  
100       this.type = type;
101       setDefaultValue( defaultValue );
102    }
103 
104    public boolean equals( Object obj )
105    {
106       if( this == obj ){
107          return true;
108       }
109       if( obj == null ){
110          return false;
111       }
112 
113       if( !(obj instanceof NumberMorpher) ){
114          return false;
115       }
116 
117       NumberMorpher other = (NumberMorpher) obj;
118       EqualsBuilder builder = new EqualsBuilder();
119       builder.append( type, other.type );
120       if( isUseDefault() && other.isUseDefault() ){
121          builder.append( getDefaultValue(), other.getDefaultValue() );
122          return builder.isEquals();
123       }else if( !isUseDefault() && !other.isUseDefault() ){
124          return builder.isEquals();
125       }else{
126          return false;
127       }
128    }
129 
130    /**
131     * Returns the default value for this Morpher.
132     */
133    public Number getDefaultValue()
134    {
135       return defaultValue;
136    }
137 
138    public int hashCode()
139    {
140       HashCodeBuilder builder = new HashCodeBuilder();
141       builder.append( type );
142       if( isUseDefault() ){
143          builder.append( getDefaultValue() );
144       }
145       return builder.toHashCode();
146    }
147 
148    public Object morph( Object value )
149    {
150       if( value != null && type.isAssignableFrom( value.getClass() ) ){
151          // no conversion needed
152          return value;
153       }
154 
155       String str = String.valueOf( value )
156             .trim();
157 
158       if( !type.isPrimitive()
159             && (value == null || str.length() == 0 || "null".equalsIgnoreCase( str )) ){
160          // if empty string and class != primitive treat it like null
161          return null;
162       }
163 
164       if( isDecimalNumber( type ) ){
165          if( Float.class.isAssignableFrom( type ) || Float.TYPE == type ){
166             return morphToFloat( str );
167          }else if( Double.class.isAssignableFrom( type ) || Double.TYPE == type ){
168             return morphToDouble( str );
169          }else{
170             return morphToBigDecimal( str );
171          }
172       }else{
173          if( Byte.class.isAssignableFrom( type ) || Byte.TYPE == type ){
174             return morphToByte( str );
175          }else if( Short.class.isAssignableFrom( type ) || Short.TYPE == type ){
176             return morphToShort( str );
177          }else if( Integer.class.isAssignableFrom( type ) || Integer.TYPE == type ){
178             return morphToInteger( str );
179          }else if( Long.class.isAssignableFrom( type ) || Long.TYPE == type ){
180             return morphToLong( str );
181          }else{
182             return morphToBigInteger( str );
183          }
184       }
185    }
186 
187    public Class morphsTo()
188    {
189       return type;
190    }
191 
192    /**
193     * Sets the defaultValue to use if the value to be morphed is null.<br>
194     * The defaultValue should be of the same class as the type this morpher
195     * returns with <code>morphsTo()</code>.
196     *
197     * @param defaultValue return value if the value to be morphed is null
198     */
199    public void setDefaultValue( Number defaultValue )
200    {
201       if( defaultValue != null && !type.isInstance( defaultValue ) ){
202          throw new MorphException( "Default value must be of type " + type );
203       }
204       this.defaultValue = defaultValue;
205    }
206 
207    private boolean isDecimalNumber( Class type )
208    {
209       return (Double.class.isAssignableFrom( type ) || Float.class.isAssignableFrom( type )
210             || Double.TYPE == type || Float.TYPE == type || BigDecimal.class.isAssignableFrom( type ));
211    }
212 
213    private Object morphToBigDecimal( String str )
214    {
215       Object result = null;
216       if( isUseDefault() ){
217          result = new BigDecimalMorpher( (BigDecimal) defaultValue ).morph( str );
218       }else{
219          result = new BigDecimal( str );
220       }
221       return result;
222    }
223 
224    private Object morphToBigInteger( String str )
225    {
226       Object result = null;
227       if( isUseDefault() ){
228          result = new BigIntegerMorpher( (BigInteger) defaultValue ).morph( str );
229       }else{
230          result = new BigInteger( str );
231       }
232       return result;
233    }
234 
235    private Object morphToByte( String str )
236    {
237       Object result = null;
238       if( isUseDefault() ){
239          if( defaultValue == null ){
240             return (Byte) null;
241          }else{
242             result = new Byte( new ByteMorpher( defaultValue.byteValue() ).morph( str ) );
243          }
244       }else{
245          result = new Byte( new ByteMorpher().morph( str ) );
246       }
247       return result;
248    }
249 
250    private Object morphToDouble( String str )
251    {
252       Object result = null;
253       if( isUseDefault() ){
254          if( defaultValue == null ){
255             return (Double) null;
256          }else{
257             result = new Double( new DoubleMorpher( defaultValue.doubleValue() ).morph( str ) );
258          }
259       }else{
260          result = new Double( new DoubleMorpher().morph( str ) );
261       }
262       return result;
263    }
264 
265    private Object morphToFloat( String str )
266    {
267       Object result = null;
268       if( isUseDefault() ){
269          if( defaultValue == null ){
270             return (Float) null;
271          }else{
272             result = new Float( new FloatMorpher( defaultValue.floatValue() ).morph( str ) );
273          }
274       }else{
275          result = new Float( new FloatMorpher().morph( str ) );
276       }
277       return result;
278    }
279 
280    private Object morphToInteger( String str )
281    {
282       Object result = null;
283       if( isUseDefault() ){
284          if( defaultValue == null ){
285             return (Integer) null;
286          }else{
287             result = new Integer( new IntMorpher( defaultValue.intValue() ).morph( str ) );
288          }
289       }else{
290          result = new Integer( new IntMorpher().morph( str ) );
291       }
292       return result;
293    }
294 
295    private Object morphToLong( String str )
296    {
297       Object result = null;
298       if( isUseDefault() ){
299          if( defaultValue == null ){
300             return (Long) null;
301          }else{
302             result = new Long( new LongMorpher( defaultValue.longValue() ).morph( str ) );
303          }
304       }else{
305          result = new Long( new LongMorpher().morph( str ) );
306       }
307       return result;
308    }
309 
310    private Object morphToShort( String str )
311    {
312       Object result = null;
313       if( isUseDefault() ){
314          if( defaultValue == null ){
315             return (Short) null;
316          }else{
317             result = new Short( new ShortMorpher( defaultValue.shortValue() ).morph( str ) );
318          }
319       }else{
320          result = new Short( new ShortMorpher().morph( str ) );
321       }
322       return result;
323    }
324 }