fix improve feature of NullAsDefaultValue, for issue #3518

This commit is contained in:
yanxutao89 2025-04-24 22:39:05 +08:00
parent 2f1f77bd6d
commit ae093fa8fc
18 changed files with 133 additions and 43 deletions

View File

@ -1147,6 +1147,18 @@ public abstract class JSONWriter
public abstract void writeNull(); public abstract void writeNull();
public void writeObjectNull(Class<?> fieldClass) {
if ((this.context.features & (MASK_NULL_AS_DEFAULT_VALUE)) != 0) {
if (fieldClass == Character.class) {
writeString("\u0000");
} else {
writeRaw('{', '}');
}
} else {
writeNull();
}
}
public void writeStringNull() { public void writeStringNull() {
String raw; String raw;
long features = this.context.features; long features = this.context.features;
@ -1176,6 +1188,16 @@ public abstract class JSONWriter
} }
} }
public final void writeDecimalNull() {
if ((this.context.features & MASK_NULL_AS_DEFAULT_VALUE) != 0) {
writeDouble(0.0);
} else if ((this.context.features & MASK_WRITE_NULL_NUMBER_AS_ZERO) != 0) {
writeInt32(0);
} else {
writeNull();
}
}
public final void writeInt64Null() { public final void writeInt64Null() {
if ((this.context.features & (MASK_NULL_AS_DEFAULT_VALUE | MASK_WRITE_NULL_NUMBER_AS_ZERO)) != 0) { if ((this.context.features & (MASK_NULL_AS_DEFAULT_VALUE | MASK_WRITE_NULL_NUMBER_AS_ZERO)) != 0) {
writeInt64(0); writeInt64(0);

View File

@ -1045,7 +1045,7 @@ class JSONWriterUTF16
public final void writeDecimal(BigDecimal value, long features, DecimalFormat format) { public final void writeDecimal(BigDecimal value, long features, DecimalFormat format) {
if (value == null) { if (value == null) {
writeNumberNull(); writeDecimalNull();
return; return;
} }

View File

@ -2371,7 +2371,7 @@ final class JSONWriterUTF8
@Override @Override
public final void writeDecimal(BigDecimal value, long features, DecimalFormat format) { public final void writeDecimal(BigDecimal value, long features, DecimalFormat format) {
if (value == null) { if (value == null) {
writeNumberNull(); writeDecimalNull();
return; return;
} }

View File

@ -23,7 +23,7 @@ final class FieldWriterBigDecimalField<T>
BigDecimal value = (BigDecimal) getFieldValue(object); BigDecimal value = (BigDecimal) getFieldValue(object);
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
} }

View File

@ -50,7 +50,7 @@ final class FieldWriterBigDecimalFunc<T>
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
} }

View File

@ -51,7 +51,7 @@ final class FieldWriterBigDecimalMethod<T>
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
} }

View File

@ -23,7 +23,7 @@ final class FieldWriterBigIntField<T>
BigInteger value = (BigInteger) getFieldValue(object); BigInteger value = (BigInteger) getFieldValue(object);
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
} }

View File

@ -41,7 +41,7 @@ final class FieldWriterBigIntFunc<T>
BigInteger value = function.apply(o); BigInteger value = function.apply(o);
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
} }

View File

@ -58,11 +58,12 @@ final class FieldWriterDoubleFunc<T>
if (value == null) { if (value == null) {
long features = jsonWriter.getFeatures(this.features); long features = jsonWriter.getFeatures(this.features);
if ((features & JSONWriter.Feature.WriteNulls.mask) != 0 if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
&& (features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0 return false;
) { }
if ((features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0) {
writeFieldName(jsonWriter); writeFieldName(jsonWriter);
jsonWriter.writeNumberNull(); jsonWriter.writeDecimalNull();
return true; return true;
} }
return false; return false;

View File

@ -58,11 +58,12 @@ final class FieldWriterFloatFunc<T>
if (value == null) { if (value == null) {
long features = jsonWriter.getFeatures(this.features); long features = jsonWriter.getFeatures(this.features);
if ((features & JSONWriter.Feature.WriteNulls.mask) != 0 if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
&& (features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0 return false;
) { }
if ((features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0) {
writeFieldName(jsonWriter); writeFieldName(jsonWriter);
jsonWriter.writeNumberNull(); jsonWriter.writeDecimalNull();
return true; return true;
} }
return false; return false;

View File

@ -46,7 +46,7 @@ abstract class FieldWriterInt16<T>
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
writeFieldName(jsonWriter); writeFieldName(jsonWriter);

View File

@ -45,7 +45,7 @@ abstract class FieldWriterInt8<T>
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false; return false;
} }
writeFieldName(jsonWriter); writeFieldName(jsonWriter);

View File

@ -272,7 +272,10 @@ public class FieldWriterObject<T>
// (features & JSONWriter.Feature.WriteNullNumberAsZero.mask) != 0 // (features & JSONWriter.Feature.WriteNullNumberAsZero.mask) != 0
if (value == null) { if (value == null) {
if ((features & WriteNulls.mask) != 0 && (features & NotWriteDefaultValue.mask) == 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
return false;
}
if ((features & NotWriteDefaultValue.mask) == 0) {
writeFieldName(jsonWriter); writeFieldName(jsonWriter);
if (array) { if (array) {
jsonWriter.writeArrayNull(); jsonWriter.writeArrayNull();
@ -283,7 +286,7 @@ public class FieldWriterObject<T>
|| fieldClass == StringBuilder.class) { || fieldClass == StringBuilder.class) {
jsonWriter.writeStringNull(); jsonWriter.writeStringNull();
} else { } else {
jsonWriter.writeNull(); jsonWriter.writeObjectNull(fieldClass);
} }
return true; return true;
} else { } else {

View File

@ -59,20 +59,18 @@ abstract class FieldWriterObjectFinal<T>
if (value == null) { if (value == null) {
long features = this.features | jsonWriter.getFeatures(); long features = this.features | jsonWriter.getFeatures();
if ((features & JSONWriter.Feature.WriteNulls.mask) != 0) { if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
writeFieldName(jsonWriter);
if (fieldClass.isArray()) {
jsonWriter.writeArrayNull();
} else if (fieldClass == StringBuffer.class || fieldClass == StringBuilder.class) {
jsonWriter.writeStringNull();
} else {
jsonWriter.writeNull();
}
return true;
} else {
return false; return false;
} }
writeFieldName(jsonWriter);
if (fieldClass.isArray()) {
jsonWriter.writeArrayNull();
} else if (fieldClass == StringBuffer.class || fieldClass == StringBuilder.class) {
jsonWriter.writeStringNull();
} else {
jsonWriter.writeObjectNull(fieldClass);
}
return true;
} }
ObjectWriter valueWriter = getObjectWriter(jsonWriter, fieldClass); ObjectWriter valueWriter = getObjectWriter(jsonWriter, fieldClass);

View File

@ -2526,7 +2526,7 @@ public class ObjectWriterCreatorASM
// writeFieldName(w); // writeFieldName(w);
gwFieldName(mwc, fieldWriter, i); gwFieldName(mwc, fieldWriter, i);
// jw.writeNulll // jw.writeNull
mw.aload(JSON_WRITER); mw.aload(JSON_WRITER);
mw.invokevirtual(TYPE_JSON_WRITER, "writeNull", "()V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeNull", "()V");
@ -2813,6 +2813,8 @@ public class ObjectWriterCreatorASM
} else if (fieldClass == String.class) { } else if (fieldClass == String.class) {
nullFeatures |= WriteNullStringAsEmpty.mask; nullFeatures |= WriteNullStringAsEmpty.mask;
nullFeatures |= NullAsDefaultValue.mask; nullFeatures |= NullAsDefaultValue.mask;
} else {
nullFeatures |= NullAsDefaultValue.mask;
} }
mwc.genIsEnabled(nullFeatures, notNull_); mwc.genIsEnabled(nullFeatures, notNull_);
// mw.iload(mwc.var(WRITE_NULLS)); // mw.iload(mwc.var(WRITE_NULLS));
@ -2822,13 +2824,19 @@ public class ObjectWriterCreatorASM
// writeFieldName(w); // writeFieldName(w);
gwFieldName(mwc, fieldWriter, i); gwFieldName(mwc, fieldWriter, i);
// jw.writeNulll // jw.writeNull
mw.aload(JSON_WRITER);
String WRITE_NULL_METHOD; String WRITE_NULL_METHOD;
String WRITE_NULL_DESC = "()V";
if (fieldClass == AtomicLongArray.class if (fieldClass == AtomicLongArray.class
|| fieldClass == AtomicIntegerArray.class || fieldClass == AtomicIntegerArray.class
|| Collection.class.isAssignableFrom(fieldClass) || Collection.class.isAssignableFrom(fieldClass)
|| fieldClass.isArray()) { || fieldClass.isArray()) {
WRITE_NULL_METHOD = "writeArrayNull"; WRITE_NULL_METHOD = "writeArrayNull";
} else if (fieldClass == Float.class
|| fieldClass == Double.class
|| fieldClass == BigDecimal.class) {
WRITE_NULL_METHOD = "writeDecimalNull";
} else if (Number.class.isAssignableFrom(fieldClass)) { } else if (Number.class.isAssignableFrom(fieldClass)) {
WRITE_NULL_METHOD = "writeNumberNull"; WRITE_NULL_METHOD = "writeNumberNull";
} else if (fieldClass == Boolean.class) { } else if (fieldClass == Boolean.class) {
@ -2839,10 +2847,11 @@ public class ObjectWriterCreatorASM
|| fieldClass == StringBuilder.class) { || fieldClass == StringBuilder.class) {
WRITE_NULL_METHOD = "writeStringNull"; WRITE_NULL_METHOD = "writeStringNull";
} else { } else {
WRITE_NULL_METHOD = "writeNull"; WRITE_NULL_METHOD = "writeObjectNull";
WRITE_NULL_DESC = "(Ljava/lang/Class;)V";
mwc.loadFieldClass(i, fieldClass);
} }
mw.aload(JSON_WRITER); mw.invokevirtual(TYPE_JSON_WRITER, WRITE_NULL_METHOD, WRITE_NULL_DESC);
mw.invokevirtual(TYPE_JSON_WRITER, WRITE_NULL_METHOD, "()V");
mw.visitLabel(notNull_); mw.visitLabel(notNull_);
} }
@ -3005,7 +3014,7 @@ public class ObjectWriterCreatorASM
// writeFieldName(w); // writeFieldName(w);
gwFieldName(mwc, fieldWriter, i); gwFieldName(mwc, fieldWriter, i);
// jw.writeNulll // jw.writeNull
mw.aload(JSON_WRITER); mw.aload(JSON_WRITER);
mw.invokevirtual(TYPE_JSON_WRITER, "writeArrayNull", "()V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeArrayNull", "()V");
@ -3239,7 +3248,7 @@ public class ObjectWriterCreatorASM
gwFieldName(mwc, fieldWriter, i); gwFieldName(mwc, fieldWriter, i);
mw.aload(JSON_WRITER); mw.aload(JSON_WRITER);
mw.invokevirtual(TYPE_JSON_WRITER, "writeNumberNull", "()V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeDecimalNull", "()V");
mw.goto_(endIfNull_); mw.goto_(endIfNull_);
@ -3300,7 +3309,7 @@ public class ObjectWriterCreatorASM
gwFieldName(mwc, fieldWriter, i); gwFieldName(mwc, fieldWriter, i);
mw.aload(JSON_WRITER); mw.aload(JSON_WRITER);
mw.invokevirtual(TYPE_JSON_WRITER, "writeNumberNull", "()V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeDecimalNull", "()V");
mw.goto_(endIfNull_); mw.goto_(endIfNull_);
@ -3484,7 +3493,7 @@ public class ObjectWriterCreatorASM
mw.visitLabel(writeNull_); mw.visitLabel(writeNull_);
gwFieldName(mwc, fieldWriter, i); gwFieldName(mwc, fieldWriter, i);
// jw.writeNulll // jw.writeNull
mw.aload(JSON_WRITER); mw.aload(JSON_WRITER);
mw.invokevirtual(TYPE_JSON_WRITER, "writeNull", "()V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeNull", "()V");
@ -4190,7 +4199,7 @@ public class ObjectWriterCreatorASM
mw.invokevirtual(TYPE_JSON_WRITER, "writeString", "(Ljava/lang/String;)V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeString", "(Ljava/lang/String;)V");
mw.goto_(endIfNull_); mw.goto_(endIfNull_);
// jw.writeNulll // jw.writeNull
mw.visitLabel(writeNullValue_); mw.visitLabel(writeNullValue_);
mw.aload(JSON_WRITER); mw.aload(JSON_WRITER);
mw.invokevirtual(TYPE_JSON_WRITER, "writeStringNull", "()V"); mw.invokevirtual(TYPE_JSON_WRITER, "writeStringNull", "()V");

View File

@ -11,7 +11,7 @@ public class Issue364 {
@Test @Test
public void test() { public void test() {
TestBean bean = new TestBean(); TestBean bean = new TestBean();
assertEquals("{\"msg\":\"\"}", JSON.toJSONString(bean, JSONWriter.Feature.NullAsDefaultValue)); assertEquals("{\"bean\":{},\"msg\":\"\"}", JSON.toJSONString(bean, JSONWriter.Feature.NullAsDefaultValue));
} }
@Data @Data

View File

@ -0,0 +1,56 @@
package com.alibaba.fastjson2.issues_3500;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import lombok.Getter;
import lombok.Setter;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class Issue3515 {
@Test
public void test() throws Exception {
String jsonString = JSON.toJSONString(new Bean(), JSONWriter.Feature.NullAsDefaultValue);
Bean bean = JSON.parseObject(jsonString, Bean.class);
assertFalse(bean.getBoolVal());
assertEquals((byte) 0, bean.getByteVal());
assertEquals('\u0000', bean.getCharVal());
assertEquals((short) 0, bean.getShortVal());
assertEquals(0, bean.getIntVal());
assertEquals(0L, bean.getLongVal());
assertEquals(0.0F, bean.getFloatVal());
assertEquals(0.0D, bean.getDoubleVal());
assertEquals("", bean.getStringVal());
assertEquals("{}", bean.getMapVal().toString());
assertEquals("[]", bean.getListVal().toString());
assertEquals(BigInteger.ZERO, bean.getIntegerVal());
assertEquals(new BigDecimal("0.0"), bean.getDecimalVal());
assertEquals("{}", bean.getObjectVal().toString());
}
@Getter
@Setter
static class Bean {
private Boolean boolVal;
private Byte byteVal;
private Character charVal;
private Short shortVal;
private Integer intVal;
private Long longVal;
private Float floatVal;
private Double doubleVal;
private String stringVal;
private Map<?, ?> mapVal;
private List<?> listVal;
private BigDecimal decimalVal;
private BigInteger integerVal;
private Object objectVal;
}
}

View File

@ -19,7 +19,7 @@ public class Issue_20201016_01 {
String s = JSON.toJSONString(config, JSONWriter.Feature.WriteNulls, JSONWriter.Feature.NullAsDefaultValue); String s = JSON.toJSONString(config, JSONWriter.Feature.WriteNulls, JSONWriter.Feature.NullAsDefaultValue);
assertEquals("{\"agent\":null,\"creator\":{\"account\":\"account\",\"name\":\"name\",\"workid\":\"\"},\"owner\":{\"account\":\"account\",\"name\":\"name\",\"workid\":\"\"}}", s); assertEquals("{\"agent\":{},\"creator\":{\"account\":\"account\",\"name\":\"name\",\"workid\":\"\"},\"owner\":{\"account\":\"account\",\"name\":\"name\",\"workid\":\"\"}}", s);
} }
@Test @Test