Repository: alibaba/fastjson2
Pull request #3519 (2025-04-24 14:52:25)

fix improve feature of NullAsDefaultValue, for issue #3518
### What this PR does / why we need it?

fix improve feature of NullAsDefaultValue

### 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](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.


codecov-commenter: ## [Codecov](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) Report
Attention: Patch coverage is `84.61538%` with `8 lines` in your changes missing coverage. Please review.
> Project coverage is 72.35%. Comparing base [(`31345c4`)](https://app.codecov.io/gh/alibaba/fastjson2/commit/31345c479140dee76085d1177e207b8e572c0761?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) to head [(`ae093fa`)](https://app.codecov.io/gh/alibaba/fastjson2/commit/ae093fa8fcfebdc04ffc50f5497b0498c69a7845?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba).
> Report is 9 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) | Patch % | Lines |
|---|---|---|
| [...ibaba/fastjson2/writer/FieldWriterObjectFinal.java](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?src=pr&el=tree&filepath=core%2Fsrc%2Fmain%2Fjava%2Fcom%2Falibaba%2Ffastjson2%2Fwriter%2FFieldWriterObjectFinal.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba#diff-Y29yZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zhc3Rqc29uMi93cml0ZXIvRmllbGRXcml0ZXJPYmplY3RGaW5hbC5qYXZh) | 50.00% | [2 Missing and 2 partials :warning: ](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) |
| [...libaba/fastjson2/writer/FieldWriterDoubleFunc.java](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?src=pr&el=tree&filepath=core%2Fsrc%2Fmain%2Fjava%2Fcom%2Falibaba%2Ffastjson2%2Fwriter%2FFieldWriterDoubleFunc.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba#diff-Y29yZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zhc3Rqc29uMi93cml0ZXIvRmllbGRXcml0ZXJEb3VibGVGdW5jLmphdmE=) | 25.00% | [1 Missing and 2 partials :warning: ](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) |
| [...alibaba/fastjson2/writer/FieldWriterFloatFunc.java](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?src=pr&el=tree&filepath=core%2Fsrc%2Fmain%2Fjava%2Fcom%2Falibaba%2Ffastjson2%2Fwriter%2FFieldWriterFloatFunc.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba#diff-Y29yZS9zcmMvbWFpbi9qYXZhL2NvbS9hbGliYWJhL2Zhc3Rqc29uMi93cml0ZXIvRmllbGRXcml0ZXJGbG9hdEZ1bmMuamF2YQ==) | 75.00% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##               main    #3519      +/-   ##
============================================
- Coverage     73.73%   72.35%   -1.38%     
+ Complexity    23778    23194     -584     
============================================
  Files           682      682              
  Lines         90711    90740      +29     
  Branches      20619    20578      -41     
============================================
- Hits          66885    65657    -1228     
- Misses        15534    16657    +1123     
- Partials       8292     8426     +134     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/alibaba/fastjson2/pull/3519?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java
index 942a846e6..92d0ea94d 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriter.java
@@ -1147,6 +1147,18 @@ public abstract class JSONWriter
 
     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() {
         String raw;
         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() {
         if ((this.context.features & (MASK_NULL_AS_DEFAULT_VALUE | MASK_WRITE_NULL_NUMBER_AS_ZERO)) != 0) {
             writeInt64(0);
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java
index 94ca4946c..a8b96ebaa 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF16.java
@@ -1045,7 +1045,7 @@ class JSONWriterUTF16
 
     public final void writeDecimal(BigDecimal value, long features, DecimalFormat format) {
         if (value == null) {
-            writeNumberNull();
+            writeDecimalNull();
             return;
         }
 
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java
index 0e91f1f52..0a2d70552 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONWriterUTF8.java
@@ -2371,7 +2371,7 @@ final class JSONWriterUTF8
     @Override
     public final void writeDecimal(BigDecimal value, long features, DecimalFormat format) {
         if (value == null) {
-            writeNumberNull();
+            writeDecimalNull();
             return;
         }
 
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalField.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalField.java
index 4534b5e51..a8679be8a 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalField.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalField.java
@@ -23,7 +23,7 @@ final class FieldWriterBigDecimalField<T>
         BigDecimal value = (BigDecimal) getFieldValue(object);
         if (value == null) {
             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;
             }
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalFunc.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalFunc.java
index 778c6923a..a3936a02f 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalFunc.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalFunc.java
@@ -50,7 +50,7 @@ final class FieldWriterBigDecimalFunc<T>
 
         if (value == null) {
             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;
             }
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalMethod.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalMethod.java
index eae70c1ae..5831d272d 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalMethod.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigDecimalMethod.java
@@ -51,7 +51,7 @@ final class FieldWriterBigDecimalMethod<T>
 
         if (value == null) {
             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;
             }
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntField.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntField.java
index 95d789bca..fb6e5247e 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntField.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntField.java
@@ -23,7 +23,7 @@ final class FieldWriterBigIntField<T>
         BigInteger value = (BigInteger) getFieldValue(object);
         if (value == null) {
             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;
             }
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntFunc.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntFunc.java
index 4fbe28cf8..50e5032f2 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntFunc.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterBigIntFunc.java
@@ -41,7 +41,7 @@ final class FieldWriterBigIntFunc<T>
         BigInteger value = function.apply(o);
         if (value == null) {
             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;
             }
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterDoubleFunc.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterDoubleFunc.java
index 2d8955573..1e1acaf3f 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterDoubleFunc.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterDoubleFunc.java
@@ -58,11 +58,12 @@ final class FieldWriterDoubleFunc<T>
 
         if (value == null) {
             long features = jsonWriter.getFeatures(this.features);
-            if ((features & JSONWriter.Feature.WriteNulls.mask) != 0
-                    && (features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0
-            ) {
+            if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
+                return false;
+            }
+            if ((features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0) {
                 writeFieldName(jsonWriter);
-                jsonWriter.writeNumberNull();
+                jsonWriter.writeDecimalNull();
                 return true;
             }
             return false;
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterFloatFunc.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterFloatFunc.java
index 5196f2267..2de63a517 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterFloatFunc.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterFloatFunc.java
@@ -58,11 +58,12 @@ final class FieldWriterFloatFunc<T>
 
         if (value == null) {
             long features = jsonWriter.getFeatures(this.features);
-            if ((features & JSONWriter.Feature.WriteNulls.mask) != 0
-                    && (features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0
-            ) {
+            if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
+                return false;
+            }
+            if ((features & JSONWriter.Feature.NotWriteDefaultValue.mask) == 0) {
                 writeFieldName(jsonWriter);
-                jsonWriter.writeNumberNull();
+                jsonWriter.writeDecimalNull();
                 return true;
             }
             return false;
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt16.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt16.java
index fbce556a3..d9ef572d0 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt16.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt16.java
@@ -46,7 +46,7 @@ abstract class FieldWriterInt16<T>
 
         if (value == null) {
             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;
             }
             writeFieldName(jsonWriter);
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt8.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt8.java
index 7fe96c0c5..5ef1af2d6 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt8.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterInt8.java
@@ -45,7 +45,7 @@ abstract class FieldWriterInt8<T>
 
         if (value == null) {
             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;
             }
             writeFieldName(jsonWriter);
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObject.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObject.java
index 3c181c02a..9817721d0 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObject.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObject.java
@@ -272,7 +272,10 @@ public class FieldWriterObject<T>
 
         // (features & JSONWriter.Feature.WriteNullNumberAsZero.mask) != 0
         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);
                 if (array) {
                     jsonWriter.writeArrayNull();
@@ -283,7 +286,7 @@ public class FieldWriterObject<T>
                         || fieldClass == StringBuilder.class) {
                     jsonWriter.writeStringNull();
                 } else {
-                    jsonWriter.writeNull();
+                    jsonWriter.writeObjectNull(fieldClass);
                 }
                 return true;
             } else {
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObjectFinal.java b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObjectFinal.java
index 136965d4c..1ddaa3926 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObjectFinal.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/FieldWriterObjectFinal.java
@@ -59,20 +59,18 @@ abstract class FieldWriterObjectFinal<T>
 
         if (value == null) {
             long features = this.features | jsonWriter.getFeatures();
-            if ((features & JSONWriter.Feature.WriteNulls.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 {
+            if ((features & (JSONWriter.Feature.WriteNulls.mask | JSONWriter.Feature.NullAsDefaultValue.mask)) == 0) {
                 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);
diff --git a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java
index 4457c5ec7..434c9aa5d 100644
--- a/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java
+++ b/core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java
@@ -2526,7 +2526,7 @@ public class ObjectWriterCreatorASM
         // writeFieldName(w);
         gwFieldName(mwc, fieldWriter, i);
 
-        // jw.writeNulll
+        // jw.writeNull
         mw.aload(JSON_WRITER);
         mw.invokevirtual(TYPE_JSON_WRITER, "writeNull", "()V");
 
@@ -2813,6 +2813,8 @@ public class ObjectWriterCreatorASM
             } else if (fieldClass == String.class) {
                 nullFeatures |= WriteNullStringAsEmpty.mask;
                 nullFeatures |= NullAsDefaultValue.mask;
+            } else {
+                nullFeatures |= NullAsDefaultValue.mask;
             }
             mwc.genIsEnabled(nullFeatures, notNull_);
 //            mw.iload(mwc.var(WRITE_NULLS));
@@ -2822,13 +2824,19 @@ public class ObjectWriterCreatorASM
         // writeFieldName(w);
         gwFieldName(mwc, fieldWriter, i);
 
-        // jw.writeNulll
+        // jw.writeNull
+        mw.aload(JSON_WRITER);
         String WRITE_NULL_METHOD;
+        String WRITE_NULL_DESC = "()V";
         if (fieldClass == AtomicLongArray.class
                 || fieldClass == AtomicIntegerArray.class
                 || Collection.class.isAssignableFrom(fieldClass)
                 || fieldClass.isArray()) {
             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)) {
             WRITE_NULL_METHOD = "writeNumberNull";
         } else if (fieldClass == Boolean.class) {
@@ -2839,10 +2847,11 @@ public class ObjectWriterCreatorASM
                 || fieldClass == StringBuilder.class) {
             WRITE_NULL_METHOD = "writeStringNull";
         } 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, "()V");
+        mw.invokevirtual(TYPE_JSON_WRITER, WRITE_NULL_METHOD, WRITE_NULL_DESC);
 
         mw.visitLabel(notNull_);
     }
@@ -3005,7 +3014,7 @@ public class ObjectWriterCreatorASM
         // writeFieldName(w);
         gwFieldName(mwc, fieldWriter, i);
 
-        // jw.writeNulll
+        // jw.writeNull
         mw.aload(JSON_WRITER);
         mw.invokevirtual(TYPE_JSON_WRITER, "writeArrayNull", "()V");
 
@@ -3239,7 +3248,7 @@ public class ObjectWriterCreatorASM
         gwFieldName(mwc, fieldWriter, i);
 
         mw.aload(JSON_WRITER);
-        mw.invokevirtual(TYPE_JSON_WRITER, "writeNumberNull", "()V");
+        mw.invokevirtual(TYPE_JSON_WRITER, "writeDecimalNull", "()V");
 
         mw.goto_(endIfNull_);
 
@@ -3300,7 +3309,7 @@ public class ObjectWriterCreatorASM
         gwFieldName(mwc, fieldWriter, i);
 
         mw.aload(JSON_WRITER);
-        mw.invokevirtual(TYPE_JSON_WRITER, "writeNumberNull", "()V");
+        mw.invokevirtual(TYPE_JSON_WRITER, "writeDecimalNull", "()V");
 
         mw.goto_(endIfNull_);
 
@@ -3484,7 +3493,7 @@ public class ObjectWriterCreatorASM
         mw.visitLabel(writeNull_);
         gwFieldName(mwc, fieldWriter, i);
 
-        // jw.writeNulll
+        // jw.writeNull
         mw.aload(JSON_WRITER);
         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.goto_(endIfNull_);
 
-        // jw.writeNulll
+        // jw.writeNull
         mw.visitLabel(writeNullValue_);
         mw.aload(JSON_WRITER);
         mw.invokevirtual(TYPE_JSON_WRITER, "writeStringNull", "()V");


Test patch:
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues/Issue364.java b/core/src/test/java/com/alibaba/fastjson2/issues/Issue364.java
index 9582d2885..6cda849b4 100644
--- a/core/src/test/java/com/alibaba/fastjson2/issues/Issue364.java
+++ b/core/src/test/java/com/alibaba/fastjson2/issues/Issue364.java
@@ -11,7 +11,7 @@ public class Issue364 {
     @Test
     public void test() {
         TestBean bean = new TestBean();
-        assertEquals("{\"msg\":\"\"}", JSON.toJSONString(bean, JSONWriter.Feature.NullAsDefaultValue));
+        assertEquals("{\"bean\":{},\"msg\":\"\"}", JSON.toJSONString(bean, JSONWriter.Feature.NullAsDefaultValue));
     }
 
     @Data
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_3500/Issue3515.java b/core/src/test/java/com/alibaba/fastjson2/issues_3500/Issue3515.java
new file mode 100644
index 000000000..9d440e73e
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_3500/Issue3515.java
@@ -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;
+    }
+}
diff --git a/core/src/test/java/com/alibaba/fastjson2/v1issues/issue_3400/Issue_20201016_01.java b/core/src/test/java/com/alibaba/fastjson2/v1issues/issue_3400/Issue_20201016_01.java
index e8c500390..92111e7df 100644
--- a/core/src/test/java/com/alibaba/fastjson2/v1issues/issue_3400/Issue_20201016_01.java
+++ b/core/src/test/java/com/alibaba/fastjson2/v1issues/issue_3400/Issue_20201016_01.java
@@ -19,7 +19,7 @@ public class Issue_20201016_01 {
 
         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