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)