/** Return a UtilEvalError or UtilTargetError wrapping a ClassCastException describing an illegal assignment or illegal cast, respectively. */ static UtilEvalError castError( Class lhsType, Class rhsType, int operation ) { return castError( StringUtil.typeString(lhsType), StringUtil.typeString(rhsType), operation ); }
/** Coerce parameter values to parameter type and unwrap primitives. * @param param the parameter value * @param type the parameter type * @return unwrapped coerced value * @throws Throwable on cast errors */ protected Object coerceToType(Object param, Class<?> type) throws Throwable { if (type != Object.class) param = Types.castObject(param, type, Types.CAST); return Primitive.unwrap(param); }
/** Find invocable for the given name and arguments. * Arguments are converted to type parameters. * @param name of member * @param args parameter argument values * @return the most specific member or null */ public Invocable findMethod(String name, Object... args) { return findMethod(name, Types.getTypes(args)); }
/** Test if a conversion of the rhsType type to the lhsType type is legal via standard Java assignment conversion rules (i.e. without a cast). The rules include Java 5 autoboxing/unboxing. <p/> For Java primitive TYPE classes this method takes primitive promotion into account. The ordinary Class.isAssignableFrom() does not take primitive promotion conversions into account. Note that Java allows additional assignments without a cast in combination with variable declarations and array allocations. Those are handled elsewhere (maybe should be here with a flag?) <p/> This class accepts a null rhsType type indicating that the rhsType was the value Primitive.NULL and allows it to be assigned to any reference lhsType type (non primitive). <p/> Note that the getAssignableForm() method is the primary bsh method for checking assignability. It adds additional bsh conversions, etc. @see #isBshAssignable( Class, Class ) @param lhsType assigning from rhsType to lhsType @param rhsType assigning from rhsType to lhsType */ static boolean isJavaAssignable( Class lhsType, Class rhsType ) { return isJavaBaseAssignable( lhsType, rhsType ) || isJavaBoxTypesAssignable( lhsType, rhsType ); }
Class<?>[] targetMatch = candidates[i]; if (null != bestMatch && Types .areSignaturesEqual(targetMatch, bestMatch)) if ( Types.isSignatureAssignable( idealMatch, targetMatch, round ) && ( bestMatch == null || Types.areSignaturesEqual(idealMatch, targetMatch) || ( Types.isSignatureAssignable(targetMatch, bestMatch, Types.JAVA_BASE_ASSIGNABLE) && !Types.areSignaturesEqual(idealMatch, bestMatch)))) { bestMatch = targetMatch; bestMatchIndex = i;
if ( !isJavaBaseAssignable( to[i], from[i] ) ) return false; return true; case JAVA_BOX_TYPES_ASSIGABLE: for( int i=0; i<from.length; i++ ) if ( !isJavaBoxTypesAssignable( to[i], from[i] ) ) return false; return true; case JAVA_VARARGS_ASSIGNABLE: return isSignatureVarargsAssignable( from, to ); case BSH_ASSIGNABLE: for( int i=0; i<from.length; i++ ) if ( !isBshAssignable( to[i], from[i] ) ) return false; return true;
if ( Types.isJavaAssignable(Collection.class, toType) ) if ( Types.isJavaAssignable(List.class, toType) || Queue.class == toType ) { if ( Types.isJavaAssignable(toType, ArrayList.class) ) Types.castObject(fromValue, Object.class, Types.CAST))); else if ( Types.isJavaAssignable(toType, LinkedList.class) ) Types.castObject(fromValue, Object.class, Types.CAST))); } else if ( Types.isJavaAssignable(toType, ArrayDeque.class) ) Types.castObject(fromValue, Object.class, Types.CAST))); else if ( Types.isJavaAssignable(toType, LinkedHashSet.class) ) Types.castObject(fromValue, Object.class, Types.CAST))); if ( Types.isJavaAssignable(Map.class, toType) ) { if ( Types.isJavaAssignable(Entry.class, Types.arrayElementType(fromType)) ) return mapOfEntries((Entry[]) fromValue); if ( Types.isJavaAssignable(toType, LinkedHashMap.class) ) { int length = Array.getLength(fromValue); Map<Object, Object> map = new LinkedHashMap<>( if ( Types.isJavaAssignable(Entry.class, toType) ) { int length = Array.getLength(fromValue); if ( length == 1 ) toType = Types.arrayElementType(toType); int[] dims = dimensions(fromValue); Object toArray = Array.newInstance(toType, dims);
return Types.INVALID_CAST; else throw Types.castError( Reflect.normalizeClassName(toType), "void value", operation ); return Types.INVALID_CAST; else throw Types.castError( "primitive type:" + toType, "Null value", operation ); return Types.INVALID_CAST; else throw Types.castError( "object type:" + toType, "primitive value", operation); return Types.INVALID_CAST; else throw Types.castError( toType, fromType, operation ); && !Types.isJavaAssignable( toType, fromType ) ) { if ( checkOnly ) return Types.INVALID_CAST; else throw Types.castError( toType, fromType, operation );
/** Helper class for type suffixes. */ public static class Suffix { private static final Map<String, Class<?>> m = Collections.unmodifiableMap(new HashMap<String, Class<?>>() { private static final long serialVersionUID = 1L; { put("O", Byte.TYPE); put("S", Short.TYPE); put("I", Integer.TYPE); put("L", Long.TYPE); put("W", BigInteger.class); put("w", BigDecimal.class); put("d", Double.TYPE); put("f", Float.TYPE); } }); private static String toUpperKey(Character key) { return key.toString().toUpperCase(); } private static String toLowerKey(Character key) { return key.toString().toLowerCase(); } public static boolean isIntegral(Character key) { return m.containsKey(toUpperKey(key)); } public static Class<?> getIntegralType(Character key) { return m.get(toUpperKey(key));
if ( !isPrimitive(toType) && !Primitive.isWrapperType(toType) ) return Primitive.NULL; else Class<?> fromType = getType(fromValue); return castObject( toType, fromType, fromValue, operation, false/*checkonly*/ );
if ( Types.isJavaAssignable(Collection.class, baseType) || Types.isJavaAssignable(Map.class, baseType) || Types.isJavaAssignable(Entry.class, baseType) ) baseType = Void.TYPE; value = Types.castObject( currentInitializer, baseType, Types.CAST ); } catch ( UtilEvalError e ) { if ( Types.isJavaAssignable(Collection.class, originalBaseType) || Types.isJavaAssignable(Map.class, originalBaseType) || Types.isJavaAssignable(Entry.class, originalBaseType) ) try { initializers = Types.castObject(initializers, originalBaseType, Types.CAST); } catch (UtilEvalError e) { throw new EvalError(e.getMessage(), this, callstack, e);
: Types.getType(val).getSimpleName(); throw new UtilEvalError( "Argument type mismatch. " + type val = Types.castObject( val, Types.arrayElementType(object.getClass()), Types.ASSIGNMENT); } catch (Exception e) { /* ignore cast exceptions */ } if ( nameSpace.isInterface ) mods.setConstant(); nameSpace.setTypedVariable(varName, Types.getType(val), val, mods); return val; } else if ( type == MAP_ENTRY ) {
BshMethod constructor = instanceNameSpace.getMethod(Types.getBaseName(className), Types.getTypes(args), true/*declaredOnly*/);
/** Determine if the type is assignable via Java boxing/unboxing rules. */ static boolean isJavaBoxTypesAssignable( Class lhsType, Class rhsType ) { // Assignment to loose type... defer to bsh extensions if ( lhsType == null ) return false; // prim can be boxed and assigned to Object if ( lhsType == Object.class ) return true; // null rhs type corresponds to type of Primitive.NULL // assignable to any object type but not array if (rhsType == null) return !lhsType.isPrimitive() && !lhsType.isArray(); // prim numeric type can be boxed and assigned to number if ( lhsType == Number.class && rhsType != Character.TYPE && rhsType != Boolean.TYPE ) return true; // General case prim type to wrapper or vice versa. // I don't know if this is faster than a flat list of 'if's like above. // wrapperMap maps both prim to wrapper and wrapper to prim types, // so this test is symmetric if ( Primitive.wrapperMap.get( lhsType ) == rhsType ) return true; return isJavaBaseAssignable(lhsType, rhsType); }
length = Array.getLength(from[0]), total = from.length > 1 ? Array.getLength(to) : length; if ( Types.arrayDimensions(to.getClass()) == 1 ) { for ( int i = 0; i < total; i++ ) { Object value = Array.get(from[f], fi++); try { value = Primitive.unwrap( Types.castObject(value, toType, Types.CAST)); } catch (UtilEvalError e) { /* ignore cast errors */ } if ( Byte.TYPE == toType )
if (Types.isSignatureAssignable(idealMatch, targetMatch, round) && ((bestMatch == null) || Types.isSignatureAssignable(targetMatch, bestMatch, Types.JAVA_BASE_ASSIGNABLE))) { bestMatch = targetMatch; bestMatchIndex = i;
private static boolean isSignatureVarargsAssignable( Class<?>[] from, Class<?>[] to ) { if ( to.length == 0 || to.length > from.length + 1 ) return false; int last = to.length - 1; if ( to[last] == null || !to[last].isArray() ) return false; if ( from.length == to.length && from[last] != null && from[last].isArray() && !isJavaAssignable(to[last].getComponentType(), from[last].getComponentType()) ) return false; if ( from.length >= to.length && from[last] != null && !from[last].isArray() ) for ( int i = last; i < from.length; i++ ) if ( !isJavaAssignable(to[last].getComponentType(), from[i]) ) return false; for ( int i = 0; i < last; i++ ) if ( !isJavaAssignable(to[i], from[i]) ) return false; return true; }
boolean found = false; for ( Class<?> cType: mc.getTypes() ) if ( true == ( found = Types.isBshAssignable(cType, thrownType) ) ) { mcType = cType; break;
&& Types.areSignaturesEqual( method.getParameterTypes(), m.getParameterTypes()))
if ( !isJavaBaseAssignable( to[i], from[i] ) ) return false; return true; case JAVA_BOX_TYPES_ASSIGABLE: for( int i=0; i<from.length; i++ ) if ( !isJavaBoxTypesAssignable( to[i], from[i] ) ) return false; return true; case JAVA_VARARGS_ASSIGNABLE: return isSignatureVarargsAssignable( from, to ); case BSH_ASSIGNABLE: for( int i=0; i<from.length; i++ ) if ( !isBshAssignable( to[i], from[i] ) ) return false; return true;