{"record":{"id":"c9204348a6f4617a","repo":"apache/dubbo","slug":"number-expected-to-be-long-d","errorCode":null,"errorMessage":"Number expected to be long: ${d}","messagePattern":"Number expected to be long: (.+?)","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/AbstractJsonUtilImpl.java","lineNumber":185,"sourceCode":"\n    /**\n     * Gets a number from an object for the given key, casted to an long.  If the key is not\n     * present, this returns null.  If the value does not represent a long integer, throws an\n     * exception.\n     */\n    @Override\n    public Long getNumberAsLong(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (value instanceof Double) {\n            Double d = (Double) value;\n            long l = d.longValue();\n            if (l != d) {\n                throw new ClassCastException(\"Number expected to be long: \" + d);\n            }\n            return l;\n        }\n        if (value instanceof String) {\n            try {\n                return Long.parseLong((String) value);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\n                        String.format(\"value '%s' for key '%s' is not a long integer\", value, key));\n            }\n        }\n        throw new IllegalArgumentException(String.format(\"value '%s' for key '%s' is not a long integer\", value, key));\n    }\n\n    /**\n     * Gets a string from an object for the given key.  If the key is not present, this returns null.\n     * If the value is not a String, throws an exception.\n     */","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/AbstractJsonUtilImpl.java#L167-L203","documentation":"Thrown by AbstractJsonUtilImpl.getNumberAsLong(Map,String) when obj contains key, the value is a Double, but the long cast loses precision — i.e. d.longValue() != d. This guards against silently truncating a fractional Double (e.g. 3.5) into a long. It is a ClassCastException naming the offending Double. Only the Double branch reaches it; String values go through Long.parseLong.","triggerScenarios":"jsonUtil.getNumberAsLong(obj, key) where obj.get(key) is a Double with a non-zero fractional part (e.g. 1.5, 99.9). Whole-valued doubles pass; anything off-integer throws.","commonSituations":"A field that is usually a count (integral) but occasionally a ratio/average; floating accumulation error turning 5 into 5.0000001; a Double-typed upstream widened from a fractional source; an ID/timestamp mistakenly encoded with a decimal portion.","solutions":["If truncation/rounding is acceptable, pre-round: Math.round(d) before reading.","If the fractional value is a data error, fix the producer to emit whole numbers.","Switch to getNumberAsDouble if the field is genuinely non-integral.","Catch ClassCastException and treat as a validation error."],"exampleFix":"// before\nLong id = jsonUtil.getNumberAsLong(obj, \"id\"); // id = 42.7\n// after - round then read\nObject raw = obj.get(\"id\");\nLong id = raw instanceof Double ? Math.round((Double) raw) : jsonUtil.getNumberAsLong(obj, \"id\");","handlingStrategy":"type-guard","validationCode":"Object raw = obj.get(key);\nif (raw instanceof Double) {\n    double d = (Double) raw;\n    if (d != Math.rint(d)) {\n        return Math.round(d); // round before reading as long\n    }\n}\nreturn jsonUtil.getNumberAsLong(obj, key);","typeGuard":"private static boolean isWholeDouble(Object value) {\n    if (!(value instanceof Double)) return value instanceof String;\n    double d = (Double) value;\n    return d == Math.rint(d);\n}","tryCatchPattern":"try {\n    return jsonUtil.getNumberAsLong(obj, key);\n} catch (ClassCastException e) {\n    Object raw = obj.get(key);\n    if (raw instanceof Double) return Math.round((Double) raw); // recover\n    throw e;\n}","preventionTips":["Round fractional Doubles before reading them as long.","Watch for floating accumulation error on IDs/timestamps.","If the field is genuinely fractional, use getNumberAsDouble instead."],"tags":["json","number-parsing","classcast","precision","jsonutil","dubbo-common"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}