You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Tom Tobin (JIRA)" <ji...@apache.org> on 2015/05/27 14:32:18 UTC

[jira] [Created] (GROOVY-7437) Support comparison between numbers and strings

Tom Tobin created GROOVY-7437:
---------------------------------

             Summary: Support comparison between numbers and strings
                 Key: GROOVY-7437
                 URL: https://issues.apache.org/jira/browse/GROOVY-7437
             Project: Groovy
          Issue Type: Bug
          Components: groovy-jdk
    Affects Versions: 2.4.3
         Environment: Linux/Windows
            Reporter: Tom Tobin
            Assignee: Guillaume Laforge
            Priority: Critical


Would like logical comparison of numbers and strings, e.g.  123.45f > "300.0".  Same applies to equality and both directions: "123.45" == 123.45d.

Successful with other operators (plus, minus..) because operator overloading works.  It does not work with comparison operators because DefaultTypeTransformations.java tries to do a smart compare but ignores operator overloading (that's why marking as bug vs enhancement).

Simple fix is to add string compares if the string is a number in DefaultTypeTransformations:compareToWithEqualityCheck() (example below).  More complete fix would be that plus respect operator overloading of compareTo() and equals().   I would also like to do special handling (e.g. 3rd party data sometimes in form 00012345 and would love for 0.34 > "30%" to work) - could do that if operator overloading worked.

in DefaultTypeTransformations.java:
    private static int compareToWithEqualityCheck(Object left, Object right, boolean equalityCheckOnly) {
        if (left == right) {
            return 0;
        }
        if (left == null) {
            return -1;
        }
        else if (right == null) {
            return 1;
        }
        if (left instanceof Comparable) {
            if (left instanceof Number) {
                if (right instanceof Character || right instanceof Number) {
                    return DefaultGroovyMethods.compareTo((Number) left, castToNumber(right));
                }
                if (isValidCharacterString(right)) {
                    return DefaultGroovyMethods.compareTo((Number) left, ShortTypeHandling.castToChar(right));
                }
// ********* SNIP *********
                if (right instanceof String) {
                    Number rightNumber = convertToNumber(left.getClass(), (String)right);
                    if (rightNumber != null) {
                        return DefaultGroovyMethods.compareTo((Number) left, rightNumber);
                    }
                }
// ********* SNIP *********
            }
            else if (left instanceof Character) {
                if (isValidCharacterString(right)) {
                    return DefaultGroovyMethods.compareTo((Character)left, ShortTypeHandling.castToChar(right));
                }
                if (right instanceof Number) {
                    return DefaultGroovyMethods.compareTo((Character)left,(Number)right);
                }
            }
            else if (right instanceof Number) {
                if (isValidCharacterString(left)) {
                    return DefaultGroovyMethods.compareTo(ShortTypeHandling.castToChar(left),(Number) right);
                }
// ********* SNIP *********
                if (left instanceof String) {
                    Number number = convertToNumber(right.getClass(), (String)left);
                    if (number != null) {
                        return DefaultGroovyMethods.compareTo(number, (Number) right);
                    }
                }
// ********* SNIP *********
            }
            else if (left instanceof String && right instanceof Character) {
                return ((String) left).compareTo(right.toString());
            }
            else if (left instanceof String && right instanceof GString) {
                return ((String) left).compareTo(right.toString());
            }
            if (!equalityCheckOnly || left.getClass().isAssignableFrom(right.getClass())
                    || (right.getClass() != Object.class && right.getClass().isAssignableFrom(left.getClass())) //GROOVY-4046
                    || (left instanceof GString && right instanceof String)) {
                Comparable comparable = (Comparable) left;
                return comparable.compareTo(right);
            }
        }

        if (equalityCheckOnly) {
            return -1; // anything other than 0
        }
        throw new GroovyRuntimeException(
                MessageFormat.format("Cannot compare {0} with value ''{1}'' and {2} with value ''{3}''",
                        left.getClass().getName(),
                        left,
                        right.getClass().getName(),
                        right));
    }

// ********* SNIP *********
    private static Number convertToNumber(Class numberClass, String string) {

        Number number = null;

        try {
            // attempt convert string to number - could be more elegant, like org.apache.commons.lang3.math.NumberUtils.createNumber()
            if (numberClass.equals(Integer.class)) {
                number = Integer.parseInt(string);
            } else if (numberClass.equals(Long.class)) {
                number = Long.parseLong(string);
            } else if (numberClass.equals(Float.class)) {
                number = Float.parseFloat(string);
            } else if (numberClass.equals(Double.class)) {
                number = Double.parseDouble(string);
            } else if (numberClass.equals(BigInteger.class)) {
                number = new BigInteger(string);
            } else if (numberClass.equals(BigDecimal.class)) {
                number = new BigDecimal(string);
            }
        } catch (NumberFormatException exception) {
            return null;
        }

        return number;
    }





--
This message was sent by Atlassian JIRA
(v6.3.4#6332)