All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.projectmonkey.object.mapper.construction.converter.NumberConverter Maven / Gradle / Ivy

Go to download

Object mapping implementation written as an alternative to modelmapper which is able to support inheritance, handles flattening / expanding in a precise way, and is extensible / configurable

The newest version!
package net.projectmonkey.object.mapper.construction.converter;

import net.projectmonkey.object.mapper.construction.PopulationContext;
import net.projectmonkey.object.mapper.construction.RootPopulationContext;
import net.projectmonkey.object.mapper.util.Assert;
import net.projectmonkey.object.mapper.util.Primitives;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

/*
 *
 *  * Copyright 2012 the original author or authors.
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 *
 */

/**
 * Converts:
 * 

*

    *
  • Number
  • *
  • Boolean
  • *
  • String
  • *
*

* instances to instances of: *

*

    *
  • Byte
  • *
  • Short
  • *
  • Integer
  • *
  • Long
  • *
  • Float
  • *
  • Double
  • *
  • BigDecimal
  • *
  • BigInteger
  • *
*

* Adapted from ModelMapper (modelmapper.org) * * @author Jonathan Halterman * @author Andy Moody */ public class NumberConverter implements CacheableConverter { public static final NumberConverter INSTANCE = new NumberConverter(); private static final Map, NumberLimits> LIMITS = new HashMap, NumberLimits>(); private static final Map, NumberParser> PARSERS = new HashMap, NumberParser>(); static { LIMITS.put(Byte.class, new NumberLimits(Byte.MIN_VALUE, Byte.MAX_VALUE)); LIMITS.put(Integer.class, new NumberLimits(Integer.MIN_VALUE, Integer.MAX_VALUE)); LIMITS.put(Short.class, new NumberLimits(Short.MIN_VALUE, Short.MAX_VALUE)); LIMITS.put(Float.class, new NumberLimits(null, Float.MAX_VALUE)); PARSERS.put(Byte.class, new ByteParser()); PARSERS.put(Integer.class, new IntegerParser()); PARSERS.put(Short.class, new ShortParser()); PARSERS.put(Float.class, new FloatParser()); PARSERS.put(Double.class, new DoubleParser()); PARSERS.put(Long.class, new LongParser()); PARSERS.put(BigDecimal.class, new BigDecimalParser()); PARSERS.put(BigInteger.class, new BigIntegerParser()); } private NumberConverter() { } public Number convert(final PopulationContext context) { Number toReturn = null; Object source = context.getSource(); Class destinationType = context.getDestinationType(); if(source != null) { if(source instanceof Number) { toReturn = numberFor((Number) source, destinationType); } else if(source instanceof Boolean || source.getClass().equals(Boolean.TYPE)) { toReturn = numberFor(((Boolean) source).booleanValue() ? 1 : 0, destinationType); } else { RootPopulationContext stringContext = new RootPopulationContext(source, String.class); return numberFor(StringConverter.INSTANCE.convert(stringContext), destinationType); } } return toReturn; } @Override public boolean canConvert(final PopulationContext context) { return Number.class.isAssignableFrom(Primitives.wrapperFor(context.getDestinationType())); } private D numberFor(final String source, final Class destinationType) { try { BigDecimal decimal = new BigDecimal(source); return numberFor(decimal, destinationType); } catch(NumberFormatException e) { throw new IllegalArgumentException("Unable to convert string " + source + " to " + destinationType, e); } } /** * Creates a Number for the {@code source} and {@code destinationType}. */ private D numberFor(Number source, Class destinationType) { D toReturn = null; Class sourceType = Primitives.wrapperFor(source.getClass()); Class destinationWrapperType = Primitives.wrapperFor(destinationType); if(destinationType.equals(sourceType) || destinationWrapperType.equals(sourceType)) { toReturn = (D) source; } else { if(PARSERS.containsKey(destinationWrapperType)) { if(LIMITS.containsKey(destinationWrapperType)) { NumberLimits limits = LIMITS.get(destinationWrapperType); Assert.isTrue(limits.isValid(source), "value " + source + " is not within limits " + limits); } toReturn = (D) PARSERS.get(destinationWrapperType).parse(source); } } if(toReturn == null) { throw new IllegalArgumentException("Unable to convert number of type " + sourceType + " to " + destinationType); } return toReturn; } @Override public Class[] getApplicableSourceTypes() { return new Class[]{ Integer.class, Integer.TYPE, Long.class, Long.TYPE, Short.class, Short.TYPE, Float.class, Float.TYPE, Double.class, Double.TYPE, BigInteger.class, BigDecimal.class, Byte.class, Byte.TYPE, Boolean.class, Boolean.TYPE, String.class }; } @Override public Class[] getApplicableDestinationTypes() { return new Class[]{ Integer.class, Integer.TYPE, Long.class, Long.TYPE, Short.class, Short.TYPE, Float.class, Float.TYPE, Double.class, Double.TYPE, BigInteger.class, BigDecimal.class, Byte.class, Byte.TYPE }; } private static class NumberLimits { private Number min; private Number max; public NumberLimits(final Number min, final Number max) { this.min = min; this.max = max; } public boolean isValid(Number value) { return (min == null || isLessThanOrEqualTo(min, value)) && isLessThanOrEqualTo(value, max); } private BigDecimal getNumberForComparison(final Number n) { return new BigDecimal(n.toString()); } private boolean isLessThanOrEqualTo(Number first, Number second) { return getNumberForComparison(first).compareTo(getNumberForComparison(second)) <= 0; } @Override public String toString() { return "NumberLimits{" + "min=" + min + ", max=" + max + '}'; } } private static interface NumberParser { D parse(Number number); } private static class ByteParser implements NumberParser { @Override public Byte parse(final Number number) { return Byte.valueOf(number.byteValue()); } } private static class LongParser implements NumberParser { @Override public Long parse(final Number number) { return Long.valueOf(number.longValue()); } } private static class IntegerParser implements NumberParser { @Override public Integer parse(final Number number) { return Integer.valueOf(number.intValue()); } } private static class ShortParser implements NumberParser { @Override public Short parse(final Number number) { return Short.valueOf(number.shortValue()); } } private static class FloatParser implements NumberParser { @Override public Float parse(final Number number) { return Float.valueOf(number.floatValue()); } } private static class DoubleParser implements NumberParser { @Override public Double parse(final Number number) { return new BigDecimal(number.toString()).doubleValue(); } } private static class BigDecimalParser implements NumberParser { @Override public BigDecimal parse(final Number number) { if(number instanceof BigInteger) { return new BigDecimal((BigInteger)number); } return new BigDecimal(number.toString()); } } private static class BigIntegerParser implements NumberParser { @Override public BigInteger parse(final Number number) { if(number instanceof BigDecimal) { return ((BigDecimal) number).toBigInteger(); } return BigInteger.valueOf(number.longValue()); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy