Skip to content

Conversation

@jujn
Copy link
Contributor

@jujn jujn commented Dec 29, 2025

What this PR does / why we need it?

android5 分支

Summary of your change

Please indicate you've done the following:

  • Made sure tests are passing and test coverage is added if needed.
  • Made sure commit message follow the rule of Conventional Commits specification.
  • Considered the docs impact and opened a new docs issue or PR with docs changes if needed.

Copilot AI review requested due to automatic review settings December 29, 2025 09:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for serializing non-finite floating-point numbers (NaN, Infinity, -Infinity) as strings instead of null values. A new feature flag WriteFloatSpecialAsString is introduced to enable this behavior. When enabled, NaN is serialized as "NaN", positive infinity as "Infinity", and negative infinity as "-Infinity".

Key Changes

  • Added WriteFloatSpecialAsString feature flag to JSONWriter.Feature enum
  • Extended DoubleToDecimal.toString() methods to accept a writeSpecialAsString parameter
  • Updated float/double serialization logic in JSONWriterUTF8 and JSONWriterUTF16 to conditionally serialize special values as quoted strings

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
core/src/main/java/com/alibaba/fastjson2/JSONWriter.java Adds new WriteFloatSpecialAsString feature flag and integrates it into format handling methods
core/src/main/java/com/alibaba/fastjson2/util/DoubleToDecimal.java Extends all toString() method signatures with writeSpecialAsString parameter and implements logic to wrap NaN/Infinity in quotes when enabled
core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java Updates writeFloat(), writeDouble(), and array methods to use the new feature flag and pass it to DoubleToDecimal
core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java Updates writeFloat(), writeDouble(), writeDoubleArray(), and array methods to use the new feature flag
core/src/main/java/com/alibaba/fastjson2/util/TypeUtils.java Updates toBigDecimal() calls to pass false for the new writeSpecialAsString parameter
core/src/test/java/com/alibaba/fastjson2/features/WriteFloatSpecialAsString.java Comprehensive test suite covering UTF-8, UTF-16, arrays, reflection, and interaction with other features
core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/DoubleTest3_random.java Updates test call to include new writeSpecialAsString parameter
core/src/test/java/com/alibaba/fastjson2/util/RyuTest.java Updates test helper methods to pass false for new parameter
core/src/test/java/com/alibaba/fastjson2/util/RyuFloatTest.java Updates test helper method to pass false for new parameter
core/src/test/java/com/alibaba/fastjson2/util/RyuDoubleTest.java Updates test helper method to pass false for new parameter
core/src/test/java/com/alibaba/fastjson2/util/FloatToDecimalTest.java Updates test calls to pass false for new parameter
core/src/test/java/com/alibaba/fastjson2/util/DoubleToDecimalTest.java Updates test calls to pass false for new parameter
benchmark/src/main/java/com/alibaba/fastjson2/benchmark/fastcode/DoubleToString.java Updates benchmark methods to pass false for new parameter
Comments suppressed due to low confidence (2)

core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java:2285

  • The minCapacity calculation doesn't account for the additional space needed when writing special values as strings. When WriteFloatSpecialAsString is enabled, NaN becomes "NaN" (5 chars), Infinity becomes "Infinity" (10 chars), and negative infinity becomes "-Infinity" (11 chars). The current calculation of off + 24 may be insufficient for doubles. It should add extra capacity when writeSpecialAsString is true.
        int minCapacity = off + 24;
        if (writeAsString) {
            minCapacity += 2;
        }

core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java:2213

  • The minCapacity calculation doesn't account for the additional space needed when writing special values as strings. When WriteFloatSpecialAsString is enabled, NaN becomes "NaN" (5 chars), Infinity becomes "Infinity" (10 chars), and negative infinity becomes "-Infinity" (11 chars). The current calculation of off + 15 may be insufficient. It should add extra capacity when writeSpecialAsString is true, similar to how it's done for writeAsString.
        int minCapacity = off + 15;
        if (writeAsString) {
            minCapacity += 2;
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

boolean writeSpecialAsString = (context.features & WriteFloatSpecialAsString.mask) != 0;

int off = this.off;
int minCapacity = off + values.length * (writeAsString ? 16 : 18) + 1;
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation may be insufficient when WriteFloatSpecialAsString is enabled. The calculation uses values.length * (writeAsString ? 16 : 18) but this doesn't account for special string values which require up to 11 characters ("-Infinity"). When writeSpecialAsString is true, the capacity should be increased to accommodate the larger special strings.

Suggested change
int minCapacity = off + values.length * (writeAsString ? 16 : 18) + 1;
int perValueCapacity = writeAsString ? 16 : 18;
if (writeSpecialAsString) {
perValueCapacity += 4; // additional space for special values like "-Infinity"
}
int minCapacity = off + values.length * perValueCapacity + 1;

Copilot uses AI. Check for mistakes.
boolean writeSpecialAsString = (context.features & WriteFloatSpecialAsString.mask) != 0;

int off = this.off;
int minCapacity = off + values.length * 27 + 1;
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation may be insufficient when WriteFloatSpecialAsString is enabled. The calculation uses values.length * 27 but this doesn't account for special string values which require up to 11 characters ("-Infinity"). When writeSpecialAsString is true, the capacity should be increased to accommodate the larger special strings.

Suggested change
int minCapacity = off + values.length * 27 + 1;
int charsPerValue = 27;
if (writeSpecialAsString) {
// Allow extra space for special string representations like "-Infinity"
charsPerValue += 11;
}
int minCapacity = off + values.length * charsPerValue + 1;

Copilot uses AI. Check for mistakes.
boolean writeSpecialAsString = (context.features & WriteFloatSpecialAsString.mask) != 0;

int off = this.off;
int minCapacity = off + values.length * 27 + 1;
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation may be insufficient when WriteFloatSpecialAsString is enabled. The calculation uses values.length * 27 but this doesn't account for special string values which require up to 11 bytes ("-Infinity"). When writeSpecialAsString is true, the capacity should be increased to accommodate the larger special strings.

Suggested change
int minCapacity = off + values.length * 27 + 1;
int charsPerValue = 27;
if (writeAsString || writeSpecialAsString) {
charsPerValue = 32;
}
int minCapacity = off + values.length * charsPerValue + 1;

Copilot uses AI. Check for mistakes.
WriterUtilDateAsMillis(1L << 44),

/**
* Feature that determines whether to write float/double NaN and Infinite values as Strings.
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment mentions "Infinite" but should say "Infinity" to match the actual serialized values ("Infinity" and "-Infinity") produced by the implementation.

Suggested change
* Feature that determines whether to write float/double NaN and Infinite values as Strings.
* Feature that determines whether to write float/double NaN and Infinity values as Strings.

Copilot uses AI. Check for mistakes.
* @since 2.0.54
*/
PrettyFormatWith4Space(1L << 43),

Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WriterUtilDateAsMillis feature on line 2154 is missing documentation. For consistency with other features in the enum, it should have a JavaDoc comment explaining its purpose and including a @SInCE tag.

Suggested change
/**
* Feature that determines whether {@link java.util.Date} values are written
* as milliseconds from the epoch instead of using the default date format.
* @since 2.0.60
*/

Copilot uses AI. Check for mistakes.
if (writeAsString) {
minCapacity += 2;
minCapacity += 4;
}
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation may be insufficient when WriteFloatSpecialAsString is enabled. The calculation assumes 48 chars for two doubles, but with special values as strings, "-Infinity" requires 11 characters. The capacity should account for the maximum special string length when writeSpecialAsString is true.

Suggested change
}
}
if (writeSpecialAsString) {
// Account for maximum length of special double string representations (e.g., "-Infinity")
// for both elements in the array.
minCapacity += 22; // 2 * 11
}

Copilot uses AI. Check for mistakes.
}

int off = this.off;
int minCapacity = off + 17;
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation doesn't account for the additional space needed when writing special values as strings. When WriteFloatSpecialAsString is enabled, "-Infinity" requires 11 bytes with quotes. The current calculation of off + 17 may be insufficient. It should account for the maximum special string length when writeSpecialAsString is true.

Suggested change
int minCapacity = off + 17;
int additionalCapacity = 17;
if (writeSpecialAsString) {
// Ensure enough space for the longest special float string representation (e.g. "-Infinity")
// including potential surrounding quotes when written as a string.
additionalCapacity = 21;
}
int minCapacity = off + additionalCapacity;

Copilot uses AI. Check for mistakes.
Comment on lines 2239 to 2240
int off = this.off;
int minCapacity = off + 26;
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation doesn't account for the additional space needed when writing special values as strings. When WriteFloatSpecialAsString is enabled, "-Infinity" requires 11 bytes with quotes. The current calculation of off + 26 may be insufficient for doubles. It should account for the maximum special string length when writeSpecialAsString is true.

Copilot uses AI. Check for mistakes.
boolean writeSpecialAsString = (context.features & WriteFloatSpecialAsString.mask) != 0;

int off = this.off;
int minCapacity = off + values.length * (writeAsString ? 16 : 18) + 1;
Copy link

Copilot AI Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minCapacity calculation may be insufficient when WriteFloatSpecialAsString is enabled. The calculation uses values.length * (writeAsString ? 16 : 18) but this doesn't account for special string values which require up to 11 bytes ("-Infinity"). When writeSpecialAsString is true, the capacity should be increased to accommodate the larger special strings.

Suggested change
int minCapacity = off + values.length * (writeAsString ? 16 : 18) + 1;
int perValueCapacity = writeAsString ? 16 : 18;
if (writeSpecialAsString && perValueCapacity < 11) {
// Ensure enough space for special values like "-Infinity" (up to 11 bytes)
perValueCapacity = 11;
}
int minCapacity = off + values.length * perValueCapacity + 1;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant