/* * Rapid Beans Framework: TypePropertyInteger.java * * Copyright (C) 2009 Martin Bluemel * * Creation Date: 11/27/2005 * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * You should have received a copies of the GNU Lesser General Public License and the * GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>. */ package org.rapidbeans.core.type; import java.math.BigInteger; import org.rapidbeans.core.basic.IntegerSize; import org.rapidbeans.core.basic.PropertyInteger; import org.rapidbeans.core.exception.RapidBeansRuntimeException; import org.rapidbeans.core.exception.ValidationException; import org.rapidbeans.core.util.ClassHelper; import org.rapidbeans.core.util.StringHelper; import org.rapidbeans.core.util.XmlNode; /** * The bean property type class for Integer properties. * * @author Martin Bluemel */ public final class TypePropertyInteger extends TypePropertyNumber { @Override public Class<?> getValuetype() { return Number.class; } /** * Bit size of the current integer implementation. Default: byte04 is the * size of Java Integer (int). */ private IntegerSize size = IntegerSize.byte04; /** * Constructor for TypePropertyInteger. * * @param xmlNode * the XML DOM node describing the property type * @param parentBeanType * the parent bean type */ public TypePropertyInteger(final XmlNode[] xmlNodes, final TypeRapidBean parentBeanType) { super("Integer", xmlNodes, parentBeanType); final String sizeString = xmlNodes[0].getAttributeValue("@size"); if (sizeString != null) { this.size = IntegerSize.valueOf(sizeString); } if (this.getNumberClass() == null) { this.setNumberClass(sizeToNumberClass(this.size)); } final String maxValueString = xmlNodes[0].getAttributeValue("@maxval"); if (maxValueString != null) { this.setMaxValue(constructNumber(maxValueString)); } final String minValueString = xmlNodes[0].getAttributeValue("@minval"); if (minValueString != null) { this.setMinValue(constructNumber(minValueString)); } final String defaultValueString = xmlNodes[0].getAttributeValue("@default"); if (defaultValueString != null) { final Number defaultValue = convertValue(null, defaultValueString); this.setDefaultValue(defaultValue); } } /** * Tells us which Java number class implements the given size. * * @param size * the size to convert to a Java number class. * @return the Java number class implementing the given integer size. */ private Class<?> sizeToNumberClass(final IntegerSize size) { switch (size) { case byte01: return Byte.class; case byte02: return Short.class; case byte04: return Integer.class; case byte08: return Long.class; case unlimited: return BigInteger.class; default: throw new RapidBeansRuntimeException("Unknown integer size \"" + size.toString() + "\""); } } /** * @return the property type enumeration */ public PropertyType getProptype() { return PropertyType.integer; } private enum ConvertErrorType { none, tooLargeByte, tooSmallByte, tooLargeShort, tooSmallShort, tooLargeInteger, tooSmallInteger, tooLargeLong, tooSmallLong, } private static final BigInteger bigIntLongMaxValue = new BigInteger(new Long(Long.MAX_VALUE).toString()); private static final BigInteger bigIntLongMinValue = new BigInteger(new Long(Long.MIN_VALUE).toString()); private static final BigInteger bigIntIntegerMaxValue = new BigInteger(new Integer(Integer.MAX_VALUE).toString()); private static final BigInteger bigIntIntegerMinValue = new BigInteger(new Integer(Integer.MIN_VALUE).toString()); private static final BigInteger bigIntShortMaxValue = new BigInteger(new Short(Short.MAX_VALUE).toString()); private static final BigInteger bigIntShortMinValue = new BigInteger(new Short(Short.MIN_VALUE).toString()); private static final BigInteger bigIntByteMaxValue = new BigInteger(new Byte(Byte.MAX_VALUE).toString()); private static final BigInteger bigIntByteMinValue = new BigInteger(new Byte(Byte.MIN_VALUE).toString()); /** * converter. * * @param prop * the property to validate * @param integerValue * the object to convert Must be an instance of the following * classes:<br/> * <b>Integer:</b> the integer value itself<br/> * <b>String:</b> the integer as decimal string<br/> * * @return the converted value */ public Number convertValue(final PropertyInteger prop, final Object integerValue) { Number i = null; final Class<?> numberClass = this.getNumberClass(); ConvertErrorType error = ConvertErrorType.none; if (integerValue != null) { if (integerValue instanceof BigInteger) { final BigInteger intValBigInt = (BigInteger) integerValue; if (ClassHelper.classOf(BigInteger.class, numberClass)) { i = intValBigInt; } else if (ClassHelper.classOf(Long.class, numberClass)) { if (intValBigInt.compareTo(bigIntLongMaxValue) > 0) { error = ConvertErrorType.tooLargeLong; } else if (intValBigInt.compareTo(bigIntLongMinValue) < 0) { error = ConvertErrorType.tooSmallLong; } else { i = new Long(intValBigInt.longValue()); } } else if (ClassHelper.classOf(Integer.class, numberClass)) { if (intValBigInt.compareTo(bigIntIntegerMaxValue) > 0) { error = ConvertErrorType.tooLargeInteger; } else if (intValBigInt.compareTo(bigIntIntegerMinValue) < 0) { error = ConvertErrorType.tooSmallInteger; } else { i = new Integer(intValBigInt.intValue()); } } else if (ClassHelper.classOf(Short.class, numberClass)) { if (intValBigInt.compareTo(bigIntShortMaxValue) > 0) { error = ConvertErrorType.tooLargeShort; } else if (intValBigInt.compareTo(bigIntShortMinValue) < 0) { error = ConvertErrorType.tooSmallShort; } else { i = new Short(intValBigInt.shortValue()); } } else if (ClassHelper.classOf(Byte.class, numberClass)) { if (intValBigInt.compareTo(bigIntByteMaxValue) > 0) { error = ConvertErrorType.tooLargeByte; } else if (intValBigInt.compareTo(bigIntByteMinValue) < 0) { error = ConvertErrorType.tooSmallByte; } else { i = new Byte(intValBigInt.byteValue()); } } } else if (integerValue instanceof Long) { final Long intValLong = (Long) integerValue; if (ClassHelper.classOf(BigInteger.class, numberClass)) { i = new BigInteger(intValLong.toString()); } else if (ClassHelper.classOf(Long.class, numberClass)) { i = intValLong; } else if (ClassHelper.classOf(Integer.class, numberClass)) { if (intValLong > Integer.MAX_VALUE) { error = ConvertErrorType.tooLargeInteger; } else if (intValLong < Integer.MIN_VALUE) { error = ConvertErrorType.tooSmallInteger; } else { i = new Integer(intValLong.intValue()); } } else if (ClassHelper.classOf(Short.class, numberClass)) { if (intValLong > Short.MAX_VALUE) { error = ConvertErrorType.tooLargeShort; } else if (intValLong < Short.MIN_VALUE) { error = ConvertErrorType.tooSmallShort; } else { i = new Short(intValLong.shortValue()); } } else if (ClassHelper.classOf(Byte.class, numberClass)) { if (intValLong > Byte.MAX_VALUE) { error = ConvertErrorType.tooLargeByte; } else if (intValLong < Byte.MIN_VALUE) { error = ConvertErrorType.tooSmallByte; } else { i = new Byte(intValLong.byteValue()); } } } else if (integerValue instanceof Integer) { final Integer intValInteger = (Integer) integerValue; if (ClassHelper.classOf(BigInteger.class, numberClass)) { i = new BigInteger(intValInteger.toString()); } else if (ClassHelper.classOf(Long.class, numberClass)) { i = new Long(intValInteger.longValue()); } else if (ClassHelper.classOf(Integer.class, numberClass)) { i = intValInteger; } else if (ClassHelper.classOf(Short.class, numberClass)) { if (intValInteger > Short.MAX_VALUE) { error = ConvertErrorType.tooLargeShort; } else if (intValInteger < Short.MIN_VALUE) { error = ConvertErrorType.tooSmallShort; } else { i = new Short(intValInteger.shortValue()); } } else if (ClassHelper.classOf(Byte.class, numberClass)) { if (intValInteger > Byte.MAX_VALUE) { error = ConvertErrorType.tooLargeByte; } else if (intValInteger < Byte.MIN_VALUE) { error = ConvertErrorType.tooSmallByte; } else { i = new Byte(intValInteger.byteValue()); } } } else if (integerValue instanceof Short) { final Short intValShort = (Short) integerValue; if (ClassHelper.classOf(BigInteger.class, numberClass)) { i = new BigInteger(intValShort.toString()); } else if (ClassHelper.classOf(Long.class, numberClass)) { i = new Long(intValShort.longValue()); } else if (ClassHelper.classOf(Integer.class, numberClass)) { i = new Integer(intValShort.intValue()); } else if (ClassHelper.classOf(Short.class, numberClass)) { i = intValShort; } else if (ClassHelper.classOf(Byte.class, numberClass)) { if (intValShort > Byte.MAX_VALUE) { error = ConvertErrorType.tooLargeByte; } else if (intValShort < Byte.MIN_VALUE) { error = ConvertErrorType.tooSmallByte; } else { i = new Byte(intValShort.byteValue()); } } } else if (integerValue instanceof Byte) { if (ClassHelper.classOf(BigInteger.class, numberClass)) { i = new BigInteger(((Byte) integerValue).toString()); } else if (ClassHelper.classOf(Long.class, numberClass)) { i = new Long(((Byte) integerValue).longValue()); } else if (ClassHelper.classOf(Integer.class, numberClass)) { i = new Integer(((Byte) integerValue).intValue()); } else if (ClassHelper.classOf(Short.class, numberClass)) { i = new Short(((Byte) integerValue).shortValue()); } else if (ClassHelper.classOf(Byte.class, numberClass)) { i = (Byte) integerValue; } } else if (integerValue instanceof String) { String sIntegerValue = (String) integerValue; try { if (ClassHelper.classOf(BigInteger.class, numberClass)) { i = new BigInteger(sIntegerValue); } else if (ClassHelper.classOf(Long.class, numberClass)) { i = new Long(sIntegerValue); } else if (ClassHelper.classOf(Integer.class, numberClass)) { i = new Integer(sIntegerValue); } else if (ClassHelper.classOf(Short.class, numberClass)) { i = new Short(sIntegerValue); } else if (ClassHelper.classOf(Byte.class, numberClass)) { i = new Byte(sIntegerValue); } } catch (NumberFormatException e) { boolean negative = false; sIntegerValue = sIntegerValue.trim(); if (sIntegerValue.startsWith("-")) { sIntegerValue = sIntegerValue.substring(1); negative = true; } if (sIntegerValue.length() > 0 && StringHelper.isDigitsOnly(sIntegerValue) && (!ClassHelper.classOf(BigInteger.class, numberClass))) { if (negative) { if (ClassHelper.classOf(Long.class, numberClass)) { error = ConvertErrorType.tooSmallLong; } else if (ClassHelper.classOf(Integer.class, numberClass)) { error = ConvertErrorType.tooSmallInteger; } else if (ClassHelper.classOf(Short.class, numberClass)) { error = ConvertErrorType.tooSmallShort; } else if (ClassHelper.classOf(Byte.class, numberClass)) { error = ConvertErrorType.tooSmallByte; } } else { if (ClassHelper.classOf(Long.class, numberClass)) { error = ConvertErrorType.tooLargeLong; } else if (ClassHelper.classOf(Integer.class, numberClass)) { error = ConvertErrorType.tooLargeInteger; } else if (ClassHelper.classOf(Short.class, numberClass)) { error = ConvertErrorType.tooLargeShort; } else if (ClassHelper.classOf(Byte.class, numberClass)) { error = ConvertErrorType.tooLargeByte; } } } else { throw new ValidationException("invalid.prop.integer.nonumber", prop, "\"" + (String) integerValue + "\" is no valid number.", new Object[] { integerValue }); } } } else { throw new ValidationException("invalid.prop.integer.type", prop, "invalid data type \"" + integerValue.getClass().getName() + "\".\nOnly \"Integer\" and \"String\" are valid types."); } } switch (error) { case tooLargeLong: throw new ValidationException("invalid.prop.integer.int.large", prop, integerValue.toString() + " is too large for a Java Long.\n" + "The largest possible Long value is " + new Long(Long.MAX_VALUE).toString() + ".", new Object[] { integerValue.toString(), Long.MAX_VALUE }); case tooSmallLong: throw new ValidationException("invalid.prop.integer.int.small", prop, integerValue.toString() + " is too small for a Java Long.\n" + "The smallest possible Long value is " + new Long(Long.MIN_VALUE).toString() + ".", new Object[] { integerValue.toString(), Long.MIN_VALUE }); case tooLargeInteger: throw new ValidationException("invalid.prop.integer.int.large", prop, integerValue.toString() + " is too large for a Java Integer.\n" + "The largest possible Java Integer value is " + new Integer(Integer.MAX_VALUE).toString() + ".", new Object[] { integerValue.toString(), Integer.MAX_VALUE }); case tooSmallInteger: throw new ValidationException("invalid.prop.integer.int.small", prop, integerValue.toString() + " is too small for a Java Integer.\n" + "The smallest possible Java Integer value is " + new Integer(Integer.MIN_VALUE).toString() + ".", new Object[] { integerValue.toString(), Integer.MIN_VALUE }); case tooLargeShort: throw new ValidationException("invalid.prop.integer.int.large", prop, integerValue.toString() + " is too large for a Java Short.\n" + "The largest possible Java Short value is " + new Short(Short.MAX_VALUE).toString() + ".", new Object[] { integerValue.toString(), Short.MAX_VALUE }); case tooSmallShort: throw new ValidationException("invalid.prop.integer.int.small", prop, integerValue.toString() + " is too small for a Java Short.\n" + "The smallest possible Java Short value is " + new Short(Short.MIN_VALUE).toString() + ".", new Object[] { integerValue.toString(), Short.MIN_VALUE }); case tooLargeByte: throw new ValidationException("invalid.prop.integer.int.large", prop, integerValue.toString() + " is too large for a Java Byte\n" + "The largest possible Java Byte value is " + new Byte(Byte.MAX_VALUE).toString() + ".", new Object[] { integerValue.toString(), Byte.MAX_VALUE }); case tooSmallByte: throw new ValidationException("invalid.prop.integer.int.small", prop, integerValue.toString() + " is too small for a Java Byte\n" + "The smallest possible Java Byte value is " + new Byte(Byte.MIN_VALUE).toString() + ".", new Object[] { integerValue.toString(), Byte.MIN_VALUE }); case none: break; default: throw new RapidBeansRuntimeException("Unexpected errorType \"" + error.name() + "\""); } return i; } }