public CoercedExpressionResult coerce() {

        final Class<?> leftClass = left.getRawClass();
        final Class<?> nonPrimitiveLeftClass = toNonPrimitiveType(leftClass);
        final Class<?> rightClass = right.getRawClass();
        final Class<?> nonPrimitiveRightClass = toNonPrimitiveType(rightClass);

        boolean sameClass = leftClass == rightClass;
        boolean isUnificationExpression = left instanceof UnificationTypedExpression || right instanceof UnificationTypedExpression;

        if (sameClass || isUnificationExpression) {
            return new CoercedExpressionResult(left, right);
        }

        if (!canCoerce()) {
            throw new CoercedExpressionException(new InvalidExpressionErrorResult("Comparison operation requires compatible types. Found " + leftClass + " and " + rightClass));
        }

        if ((nonPrimitiveLeftClass == Integer.class || nonPrimitiveLeftClass == Long.class) && nonPrimitiveRightClass == Double.class) {
            CastExpr castExpression = new CastExpr(PrimitiveType.doubleType(), this.left.getExpression());
            return new CoercedExpressionResult(
                    new TypedExpression(castExpression, double.class, left.getType()),
                    right,
                    false);
        }

        final boolean leftIsPrimitive = leftClass.isPrimitive() || Number.class.isAssignableFrom( leftClass );
        final boolean canCoerceLiteralNumberExpr = canCoerceLiteralNumberExpr(leftClass);

        boolean rightAsStaticField = false;
        final Expression rightExpression = right.getExpression();
        final TypedExpression coercedRight;

        if (leftIsPrimitive && canCoerceLiteralNumberExpr && rightExpression instanceof LiteralStringValueExpr) {
            final Expression coercedLiteralNumberExprToType = coerceLiteralNumberExprToType((LiteralStringValueExpr) right.getExpression(), leftClass);
            coercedRight = right.cloneWithNewExpression(coercedLiteralNumberExprToType);
            coercedRight.setType( leftClass );
        } else if (shouldCoerceBToString(left, right)) {
            coercedRight = coerceToString(right);
        } else if (isNotBinaryExpression(right) && canBeNarrowed(leftClass, rightClass) && right.isNumberLiteral()) {
            coercedRight = castToClass(leftClass);
        } else if (leftClass == long.class && rightClass == int.class) {
            coercedRight = right.cloneWithNewExpression(new CastExpr(PrimitiveType.longType(), right.getExpression()));
        } else if (leftClass == Date.class && rightClass == String.class) {
            coercedRight = coerceToDate(right);
            rightAsStaticField = true;
        } else if (leftClass == LocalDate.class && rightClass == String.class) {
            coercedRight = coerceToLocalDate(right);
            rightAsStaticField = true;
        } else if (leftClass == LocalDateTime.class && rightClass == String.class) {
            coercedRight = coerceToLocalDateTime(right);
            rightAsStaticField = true;
        } else if (shouldCoerceBToMap()) {
            coercedRight = castToClass(toNonPrimitiveType(leftClass));
        } else if (isBoolean(leftClass) && !isBoolean(rightClass)) {
            coercedRight = coerceBoolean(right);
        } else {
            coercedRight = right;
        }

        final TypedExpression coercedLeft;
        if (nonPrimitiveLeftClass == Character.class && shouldCoerceBToString(right, left)) {
            coercedLeft = coerceToString(left);
        } else {
            coercedLeft = left;
        }

        return new CoercedExpressionResult(coercedLeft, coercedRight, rightAsStaticField);
    }
@Test
    public void avoidCoercingStrings() {
        final TypedExpression left = expr(THIS_PLACEHOLDER + ".getName()", String.class);
        final TypedExpression right = expr("\"50\"", String.class);
        final CoercedExpression.CoercedExpressionResult coerce = new CoercedExpression(left, right, false).coerce();
        assertThat(coerce.getCoercedRight()).isEqualTo(expr("\"50\"", String.class));
    }