Java/J2EE/JDO

Материал из Java эксперт
Перейти к: навигация, поиск

Contains static methods related to Java and JDO type conversions

  
/*
 * Copyright 2005 (C) TJDO.
 * All rights reserved.
 *
 * This software is distributed under the terms of the TJDO License version 1.0.
 * See the terms of the TJDO License in the documentation provided with this software.
 *
 * $Id: Types.java,v 1.1 2005/12/13 20:46:16 jackknifebarber Exp $
 */

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

/**
 * Contains static methods related to Java and JDO type conversions.
 *
 * @author 
 * @version $Revision: 1.1 $
 */
public final class Types
{
    private Types()
    {
    }
    private static final HashMap WRAPPERS_BY_PRIMITIVE = new HashMap(9);
    private static final HashMap PRIMITIVES_BY_WRAPPER = new HashMap(9);
    static
    {
        WRAPPERS_BY_PRIMITIVE.put(Boolean.TYPE,   Boolean.class);
        WRAPPERS_BY_PRIMITIVE.put(Byte.TYPE,      Byte.class);
        WRAPPERS_BY_PRIMITIVE.put(Character.TYPE, Character.class);
        WRAPPERS_BY_PRIMITIVE.put(Short.TYPE,     Short.class);
        WRAPPERS_BY_PRIMITIVE.put(Integer.TYPE,   Integer.class);
        WRAPPERS_BY_PRIMITIVE.put(Long.TYPE,      Long.class);
        WRAPPERS_BY_PRIMITIVE.put(Float.TYPE,     Float.class);
        WRAPPERS_BY_PRIMITIVE.put(Double.TYPE,    Double.class);
        WRAPPERS_BY_PRIMITIVE.put(Void.TYPE,      Void.class);
        PRIMITIVES_BY_WRAPPER.put(Boolean.class,   Boolean.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Byte.class,      Byte.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Character.class, Character.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Short.class,     Short.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Integer.class,   Integer.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Long.class,      Long.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Float.class,     Float.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Double.class,    Double.TYPE);
        PRIMITIVES_BY_WRAPPER.put(Void.class,      Void.TYPE);
    }
    /**
     * Performs a boxing conversion, if applicable.
     * If the type is a Java primitive type it"s equivalent wrapper class is
     * returned.
     * Otherwise the type itself is returned.
     *
     * @param c
     *      the type to be boxed, or <code>null</code>
     *
     * @return
     *      The boxed equivalent, or the type itself if not applicable.
     *      <code>null</code> is returned if the argument was null.
     */
    public static Class box(Class c)
    {
        Class boxed = (Class)WRAPPERS_BY_PRIMITIVE.get(c);
        return boxed == null ? c : boxed;
    }
    /**
     * Performs an unboxing conversion, if applicable.
     * If the type is a Java primitive wrapper class it"s equivalent primitive
     * type is returned.
     * Otherwise the type itself is returned.
     *
     * @param c
     *      the type to be unboxed, or <code>null</code>
     *
     * @return
     *      The unboxed equivalent, or the type itself if not applicable.
     *      <code>null</code> is returned if the argument was null.
     */
    public static Class unbox(Class c)
    {
        Class unboxed = (Class)PRIMITIVES_BY_WRAPPER.get(c);
        return unboxed == null ? c : unboxed;
    }
    /**
     * Performs a boxing conversion on multiple classes.
     * The returned array contains the results of calling {@link #box(Class)}
     * on every class in the argument array.
     *
     * @param c
     *      the types to be boxed
     *
     * @return
     *      the boxed equivalent of all the types in <var>c</var>
     */
    public static Class[] box(Class[] c)
    {
        int n = c.length;
        Class[] boxed = new Class[n];
        for (int i = 0; i < n; ++i)
            boxed[i] = box(c[i]);
        return boxed;
    }
    /**
     * Performs an unboxing conversion on multiple classes.
     * The returned array contains the results of calling {@link #unbox(Class)}
     * on every class in the argument array.
     *
     * @param c
     *      the types to be unboxed
     *
     * @return
     *      the unboxed equivalent of all the types in <var>c</var>
     */
    public static Class[] unbox(Class[] c)
    {
        int n = c.length;
        Class[] unboxed = new Class[n];
        for (int i = 0; i < n; ++i)
            unboxed[i] = unbox(c[i]);
        return unboxed;
    }
    /**
     * Tests if a set of parameters types are all assignable from a given set of
     * argument types.
     * Returns true iff the number of types match and each parameter type is
     * assignable from its corresponding argument type.
     * "Assignable" is defined by <code>Class.isAssignableFrom()</code>.
     * <p>
     * All classes in the parameter type array and the argument type array must
     * already be boxed.
     *
     * @param boxedParamTypes
     *      the parameter types
     * @param boxedArgTypes
     *      the argument types
     *
     * @return
     *      <code>true</code> if the all the parameter types are assignable from
     *      the argument types.
     */
    public static boolean areAssignableFrom(Class[] boxedParamTypes, Class[] boxedArgTypes)
    {
        int n = boxedParamTypes.length;
        if (n != boxedArgTypes.length)
            return false;
        for (int i = 0; i < n; ++i)
        {
            if (!boxedParamTypes[i].isAssignableFrom(boxedArgTypes[i]))
                return false;
        }
        return true;
    }
    /**
     * Performs <dfn>unary numeric promotion</dfn> on the given type.
     * Unary numeric promotion is as defined in &sect;5.6.1 of the Java Language
     * Specification.
     *
     * @param operandType
     *      the type to be promoted, or <code>null</code>
     *
     * @return
     *      The promoted type, or <code>null</code> if the argument was null.
     */
    public static Class unaryNumericPromotion(Class operandType)
    {
        operandType = box(operandType);
        if (operandType == Byte.class || operandType == Character.class || operandType == Short.class)
            return Integer.class;
        else
            return operandType;
    }
    /**
     * Performs <dfn>binary numeric promotion</dfn> on a set of input types.
     * Binary numeric promotion is as defined in &sect;14.6.2 of the JDO 2.0
     * spec.
     *
     * @param types
     *      The input types to be promoted.  If more than two types are present
     *      then the first two are promoted, then the promoted type and the
     *      third type are promoted, and so on for all the types.
     *
     * @return
     *      The promoted type.  Returns <code>null</code> if the input array
     *      is empty.  Returns the first type if the input array has only one
     *      type.
     *
     * @exception IllegalArgumentException
     *      if any argument type is not a subclass of java.lang.Number
     */
    public static Class binaryNumericPromotion(Class[] types)
    {
        Class promoted = null;
        int n = types.length;
        if (n > 0)
            promoted = types[0];
        for (int i = 1; i < n; ++i)
            promoted = binaryNumericPromotion(promoted, types[i]);
        return promoted;
    }
    /**
     * Performs <dfn>binary numeric promotion</dfn> on a pair of types.
     * Binary numeric promotion is as defined in &sect;14.6.2 of the JDO 2.0
     * spec.
     *
     * @param operand1Type
     *      the first type in the pair.
     * @param operand2Type
     *      the other type in the pair.
     *
     * @return
     *      The promoted type.
     *
     * @exception IllegalArgumentException
     *      if either argument type is not a subclass of java.lang.Number
     */
    public static Class binaryNumericPromotion(Class operand1Type, Class operand2Type)
    {
        operand1Type = box(operand1Type);
        operand2Type = box(operand2Type);
        if (operand1Type == BigDecimal.class || operand2Type == BigDecimal.class)
            return BigDecimal.class;
        if (isBigIntegerVsFloating(operand1Type, operand2Type) || isBigIntegerVsFloating(operand2Type, operand1Type))
            return BigDecimal.class;
        if (operand1Type == BigInteger.class || operand2Type == BigInteger.class)
            return BigInteger.class;
        if (operand1Type == Double.class || operand2Type == Double.class)
            return Double.class;
        if (operand1Type == Float.class || operand2Type == Float.class)
            return Float.class;
        if (operand1Type == Long.class || operand2Type == Long.class)
            return Long.class;
        if (!Number.class.isAssignableFrom(operand1Type) || !Number.class.isAssignableFrom(operand2Type))
            throw new IllegalArgumentException("No defined numeric promotion for operands of type " + operand1Type.getName() + " and " + operand2Type.getName());
        return Integer.class;
    }
    private static boolean isBigIntegerVsFloating(Class c1, Class c2)
    {
        return c1 == BigInteger.class && (c2 == Float.class || c2 == Double.class);
    }
}