Coverage Report - net.sf.ezmorph.object.NumberMorpher
 
Classes in this File Line Coverage Branch Coverage Complexity
NumberMorpher
98%
126/129
86%
255/296
4.588
 
 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  724
       super( false );
 54  
 
 55  724
       if( type == null ){
 56  4
          throw new MorphException( "Must specify a type" );
 57  
       }
 58  
 
 59  720
       if( type != Byte.TYPE && type != Short.TYPE && type != Integer.TYPE && type != Long.TYPE
 60  536
             && type != Float.TYPE && type != Double.TYPE && !Byte.class.isAssignableFrom( type )
 61  513
             && !Short.class.isAssignableFrom( type ) && !Integer.class.isAssignableFrom( type )
 62  57
             && !Long.class.isAssignableFrom( type ) && !Float.class.isAssignableFrom( type )
 63  33
             && !Double.class.isAssignableFrom( type ) && !BigInteger.class.isAssignableFrom( type )
 64  12
             && !BigDecimal.class.isAssignableFrom( type ) ){
 65  4
          throw new MorphException( "Must specify a Number subclass" );
 66  
       }
 67  
 
 68  716
       this.type = type;
 69  716
    }
 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  8960
       super( true );
 82  
 
 83  8960
       if( type == null ){
 84  4
          throw new MorphException( "Must specify a type" );
 85  
       }
 86  
 
 87  8956
       if( type != Byte.TYPE && type != Short.TYPE && type != Integer.TYPE && type != Long.TYPE
 88  6753
             && type != Float.TYPE && type != Double.TYPE && !Byte.class.isAssignableFrom( type )
 89  5961
             && !Short.class.isAssignableFrom( type ) && !Integer.class.isAssignableFrom( type )
 90  3948
             && !Long.class.isAssignableFrom( type ) && !Float.class.isAssignableFrom( type )
 91  2370
             && !Double.class.isAssignableFrom( type ) && !BigInteger.class.isAssignableFrom( type )
 92  792
             && !BigDecimal.class.isAssignableFrom( type ) ){
 93  4
          throw new MorphException( "Must specify a Number subclass" );
 94  
       }
 95  
 
 96  8952
       if( defaultValue != null && !type.isInstance( defaultValue ) ){
 97  4
          throw new MorphException( "Default value must be of type " + type );
 98  
       }
 99  
 
 100  8948
       this.type = type;
 101  8948
       setDefaultValue( defaultValue );
 102  8948
    }
 103  
 
 104  
    public boolean equals( Object obj )
 105  
    {
 106  40
       if( this == obj ){
 107  8
          return true;
 108  
       }
 109  32
       if( obj == null ){
 110  4
          return false;
 111  
       }
 112  
 
 113  28
       if( !(obj instanceof NumberMorpher) ){
 114  4
          return false;
 115  
       }
 116  
 
 117  24
       NumberMorpher other = (NumberMorpher) obj;
 118  24
       EqualsBuilder builder = new EqualsBuilder();
 119  24
       builder.append( type, other.type );
 120  24
       if( isUseDefault() && other.isUseDefault() ){
 121  8
          builder.append( getDefaultValue(), other.getDefaultValue() );
 122  8
          return builder.isEquals();
 123  16
       }else if( !isUseDefault() && !other.isUseDefault() ){
 124  8
          return builder.isEquals();
 125  
       }else{
 126  8
          return false;
 127  
       }
 128  
    }
 129  
 
 130  
    /**
 131  
     * Returns the default value for this Morpher.
 132  
     */
 133  
    public Number getDefaultValue()
 134  
    {
 135  40
       return defaultValue;
 136  
    }
 137  
 
 138  
    public int hashCode()
 139  
    {
 140  48
       HashCodeBuilder builder = new HashCodeBuilder();
 141  48
       builder.append( type );
 142  48
       if( isUseDefault() ){
 143  24
          builder.append( getDefaultValue() );
 144  
       }
 145  48
       return builder.toHashCode();
 146  
    }
 147  
 
 148  
    public Object morph( Object value )
 149  
    {
 150  1186
       if( value != null && type.isAssignableFrom( value.getClass() ) ){
 151  
          // no conversion needed
 152  68
          return value;
 153  
       }
 154  
 
 155  1958
       String str = String.valueOf( value )
 156  840
             .trim();
 157  
 
 158  1118
       if( !type.isPrimitive()
 159  822
             && (value == null || str.length() == 0 || "null".equalsIgnoreCase( str )) ){
 160  
          // if empty string and class != primitive treat it like null
 161  891
          return null;
 162  
       }
 163  
 
 164  227
       if( isDecimalNumber( type ) ){
 165  72
          if( Float.class.isAssignableFrom( type ) || Float.TYPE == type ){
 166  28
             return morphToFloat( str );
 167  44
          }else if( Double.class.isAssignableFrom( type ) || Double.TYPE == type ){
 168  28
             return morphToDouble( str );
 169  
          }else{
 170  16
             return morphToBigDecimal( str );
 171  
          }
 172  
       }else{
 173  155
          if( Byte.class.isAssignableFrom( type ) || Byte.TYPE == type ){
 174  28
             return morphToByte( str );
 175  127
          }else if( Short.class.isAssignableFrom( type ) || Short.TYPE == type ){
 176  28
             return morphToShort( str );
 177  99
          }else if( Integer.class.isAssignableFrom( type ) || Integer.TYPE == type ){
 178  55
             return morphToInteger( str );
 179  44
          }else if( Long.class.isAssignableFrom( type ) || Long.TYPE == type ){
 180  28
             return morphToLong( str );
 181  
          }else{
 182  16
             return morphToBigInteger( str );
 183  
          }
 184  
       }
 185  
    }
 186  
 
 187  
    public Class morphsTo()
 188  
    {
 189  20840
       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  8976
       if( defaultValue != null && !type.isInstance( defaultValue ) ){
 202  0
          throw new MorphException( "Default value must be of type " + type );
 203  
       }
 204  8976
       this.defaultValue = defaultValue;
 205  8976
    }
 206  
 
 207  
    private boolean isDecimalNumber( Class type )
 208  
    {
 209  281
       return (Double.class.isAssignableFrom( type ) || Float.class.isAssignableFrom( type )
 210  135
             || Double.TYPE == type || Float.TYPE == type || BigDecimal.class.isAssignableFrom( type ));
 211  
    }
 212  
 
 213  
    private Object morphToBigDecimal( String str )
 214  
    {
 215  16
       Object result = null;
 216  16
       if( isUseDefault() ){
 217  16
          result = new BigDecimalMorpher( (BigDecimal) defaultValue ).morph( str );
 218  
       }else{
 219  0
          result = new BigDecimal( str );
 220  
       }
 221  16
       return result;
 222  
    }
 223  
 
 224  
    private Object morphToBigInteger( String str )
 225  
    {
 226  16
       Object result = null;
 227  16
       if( isUseDefault() ){
 228  16
          result = new BigIntegerMorpher( (BigInteger) defaultValue ).morph( str );
 229  
       }else{
 230  0
          result = new BigInteger( str );
 231  
       }
 232  16
       return result;
 233  
    }
 234  
 
 235  
    private Object morphToByte( String str )
 236  
    {
 237  28
       Object result = null;
 238  28
       if( isUseDefault() ){
 239  20
          if( defaultValue == null ){
 240  4
             return (Byte) null;
 241  
          }else{
 242  16
             result = new Byte( new ByteMorpher( defaultValue.byteValue() ).morph( str ) );
 243  
          }
 244  
       }else{
 245  8
          result = new Byte( new ByteMorpher().morph( str ) );
 246  
       }
 247  24
       return result;
 248  
    }
 249  
 
 250  
    private Object morphToDouble( String str )
 251  
    {
 252  28
       Object result = null;
 253  28
       if( isUseDefault() ){
 254  20
          if( defaultValue == null ){
 255  4
             return (Double) null;
 256  
          }else{
 257  16
             result = new Double( new DoubleMorpher( defaultValue.doubleValue() ).morph( str ) );
 258  
          }
 259  
       }else{
 260  8
          result = new Double( new DoubleMorpher().morph( str ) );
 261  
       }
 262  24
       return result;
 263  
    }
 264  
 
 265  
    private Object morphToFloat( String str )
 266  
    {
 267  28
       Object result = null;
 268  28
       if( isUseDefault() ){
 269  20
          if( defaultValue == null ){
 270  4
             return (Float) null;
 271  
          }else{
 272  16
             result = new Float( new FloatMorpher( defaultValue.floatValue() ).morph( str ) );
 273  
          }
 274  
       }else{
 275  8
          result = new Float( new FloatMorpher().morph( str ) );
 276  
       }
 277  24
       return result;
 278  
    }
 279  
 
 280  
    private Object morphToInteger( String str )
 281  
    {
 282  55
       Object result = null;
 283  55
       if( isUseDefault() ){
 284  35
          if( defaultValue == null ){
 285  4
             return (Integer) null;
 286  
          }else{
 287  31
             result = new Integer( new IntMorpher( defaultValue.intValue() ).morph( str ) );
 288  
          }
 289  
       }else{
 290  20
          result = new Integer( new IntMorpher().morph( str ) );
 291  
       }
 292  51
       return result;
 293  
    }
 294  
 
 295  
    private Object morphToLong( String str )
 296  
    {
 297  28
       Object result = null;
 298  28
       if( isUseDefault() ){
 299  20
          if( defaultValue == null ){
 300  4
             return (Long) null;
 301  
          }else{
 302  16
             result = new Long( new LongMorpher( defaultValue.longValue() ).morph( str ) );
 303  
          }
 304  
       }else{
 305  8
          result = new Long( new LongMorpher().morph( str ) );
 306  
       }
 307  24
       return result;
 308  
    }
 309  
 
 310  
    private Object morphToShort( String str )
 311  
    {
 312  28
       Object result = null;
 313  28
       if( isUseDefault() ){
 314  20
          if( defaultValue == null ){
 315  4
             return (Short) null;
 316  
          }else{
 317  16
             result = new Short( new ShortMorpher( defaultValue.shortValue() ).morph( str ) );
 318  
          }
 319  
       }else{
 320  8
          result = new Short( new ShortMorpher().morph( str ) );
 321  
       }
 322  24
       return result;
 323  
    }
 324  
 }