Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/JSONFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public static String getProperty(String key) {
static String defaultWriterFormat;
static ZoneId defaultWriterZoneId;
static boolean defaultWriterAlphabetic;
static boolean defaultWriterPrettyFormatInlineArrays;
static boolean defaultSkipTransient;
static final boolean disableReferenceDetect;
static final boolean disableArrayMapping;
Expand Down Expand Up @@ -760,6 +761,26 @@ public static void setDefaultWriterAlphabetic(boolean defaultWriterAlphabetic) {
defaultObjectWriterProvider.setAlphabetic(defaultWriterAlphabetic);
}

/**
* Checks if the default writer uses inline arrays when pretty formatting.
*
* @return true if inline arrays is enabled, false otherwise
* @since 2.0.61
*/
public static boolean isDefaultWriterPrettyFormatInlineArrays() {
return defaultWriterPrettyFormatInlineArrays;
}

/**
* Sets whether the default writer should use inline arrays when pretty formatting.
*
* @param inlineArrays true to enable inline arrays, false to disable
* @since 2.0.61
*/
public static void setDefaultWriterPrettyFormatInlineArrays(boolean inlineArrays) {
JSONFactory.defaultWriterPrettyFormatInlineArrays = inlineArrays;
}

/**
* Checks if reference detection is disabled.
*
Expand Down
62 changes: 62 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/JSONWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public abstract class JSONWriter
implements Closeable {
static final long WRITE_ARRAY_NULL_MASK = NullAsDefaultValue.mask | WriteNullListAsEmpty.mask;
static final byte PRETTY_NON = 0, PRETTY_TAB = 1, PRETTY_2_SPACE = 2, PRETTY_4_SPACE = 4;
static final int PRETTY_INLINE_ARRAY_MAX_LENGTH = 5;
static final long NONE_DIRECT_FEATURES = ReferenceDetection.mask | NotWriteEmptyArray.mask | NotWriteDefaultValue.mask;

public final Context context;
Expand All @@ -84,12 +85,22 @@ public abstract class JSONWriter

protected boolean startObject;
protected int level;
/**
* Bitmask tracking which nesting levels are arrays (vs objects).
* Bit N is set if level N is an array context.
*/
protected long levelArray;
protected int off;
protected Object rootObject;
protected IdentityHashMap<Object, Path> refs;
protected Path path;
protected String lastReference;
protected byte pretty;
/**
* When true and pretty formatting is enabled, arrays are written inline
* (on a single line) rather than with line breaks between elements.
*/
protected boolean prettyInlineArrays;
protected Object attachment;

protected JSONWriter(
Expand Down Expand Up @@ -119,6 +130,7 @@ protected JSONWriter(
} else {
pretty = PRETTY_NON;
}
prettyInlineArrays = context.prettyFormatInlineArrays;
}

/**
Expand Down Expand Up @@ -1793,6 +1805,10 @@ public void writeInt16(short[] value) {
writeArrayNull();
return;
}
boolean savedInline = prettyInlineArrays;
if (pretty != PRETTY_NON && !prettyInlineArrays && value.length < PRETTY_INLINE_ARRAY_MAX_LENGTH) {
prettyInlineArrays = true;
}
startArray();
for (int i = 0; i < value.length; i++) {
if (i != 0) {
Expand All @@ -1801,6 +1817,7 @@ public void writeInt16(short[] value) {
writeInt16(value[i]);
}
endArray();
prettyInlineArrays = savedInline;
}

/**
Expand Down Expand Up @@ -1968,6 +1985,10 @@ public final void writeFloat(float[] value, DecimalFormat format) {
return;
}

boolean savedInline = prettyInlineArrays;
if (pretty != PRETTY_NON && !prettyInlineArrays && value.length < PRETTY_INLINE_ARRAY_MAX_LENGTH) {
prettyInlineArrays = true;
}
startArray();
for (int i = 0; i < value.length; i++) {
if (i != 0) {
Expand All @@ -1985,6 +2006,7 @@ public final void writeFloat(float[] value, DecimalFormat format) {
writeRaw(str);
}
endArray();
prettyInlineArrays = savedInline;
}

/**
Expand Down Expand Up @@ -2042,11 +2064,16 @@ public final void writeDouble(double value, DecimalFormat format) {
* @param value1 the second double value to write
*/
public void writeDoubleArray(double value0, double value1) {
boolean savedInline = prettyInlineArrays;
if (pretty != PRETTY_NON && !prettyInlineArrays) {
prettyInlineArrays = true;
}
startArray();
writeDouble(value0);
writeComma();
writeDouble(value1);
endArray();
prettyInlineArrays = savedInline;
}

/**
Expand All @@ -2067,6 +2094,10 @@ public final void writeDouble(double[] value, DecimalFormat format) {
return;
}

boolean savedInline = prettyInlineArrays;
if (pretty != PRETTY_NON && !prettyInlineArrays && value.length < PRETTY_INLINE_ARRAY_MAX_LENGTH) {
prettyInlineArrays = true;
}
startArray();
for (int i = 0; i < value.length; i++) {
if (i != 0) {
Expand All @@ -2084,6 +2115,7 @@ public final void writeDouble(double[] value, DecimalFormat format) {
writeRaw(str);
}
endArray();
prettyInlineArrays = savedInline;
}

/**
Expand Down Expand Up @@ -2113,6 +2145,10 @@ public void writeBool(boolean[] value) {
return;
}

boolean savedInline = prettyInlineArrays;
if (pretty != PRETTY_NON && !prettyInlineArrays && value.length < PRETTY_INLINE_ARRAY_MAX_LENGTH) {
prettyInlineArrays = true;
}
startArray();
for (int i = 0; i < value.length; i++) {
if (i != 0) {
Expand All @@ -2121,6 +2157,7 @@ public void writeBool(boolean[] value) {
writeBool(value[i]);
}
endArray();
prettyInlineArrays = savedInline;
}

/**
Expand Down Expand Up @@ -3251,6 +3288,7 @@ public static final class Context {
LabelFilter labelFilter;
ContextValueFilter contextValueFilter;
ContextNameFilter contextNameFilter;
boolean prettyFormatInlineArrays;

/**
* Creates a new Context with the specified object writer provider.
Expand All @@ -3267,6 +3305,7 @@ public Context(ObjectWriterProvider provider) {
this.provider = provider;
this.zoneId = defaultWriterZoneId;
this.maxLevel = defaultMaxLevel;
this.prettyFormatInlineArrays = JSONFactory.defaultWriterPrettyFormatInlineArrays;

String format = defaultWriterFormat;
if (format != null) {
Expand All @@ -3284,6 +3323,7 @@ public Context(Feature... features) {
this.provider = getDefaultObjectWriterProvider();
this.zoneId = defaultWriterZoneId;
this.maxLevel = defaultMaxLevel;
this.prettyFormatInlineArrays = JSONFactory.defaultWriterPrettyFormatInlineArrays;

String format = defaultWriterFormat;
if (format != null) {
Expand All @@ -3306,6 +3346,7 @@ public Context(String format, Feature... features) {
this.provider = getDefaultObjectWriterProvider();
this.zoneId = defaultWriterZoneId;
this.maxLevel = defaultMaxLevel;
this.prettyFormatInlineArrays = JSONFactory.defaultWriterPrettyFormatInlineArrays;

for (int i = 0; i < features.length; i++) {
this.features |= features[i].mask;
Expand Down Expand Up @@ -3335,6 +3376,7 @@ public Context(ObjectWriterProvider provider, Feature... features) {
this.provider = provider;
this.zoneId = defaultWriterZoneId;
this.maxLevel = defaultMaxLevel;
this.prettyFormatInlineArrays = JSONFactory.defaultWriterPrettyFormatInlineArrays;

for (int i = 0; i < features.length; i++) {
this.features |= features[i].mask;
Expand Down Expand Up @@ -3878,6 +3920,26 @@ public int getMaxLevel() {
public void setMaxLevel(int maxLevel) {
this.maxLevel = maxLevel;
}

/**
* Checks if inline arrays is enabled for pretty formatting.
*
* @return true if inline arrays is enabled, false otherwise
* @since 2.0.61
*/
public boolean isPrettyFormatInlineArrays() {
return prettyFormatInlineArrays;
}

/**
* Sets whether to use inline arrays when pretty formatting.
*
* @param prettyFormatInlineArrays true to enable inline arrays, false to disable
* @since 2.0.61
*/
public void setPrettyFormatInlineArrays(boolean prettyFormatInlineArrays) {
this.prettyFormatInlineArrays = prettyFormatInlineArrays;
}
}

public static final long MASK_FIELD_BASED = 1;
Expand Down
74 changes: 71 additions & 3 deletions core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ public final void writeComma() {

chars[off++] = (byte) ',';
if (pretty != PRETTY_NON) {
off = indent(chars, off);
// Check if we're in an array context with inline arrays enabled
boolean inArrayContext = (levelArray & (1L << level)) != 0;
if (!(prettyInlineArrays && inArrayContext)) {
off = indent(chars, off);
}
}
this.off = off;
}
Expand All @@ -198,6 +202,8 @@ public final void startArray() {
if (++level > context.maxLevel) {
overflowLevel();
}
// Mark current level as array context
levelArray |= (1L << level);

int off = this.off;
int minCapacity = off + 3 + pretty * level;
Expand All @@ -207,14 +213,16 @@ public final void startArray() {
}

chars[off++] = (byte) '[';
if (pretty != PRETTY_NON) {
if (pretty != PRETTY_NON && !prettyInlineArrays) {
off = indent(chars, off);
}
this.off = off;
}

@Override
public final void endArray() {
// Clear array context for current level before decrementing
levelArray &= ~(1L << level);
level--;
int off = this.off;
int minCapacity = off + 1 + (pretty == 0 ? 0 : pretty * level + 1);
Expand All @@ -223,7 +231,7 @@ public final void endArray() {
chars = grow(minCapacity);
}

if (pretty != PRETTY_NON) {
if (pretty != PRETTY_NON && !prettyInlineArrays) {
off = indent(chars, off);
}
chars[off] = (byte) ']';
Expand Down Expand Up @@ -1747,6 +1755,18 @@ public final void writeInt32(int[] value) {
return;
}

if (pretty != PRETTY_NON && !prettyInlineArrays && value.length >= PRETTY_INLINE_ARRAY_MAX_LENGTH) {
startArray();
for (int i = 0; i < value.length; i++) {
if (i != 0) {
writeComma();
}
writeInt32(value[i]);
}
endArray();
return;
}

boolean writeAsString = (context.features & WriteNonStringValueAsString.mask) != 0;

int off = this.off;
Expand Down Expand Up @@ -1802,6 +1822,18 @@ public final void writeInt8(byte[] value) {
return;
}

if (pretty != PRETTY_NON && !prettyInlineArrays && value.length >= PRETTY_INLINE_ARRAY_MAX_LENGTH) {
startArray();
for (int i = 0; i < value.length; i++) {
if (i != 0) {
writeComma();
}
writeInt8(value[i]);
}
endArray();
return;
}

boolean writeAsString = (context.features & WriteNonStringValueAsString.mask) != 0;

int off = this.off;
Expand Down Expand Up @@ -1888,6 +1920,18 @@ public final void writeInt64(long[] values) {
return;
}

if (pretty != PRETTY_NON && !prettyInlineArrays && values.length >= PRETTY_INLINE_ARRAY_MAX_LENGTH) {
startArray();
for (int i = 0; i < values.length; i++) {
if (i != 0) {
writeComma();
}
writeInt64(values[i]);
}
endArray();
return;
}

int off = this.off;
int minCapacity = off + 2 + values.length * 23;
char[] chars = this.chars;
Expand Down Expand Up @@ -2081,6 +2125,18 @@ public final void writeFloat(float[] values) {
return;
}

if (pretty != PRETTY_NON && !prettyInlineArrays && values.length >= PRETTY_INLINE_ARRAY_MAX_LENGTH) {
startArray();
for (int i = 0; i < values.length; i++) {
if (i != 0) {
writeComma();
}
writeFloat(values[i]);
}
endArray();
return;
}

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

Expand Down Expand Up @@ -2200,6 +2256,18 @@ public final void writeDouble(double[] values) {
return;
}

if (pretty != PRETTY_NON && !prettyInlineArrays && values.length >= PRETTY_INLINE_ARRAY_MAX_LENGTH) {
startArray();
for (int i = 0; i < values.length; i++) {
if (i != 0) {
writeComma();
}
writeDouble(values[i]);
}
endArray();
return;
}

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

Expand Down
Loading
Loading