/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ package org.hibernate.query.sqm.tree.expression; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author Steve Ebersole */ public class Compatibility { private Compatibility() { } private static final Map<Class,Class> primitiveToWrapper; private static final Map<Class,Class> wrapperToPrimitive; static { primitiveToWrapper = new ConcurrentHashMap<>(); wrapperToPrimitive = new ConcurrentHashMap<>(); map( boolean.class, Boolean.class ); map( char.class, Character.class ); map( byte.class, Byte.class ); map( short.class, Short.class ); map( int.class, Integer.class ); map( long.class, Long.class ); map( float.class, Float.class ); map( double.class, Double.class ); } private static void map(Class primitive, Class wrapper) { primitiveToWrapper.put( primitive, wrapper ); wrapperToPrimitive.put( wrapper, primitive ); } public static boolean isWrapper(Class potentialWrapper) { return wrapperToPrimitive.containsKey( potentialWrapper ); } public static Class primitiveEquivalent(Class potentialWrapper) { assert isWrapper( potentialWrapper ); return wrapperToPrimitive.get( potentialWrapper ); } public static Class wrapperEquivalent(Class primitive) { assert primitive.isPrimitive(); return primitiveToWrapper.get( primitive ); } @SuppressWarnings("unchecked") public static boolean areAssignmentCompatible(Class to, Class from) { assert to != null; assert from != null; if ( to.isAssignableFrom( from ) ) { return true; } // if to/from are primitive or primitive wrappers we need to check a little deeper if ( to.isPrimitive() ) { if ( from.isPrimitive() ) { return areAssignmentCompatiblePrimitive( to, from ); } else if ( isWrapper( from ) ) { return areAssignmentCompatiblePrimitive( to, primitiveEquivalent( from ) ); } } else if ( isWrapper( to ) ) { if ( from.isPrimitive() ) { return areAssignmentCompatiblePrimitive( primitiveEquivalent( to ), from ); } else if ( isWrapper( from ) ) { return areAssignmentCompatiblePrimitive( primitiveEquivalent( to ), primitiveEquivalent( from ) ); } } return false; } private static boolean areAssignmentCompatiblePrimitive(Class to, Class from) { assert to != null; assert from != null; assert to.isPrimitive(); assert from.isPrimitive(); // technically any number can be assigned to any other number, although potentially with loss of precision if ( to == boolean.class ) { return from == boolean.class; } else if ( to == char.class ) { return from == char.class; } else if ( to == byte.class ) { return from == byte.class; } else if ( isIntegralTypePrimitive( to ) ) { return from == byte.class || isIntegralTypePrimitive( from ) // this would for sure cause loss of precision || isFloatingTypePrimitive( from ); } else if ( isFloatingTypePrimitive( to ) ) { return from == byte.class || isIntegralTypePrimitive( from ) || isFloatingTypePrimitive( from ); } return false; } public static boolean isIntegralType(Class potentialIntegral) { if ( potentialIntegral.isPrimitive() ) { return isIntegralTypePrimitive( potentialIntegral ); } return isWrapper( potentialIntegral ) && isIntegralTypePrimitive( primitiveEquivalent( potentialIntegral ) ); } private static boolean isIntegralTypePrimitive(Class potentialIntegral) { assert potentialIntegral.isPrimitive(); return potentialIntegral == short.class || potentialIntegral == int.class || potentialIntegral == long.class; } public static boolean isFloatingType(Class potentialFloating) { if ( potentialFloating.isPrimitive() ) { return isFloatingTypePrimitive( potentialFloating ); } return isWrapper( potentialFloating ) && isFloatingTypePrimitive( primitiveEquivalent( potentialFloating ) ); } private static boolean isFloatingTypePrimitive(Class potentialFloating) { assert potentialFloating.isPrimitive(); return potentialFloating == float.class || potentialFloating == double.class; } }