/* * The contents of this file are subject to the Open Software License * Version 3.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.opensource.org/licenses/osl-3.0.txt * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. */ package org.mulgara.util; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; import java.util.HashMap; import java.util.Map; /** * Provides utilities for parsing numbers, and determining types for numbers. * * @created May 5, 2008 * @author Paula Gearon * @copyright © 2007 <a href="mailto:pgearon@users.sourceforge.net">Paula Gearon</a> * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a> */ public class NumberUtil { /** * Converts a string to a number of an appropriate type. The integral types are Long, Integer * and BigDecimal. The only floating point value is Double, since it is difficult to determine * a more appropriate type between Float and Double. It is possible to return Bytes and Shorts, * but these are less commonly used, so have been ignored here. * @param n The string representing the number. * @return A {@link java.lang.Number} containing the parsed data. */ static public Number parseNumber(String n) { if (n.indexOf('.') >= 0) return Double.valueOf(n); try { Long l = Long.valueOf(n); if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) return l.intValue(); return l; } catch (NumberFormatException e) { return new BigInteger(n); } } /** * Gets the XSD URI for a numeric class. * @param cls The class to get the XSD URI for. * @return A URI in the XSD namespace for the numeric type given, or <code>null</code> if the * numeric type is unrecognized. */ static public URI getXSD(Class<? extends Number> cls) { NumberStructure<?> st = classToNumber.get(cls); return (st == null) ? null : st.getURI(); } /** * Gets the XSD URI for a number. * @param n The number to get the XSD URI for. * @return A URI in the XSD namespace for the number given, or <code>null</code> if the * numeric type is unrecognized. */ static public URI getXSD(Number n) { NumberStructure<?> st = classToNumber.get(n.getClass()); return (st == null) ? null : st.getURI(); } /** * Gets the numeric Class for a numeric XSD URI. * @param xsdUri The URI for the numeric type. * @return A class that matches the URI, or <code>null</code> if the URI is not recognized. */ static public Class<? extends Number> getType(URI xsdUri) { NumberStructure<?> st = xsdToNumber.get(xsdUri); return (st == null) ? null : st.getType(); } /** * Parses a string representing a number into a numeric type defined by an XSD URI. * @param xsdUri The XSD URI of the numeric type to return. * @param str The string to be parsed for the number. * @return A {@link Number} representing the given string. * @throws NumberFormatException The number could not be parsed into the given type. */ static public Number valueOf(URI xsdUri, String str) { NumberStructure<?> st = xsdToNumber.get(xsdUri); return (st == null) ? null : st.valueOf(str); } /** * Parses a string representing a number into a numeric type defined by an XSD URI. * @param cls a Numeric class to parse the number with. * @param str The string to be parsed for the number. * @return A {@link Number} representing the given string. * @throws NumberFormatException The number could not be parsed into the given type. */ static public Number valueOf(Class<? extends Number> cls, String str) { NumberStructure<?> st = classToNumber.get(cls); return (st == null) ? null : st.valueOf(str); } /** * Returns The negation of a number, regardless of its type. * @param n The number to negate. * @return Negative the number, or null if the number was null. */ static public Number minus(Number n) { if (n instanceof Long) return new Long(-n.longValue()); if (n instanceof Integer) return new Integer(-n.intValue()); if (n instanceof Short) return new Short((short)-n.shortValue()); if (n instanceof Byte) return new Byte((byte)-n.byteValue()); if (n instanceof Double) return new Double(-n.doubleValue()); if (n instanceof Float) return new Float(-n.floatValue()); return null; } /////////////////////////////////////////////////////////////////////////////// // Internal structures for handling conversion of numeric types to XSD and back /////////////////////////////////////////////////////////////////////////////// /** A mapping of Java numeric types to XSD numeric types */ private static Map<Class<? extends Number>,NumberStructure<? extends Number>> classToNumber = new HashMap<Class<? extends Number>,NumberStructure<? extends Number>>(); /** A mapping of XSD numeric types to Java constructors that can represent those types. */ private static Map<URI,NumberStructure<? extends Number>> xsdToNumber = new HashMap<URI,NumberStructure<? extends Number>>(); /** An interface for representing a numeric class, the XSD type and a string-parsing constructor. */ private static interface NumberStructure<T extends Number> { public URI getURI(); public Class<T> getType(); public Number valueOf(String str); } /** * Utility for extracting the information out of a number structure for mapping Java and XSD types * to one another. * @param nmb The number structure to get the appropriate mapping information. */ private static void mapNumber(NumberStructure<?> nmb) { classToNumber.put(nmb.getType(), nmb); xsdToNumber.put(nmb.getURI(), nmb); } // Map info for each numeric type to that type's structure static { mapNumber(new ByteStruct()); mapNumber(new ShortStruct()); mapNumber(new IntegerStruct()); mapNumber(new LongStruct()); mapNumber(new BigIntegerStruct()); mapNumber(new FloatStruct()); mapNumber(new DoubleStruct()); mapNumber(new BigDecimalStruct()); } // Implementations of NumerStructtructor follow private static class ByteStruct implements NumberStructure<Byte> { public URI getURI() { return BYTE_URI; } public Class<Byte> getType() { return Byte.class; } public Number valueOf(String str) { return Byte.valueOf(str); } } private static class ShortStruct implements NumberStructure<Short> { public URI getURI() { return SHORT_URI; } public Class<Short> getType() { return Short.class; } public Number valueOf(String str) { return Short.valueOf(str); } } private static class IntegerStruct implements NumberStructure<Integer> { public URI getURI() { return INT_URI; } public Class<Integer> getType() { return Integer.class; } public Number valueOf(String str) { return Integer.valueOf(str); } } private static class LongStruct implements NumberStructure<Long> { public URI getURI() { return LONG_URI; } public Class<Long> getType() { return Long.class; } public Number valueOf(String str) { return Long.valueOf(str); } } private static class BigIntegerStruct implements NumberStructure<BigInteger> { public URI getURI() { return INTEGER_URI; } public Class<BigInteger> getType() { return BigInteger.class; } public Number valueOf(String str) { return new BigInteger(str); } } private static class FloatStruct implements NumberStructure<Float> { public URI getURI() { return FLOAT_URI; } public Class<Float> getType() { return Float.class; } public Number valueOf(String str) { return Float.valueOf(str); } } private static class DoubleStruct implements NumberStructure<Double> { public URI getURI() { return DOUBLE_URI; } public Class<Double> getType() { return Double.class; } public Number valueOf(String str) { return Double.valueOf(str); } } private static class BigDecimalStruct implements NumberStructure<BigDecimal> { public URI getURI() { return DECIMAL_URI; } public Class<BigDecimal> getType() { return BigDecimal.class; } public Number valueOf(String str) { return new BigDecimal(str); } } //////////////////////// // The XSD numeric types //////////////////////// /** The namespace for XSD data. */ public final static String XSD_NS = "http://www.w3.org/2001/XMLSchema#"; /** URI for the XML Schema <code>xsd:float</code> datatype; */ public final static URI FLOAT_URI = URI.create(XSD_NS + "float"); /** URI for the XML Schema <code>xsd:double</code> datatype; */ public final static URI DOUBLE_URI = URI.create(XSD_NS + "double"); /** URI for the XML Schema <code>xsd:decimal</code> datatype. */ public final static URI DECIMAL_URI = URI.create(XSD_NS + "decimal"); /** URI for the XML Schema <code>integer</code> datatype. Subtype of {@link #DECIMAL_URI}. */ public final static URI INTEGER_URI = URI.create(XSD_NS + "integer"); /** URI for the XML Schema <code>long</code> datatype. Subtype of {@link #INTEGER_URI}. */ public final static URI LONG_URI = URI.create(XSD_NS + "long"); /** URI for the XML Schema <code>int</code> datatype. Subtype of {@link #LONG_URI}. */ public final static URI INT_URI = URI.create(XSD_NS + "int"); /** URI for the XML Schema <code>short</code> datatype. Subtype of {@link #INT_URI}. */ public final static URI SHORT_URI = URI.create(XSD_NS + "short"); /** URI for the XML Schema <code>byte</code> datatype. Subtype of {@link #SHORT_URI}. */ public final static URI BYTE_URI = URI.create(XSD_NS + "byte"); }