apache/dubbo · error · ClassCastException

Number expected to be integer: ${d}

Error message

Number expected to be integer: ${d}

What it means

Thrown by AbstractJsonUtilImpl.getNumberAsInteger(Map,String) when obj contains key, the value is a Double, but its integral cast loses precision — i.e. d.intValue() != d. This guards against silently truncating a fractional value like 3.14 into 3. It is a ClassCastException (a type-shape mismatch) naming the offending Double. Only the Double branch can reach it; String values go through Integer.parseInt.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/AbstractJsonUtilImpl.java:153

    }

    /**
     * Gets a number from an object for the given key, casted to an integer.  If the key is not
     * present, this returns null.  If the value does not represent an integer, throws an exception.
     */
    @Override
    public Integer getNumberAsInteger(Map<String, ?> obj, String key) {
        assert obj != null;
        assert key != null;
        if (!obj.containsKey(key)) {
            return null;
        }
        Object value = obj.get(key);
        if (value instanceof Double) {
            Double d = (Double) value;
            int i = d.intValue();
            if (i != d) {
                throw new ClassCastException("Number expected to be integer: " + d);
            }
            return i;
        }
        if (value instanceof String) {
            try {
                return Integer.parseInt((String) value);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException(
                        String.format("value '%s' for key '%s' is not an integer", value, key));
            }
        }
        throw new IllegalArgumentException(String.format("value '%s' for key '%s' is not an integer", value, key));
    }

    /**
     * Gets a number from an object for the given key, casted to an long.  If the key is not
     * present, this returns null.  If the value does not represent a long integer, throws an
     * exception.

View on GitHub (pinned to 3a3043227f)

Solutions

  1. If a fractional value is a data error, fix the upstream producer to emit whole numbers.
  2. If truncation/rounding is acceptable, pre-round the Double: Math.round(d) or (int) Math.rint(d), then call getNumberAsInteger or read it directly.
  3. Switch to getNumberAsDouble if the field is genuinely non-integral.
  4. Catch ClassCastException and treat fractional values as a validation error.

Example fix

// before
Integer n = jsonUtil.getNumberAsInteger(obj, "qty"); // qty = 3.7
// after - round explicitly
Object raw = obj.get("qty");
Integer n = (raw instanceof Double) ? (int) Math.round((Double) raw) : jsonUtil.getNumberAsInteger(obj, "qty");
Defensive patterns

Strategy: type-guard

Validate before calling

Object raw = obj.get(key);
if (raw instanceof Double) {
    double d = (Double) raw;
    if (d != Math.rint(d)) {
        // fractional; decide rounding policy before calling getNumberAsInteger
        return (int) Math.round(d);
    }
}
return jsonUtil.getNumberAsInteger(obj, key);

Type guard

private static boolean isWholeDouble(Object value) {
    if (!(value instanceof Double)) return value instanceof String;
    double d = (Double) value;
    return d == Math.rint(d);
}

Try / catch

try {
    return jsonUtil.getNumberAsInteger(obj, key);
} catch (ClassCastException e) {
    Object raw = obj.get(key);
    if (raw instanceof Double) return (int) Math.round((Double) raw); // recover
    throw e;
}

Prevention

When it happens

Trigger: jsonUtil.getNumberAsInteger(obj, key) where obj.get(key) is a Double with a non-zero fractional part, e.g. 3.5, 1.1, -2.9. Whole-valued doubles (3.0) pass; anything off-integer throws.

Common situations: A JSON field decoded as Double (3.0-ish backend) that occasionally carries a fractional part; a ratio/percentage mistakenly read as a count; a Float-typed upstream value widened to a fractional Double; a computed value that should be integral but accumulated floating error (e.g. 4.0000001).

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/330c02d85828cea8. Report an issue: GitHub.