public static Object coerceNumber(Object value) { return EvalHelper.coerceNumber(value); }
public static Object coerceNumber(Object value) { if ( value instanceof Number && !(value instanceof BigDecimal) ) { return getBigDecimalOrNull( value ); } else { return value; } }
public boolean isDefined( String symbol ) { symbol = EvalHelper.normalizeVariableName( symbol ); return functions.containsKey( symbol ); }
/** * Compares left and right for equality applying FEEL semantics to specific data types * * @param left * @param right * @param ctx * @return */ public static Boolean isEqual(Object left, Object right, EvaluationContext ctx ) { if ( left == null || right == null ) { return left == right; } // spec defines that "a=[a]", i.e., singleton collections should be treated as the single element // and vice-versa if( left instanceof Collection && !(right instanceof Collection) && ((Collection)left).size() == 1 ) { left = ((Collection)left).toArray()[0]; } else if( right instanceof Collection && !(left instanceof Collection) && ((Collection)right).size()==1 ) { right = ((Collection) right).toArray()[0]; } if( left instanceof Range && right instanceof Range ) { return isEqual( (Range)left, (Range) right ); } else if( left instanceof Iterable && right instanceof Iterable ) { return isEqual( (Iterable)left, (Iterable) right ); } else if( left instanceof Map && right instanceof Map ) { return isEqual( (Map)left, (Map) right ); } return compare( left, right, ctx, (l, r) -> l.compareTo( r ) == 0 ); }
@Override public boolean isDefined(String symbol) { symbol = EvalHelper.normalizeVariableName( symbol ); if (rootObject != null) { if (EvalHelper.getDefinedValue(rootObject, symbol).isDefined()) { return true; } else { // do nothing! it might be shaded at this level for "item" or being in the parent frame. } } if ( variables.containsKey( symbol ) ) { return true; } if ( parentFrame != null ) { return parentFrame.isDefined( symbol ); } return false; }
Method getter = getGenericAccessor( current.getClass(), property ); if ( getter != null ) { try { result = coerceNumber(result);
@Override public Object evaluate(EvaluationContext ctx) { Object current = parts.get( 0 ).evaluate( ctx ); try { if ( current != null ) { for ( int i = 1; i < parts.size(); i++ ) { String n = parts.get( i ).getText(); if ( current instanceof Collection ) { // e.g.: FEEL: MyList.property1 // can't use Stream API as from EvalHelper.getValue I need to listen for checked exception Collection<Object> result = new ArrayList<>(); for ( Object e : (Collection<?>) current ) { result.add( EvalHelper.getValue( e, EvalHelper.normalizeVariableName( n ) ) ); } current = result; } else { current = EvalHelper.getValue( current, EvalHelper.normalizeVariableName( n ) ); } } return current; } } catch ( Exception e ) { ctx.notifyEvt( astEvent(Severity.ERROR, Msg.createMessage(Msg.ERROR_ACCESSING_QUALIFIED_NAME, getText()), e) ); return null; } return null; }
/** * FEEL spec Table 42 and derivations * Delegates to {@link EvalHelper} except evaluationcontext */ public static Boolean lte(Object left, Object right) { return EvalHelper.compare(left, right, null, (l, r) -> l.compareTo(r) <= 0); }
public static Object and(boolean left, Object right) { if (left == true) { return EvalHelper.getBooleanOrNull(right); } else { return false; } }
private Object fetchValue(final Object o, final String... names) { Object result = o; for (String nr : names) { result = EvalHelper.getDefinedValue(result, nr) .getValueResult() .cata(err -> { // no need to report error here, eg: [ {x:1, y:2}, {x:2} ].y results in [2] with no errors. return null; }, Function.identity()); } return result; } }
public static Expression getKey(Expression currentContext, CompositeType contextType, String key) { if (contextType instanceof MapBackedType) { EnclosedExpr enclosedExpr = Expressions.castTo(MapT, currentContext); return new MethodCallExpr(enclosedExpr, "get") .addArgument(new StringLiteralExpr(key)); } else if (contextType instanceof JavaBackedType) { JavaBackedType javaBackedType = (JavaBackedType) contextType; Class<?> wrappedType = javaBackedType.getWrapped(); Method accessor = EvalHelper.getGenericAccessor(wrappedType, key); Type type = JavaParser.parseType(wrappedType.getCanonicalName()); return new MethodCallExpr(Expressions.castTo(type, currentContext), accessor.getName()); } else { throw new UnsupportedOperationException("A Composite type is either MapBacked or JavaBAcked"); } } }
/** * FEEL annotated or else Java accessor. * @param clazz * @param field * @return */ public static Method getGenericAccessor(Class<?> clazz, String field) { LOG.trace( "getGenericAccessor({}, {})", clazz, field ); String accessorQualifiedName = new StringBuilder(clazz.getCanonicalName()) .append(".").append(field).toString(); return accessorCache.computeIfAbsent(accessorQualifiedName, key -> Stream.of( clazz.getMethods() ) .filter( m -> Optional.ofNullable( m.getAnnotation( FEELProperty.class ) ) .map( ann -> ann.value().equals( field ) ) .orElse( false ) ) .findFirst() .orElse( getAccessor( clazz, field ) )); }
private Object fetchValue(Object o) throws IllegalAccessException, InvocationTargetException { if ( name instanceof NameRefNode ) { o = EvalHelper.getValue( o, name.getText() ); } else if ( name instanceof QualifiedNameNode ) { for ( NameRefNode nr : ((QualifiedNameNode) name).getParts() ) { o = EvalHelper.getValue( o, nr.getText() ); } } return o; }
@Override public Object getValue(String symbol) { symbol = EvalHelper.normalizeVariableName( symbol ); if (rootObject != null) { PropertyValueResult dv = EvalHelper.getDefinedValue(rootObject, symbol); if (dv.isDefined()) { return dv.getValueResult().getOrElse(null); } } if ( variables.containsKey( symbol ) ) { return variables.get( symbol ); } if ( parentFrame != null ) { return parentFrame.getValue( symbol ); } return null; }
return or( left, right, ctx ); case LTE: return EvalHelper.compare( left, right, ctx, (l, r) -> l.compareTo( r ) <= 0 ); case LT: return EvalHelper.compare( left, right, ctx, (l, r) -> l.compareTo( r ) < 0 ); case GT: return EvalHelper.compare( left, right, ctx, (l, r) -> l.compareTo( r ) > 0 ); case GTE: return EvalHelper.compare( left, right, ctx, (l, r) -> l.compareTo( r ) >= 0 ); case EQ: return EvalHelper.isEqual( left, right, ctx ); case NE: Boolean result = EvalHelper.isEqual( left, right, ctx ); return result != null ? ! result : null; default:
/** * FEEL spec Table 42 and derivations * Delegates to {@link EvalHelper} except evaluationcontext */ public static Boolean gte(Object left, Object right) { return EvalHelper.compare(left, right, null, (l, r) -> l.compareTo(r) >= 0); }
public static Object or(Object left, boolean right) { if (right == true) { return true; } else { return EvalHelper.getBooleanOrNull(left); } }
/** * {@link #getDefinedValue(Object, String)} method instead. * @deprecated this method cannot distinguish null because: 1. property undefined for current, 2. an error, 3. a properly defined property value valorized to null. * */ public static Object getValue(final Object current, final String property) { return getDefinedValue(current, property).getValueResult().getOrElse(null); }
} else if (compositeType instanceof JavaBackedType) { JavaBackedType javaBackedType = (JavaBackedType) compositeType; Method accessor = EvalHelper.getGenericAccessor(javaBackedType.getWrapped(), accText); CastExpr castExpr = new CastExpr(JavaParser.parseType(javaBackedType.getWrapped().getCanonicalName()), exprCursor); EnclosedExpr enclosedExpr = new EnclosedExpr(castExpr);
private Object normalizeResult(Object result) { // this is to normalize types returned by external functions return result != null && result instanceof Number && !(result instanceof BigDecimal) ? EvalHelper.getBigDecimalOrNull( result.toString() ) : result; }