/* * Copyright 2013 Guidewire Software, Inc. */ package gw.lang.parser.coercers; import gw.lang.parser.IResolvingCoercer; import gw.lang.parser.ICoercer; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.TypeSystemShutdownListener; import gw.lang.reflect.java.JavaTypes; import gw.config.CommonServices; import gw.util.concurrent.LockingLazyVar; public class BasePrimitiveCoercer extends StandardCoercer implements IResolvingCoercer { public static final LockingLazyVar<BasePrimitiveCoercer> DoublePCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(DoubleCoercer.instance(), JavaTypes.pDOUBLE(), JavaTypes.DOUBLE()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> FloatPCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(FloatCoercer.instance(), JavaTypes.pFLOAT(), JavaTypes.FLOAT()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> BooleanPCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(BooleanCoercer.instance(), JavaTypes.pBOOLEAN(), JavaTypes.BOOLEAN()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> BytePCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(ByteCoercer.instance(), JavaTypes.pBYTE(), JavaTypes.BYTE()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> ShortPCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(ShortCoercer.instance(), JavaTypes.pSHORT(), JavaTypes.SHORT()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> CharPCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(CharCoercer.instance(), JavaTypes.pCHAR(), JavaTypes.CHARACTER()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> IntPCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(IntCoercer.instance(), JavaTypes.pINT(), JavaTypes.INTEGER()); } }; public static final LockingLazyVar<BasePrimitiveCoercer> LongPCoercer = new LockingLazyVar<BasePrimitiveCoercer>() { protected BasePrimitiveCoercer init() { return new BasePrimitiveCoercer(LongCoercer.instance(), JavaTypes.pLONG(), JavaTypes.LONG()); } }; static { TypeSystem.addShutdownListener(new TypeSystemShutdownListener() { public void shutdown() { DoublePCoercer.clear(); FloatPCoercer.clear(); BooleanPCoercer.clear(); BytePCoercer.clear(); ShortPCoercer.clear(); CharPCoercer.clear(); IntPCoercer.clear(); LongPCoercer.clear(); } }); } //The non-primitive coercer private final ICoercer _nonPrimitiveCoercer; private final IType _primitiveType; private final IType _nonPrimitveType; public BasePrimitiveCoercer( ICoercer nonPrimitiveCoercer, IType primitiveType, IType nonPrimitiveType ) { _nonPrimitiveCoercer = nonPrimitiveCoercer; _primitiveType = primitiveType; _nonPrimitveType = nonPrimitiveType; } public final Object coerceValue( IType typeToCoerceTo, Object value ) { if( value == null ) { return CommonServices.getCoercionManager().convertNullAsPrimitive( _primitiveType, false ); } else { return _nonPrimitiveCoercer.coerceValue(typeToCoerceTo, value); } } @Override public boolean handlesNull() { return true; } public IType resolveType( IType target, IType source ) { return target.isPrimitive() ? _primitiveType : _nonPrimitveType; } @Override public int getPriority( IType to, IType from ) { int iPriority = 2; if( to == from ) { iPriority+=4; } else if( isAWideingConversion( to, from ) ) { iPriority+=3; } else if( hasLossOfPrecision(to, from) ) { iPriority+=2; } else if( JavaTypes.OBJECT().equals( to ) ) { iPriority++; } if( (isFloatFamily( to ) && isFloatFamily( from )) || (isIntFamily( to ) && isIntFamily( from )) ) { iPriority++; } return iPriority; } private boolean hasLossOfPrecision(IType to, IType from) { boolean[][] tab = { //TO //FROM boolean char byte short int long float double /*boolean*/ {false, false, false, false, false, false, false, false }, /*char */ {false, false, false, false, false, false, false, false }, /*byte */ {false, false, false, false, false, false, false, false }, /*short */ {false, false, false, false, false, false, false, false }, /*int */ {false, false, false, false, false, false, true, false }, /*long */ {false, false, false, false, false, false, true, true }, /*float */ {false, false, false, false, false, false, false, false }, /*double */ {false, false, false, false, false, false, false, false } }; final int i = getIndex(from); final int j = getIndex(to); if(i == -1 || j == -1 ) { return false; } return tab[i][j]; } private int getIndex(IType type) { if( type == JavaTypes.pBOOLEAN() || type == JavaTypes.BOOLEAN() ) { return 0; } else if( type == JavaTypes.pCHAR() || type == JavaTypes.CHARACTER() ) { return 1; } else if( type == JavaTypes.pBYTE() || type == JavaTypes.BYTE() ) { return 2; } else if( type == JavaTypes.pSHORT() || type == JavaTypes.SHORT() ) { return 3; } else if( type == JavaTypes.pINT() || type == JavaTypes.INTEGER() ) { return 4; } else if( type == JavaTypes.pLONG() || type == JavaTypes.LONG() ) { return 5; } else if( type == JavaTypes.pFLOAT() || type == JavaTypes.FLOAT() ) { return 6; } else if( type == JavaTypes.pDOUBLE() || type == JavaTypes.DOUBLE() ) { return 7; } return -1; } private boolean isAWideingConversion(IType to, IType from) { boolean[][] tab = { //TO //FROM boolean char byte short int long float double /*boolean*/ {true, false, false, false, false, false, false, false}, /*char */ {false, true, false, false, true, true, true, true }, /*byte */ {false, false, true, true, true, true, true, true }, /*short */ {false, false, false, true, true, true, true, true }, /*int */ {false, false, false, false, true, true, false, true }, /*long */ {false, false, false, false, false, true, false, false}, /*float */ {false, false, false, false, false, false, true, true }, /*double */ {false, false, false, false, false, false, false, true } }; final int i = getIndex(from); final int j = getIndex(to); if(i == -1 || j == -1 ) { return false; } return tab[i][j]; } private boolean isFloatFamily( IType type ) { return type == JavaTypes.FLOAT() || type == JavaTypes.pFLOAT() || type == JavaTypes.DOUBLE() || type == JavaTypes.pDOUBLE(); } private boolean isIntFamily( IType type ) { return type == JavaTypes.INTEGER() || type == JavaTypes.pINT() || type == JavaTypes.LONG() || type == JavaTypes.pLONG() || type == JavaTypes.SHORT() || type == JavaTypes.pSHORT() || type == JavaTypes.BYTE() || type == JavaTypes.pBYTE(); } }