diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java index e265baf5b9..5e78db9be7 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java @@ -1974,6 +1974,9 @@ public void read(Map object, ObjectReader itemReader, long features) { } public void read(Map object, long features) { + if (ch == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if ((ch == '"' || ch == '\'') && !typeRedirect) { String str = readString(); if (str.isEmpty()) { @@ -4555,7 +4558,12 @@ public enum Feature { * * @since 2.0.51 */ - UseLongForInts(1 << 30); + UseLongForInts(1 << 30), + + /** + * Feature that disables the support for single quote. + */ + DisableSingleQuote(1 << 31); public final long mask; diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java index 36e0b0c30a..95be0ab627 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java @@ -107,6 +107,9 @@ public final boolean nextIfNullOrEmptyString() { public final long readFieldNameHashCode() { final byte[] bytes = this.bytes; int ch = this.ch; + if (ch == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (ch != '"' && ch != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(ch)) { return readFieldNameHashCodeUnquote(); @@ -1015,6 +1018,9 @@ public final String getFieldName() { @Override public final String readFieldName() { final char quote = ch; + if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (quote != '"' && quote != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(quote)) { return readFieldNameUnquote(); diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java index e5c7bcd5b7..9f49b67b2e 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java @@ -1109,6 +1109,9 @@ public final long readFieldNameHashCodeUnquote() { @Override public final long readFieldNameHashCode() { final char[] chars = this.chars; + if (ch == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (ch != '"' && ch != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(ch)) { return readFieldNameHashCodeUnquote(); @@ -1738,6 +1741,9 @@ public final String getFieldName() { @Override public final String readFieldName() { final char quote = ch; + if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (quote != '"' && quote != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(quote)) { return readFieldNameUnquote(); @@ -2317,6 +2323,10 @@ public final String readFieldName() { @Override public final boolean skipName() { char quote = ch; + if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } + if (quote != '"' && quote != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0) { readFieldNameHashCodeUnquote(); diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java index f779bd9f0b..33f8a93936 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java @@ -2323,6 +2323,9 @@ public final boolean nextIfValue4Match11(long name1) { public long readFieldNameHashCode() { final byte[] bytes = this.bytes; int ch = this.ch; + if (ch == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (ch != '"' && ch != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(ch)) { return readFieldNameHashCodeUnquote(); @@ -3127,6 +3130,9 @@ public String getFieldName() { @Override public String readFieldName() { final char quote = ch; + if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (quote != '"' && quote != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(quote)) { return readFieldNameUnquote(); @@ -4693,6 +4699,9 @@ protected void readString0() { @Override public final boolean skipName() { char quote = ch; + if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) { + throw notSupportName(); + } if (quote != '"' && quote != '\'') { if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0) { readFieldNameHashCodeUnquote(); diff --git a/core/src/test/java/com/alibaba/fastjson2/JSONTest.java b/core/src/test/java/com/alibaba/fastjson2/JSONTest.java index 183d55839b..c761815c0e 100644 --- a/core/src/test/java/com/alibaba/fastjson2/JSONTest.java +++ b/core/src/test/java/com/alibaba/fastjson2/JSONTest.java @@ -1209,6 +1209,7 @@ public void isValid1() { assertFalse(JSON.isValid("{", JSONReader.Feature.AllowUnQuotedFieldNames)); assertFalse(JSON.isValid("\"", JSONReader.Feature.AllowUnQuotedFieldNames)); assertFalse(JSON.isValid("'", JSONReader.Feature.AllowUnQuotedFieldNames)); + assertFalse(JSON.isValid("'", JSONReader.Feature.DisableSingleQuote)); } @Test diff --git a/core/src/test/java/com/alibaba/fastjson2/read/ObjectKeyTest.java b/core/src/test/java/com/alibaba/fastjson2/read/ObjectKeyTest.java index 37240cc48f..2abb395630 100644 --- a/core/src/test/java/com/alibaba/fastjson2/read/ObjectKeyTest.java +++ b/core/src/test/java/com/alibaba/fastjson2/read/ObjectKeyTest.java @@ -1,6 +1,7 @@ package com.alibaba.fastjson2.read; import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONException; import com.alibaba.fastjson2.JSONReader; import org.junit.jupiter.api.Test; @@ -9,6 +10,7 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class ObjectKeyTest { @Test @@ -31,6 +33,15 @@ public void test1() { assertEquals(1, ((Bean) JSON.parseObject(s.toCharArray(), (Type) Bean.class, JSONReader.Feature.AllowUnQuotedFieldNames)).items.size()); } + @Test + public void testDisablingSingleQuote() { + String str = "{'key': 'value'}"; + byte[] bytes = str.getBytes(); + assertThrows(JSONException.class, () -> { + JSON.parseObject(bytes, 0, bytes.length, StandardCharsets.UTF_8, Bean.class, JSONReader.Feature.DisableSingleQuote); + }); + } + public static class Bean { public Map items; } diff --git a/docs/features_cn.md b/docs/features_cn.md index 29c3ee93da..f2f8d99578 100644 --- a/docs/features_cn.md +++ b/docs/features_cn.md @@ -55,7 +55,7 @@ class Model { | AllowUnQuotedFieldNames | 支持不带双引号的字段名 | | NonStringKeyAsString | 非String类型的Key当做String处理 | | Base64StringAsByteArray | 将byte[]序列化为Base64格式的字符串 | - +| DisableSingleQuote | Do not allow single quote on key and value # 5. JSONWriter.Feature介绍 | JSONWriter.Feature | 介绍 | diff --git a/docs/features_en.md b/docs/features_en.md index 76c72c408f..0566278d1a 100644 --- a/docs/features_en.md +++ b/docs/features_en.md @@ -58,6 +58,8 @@ class Model { | AllowUnQuotedFieldNames | | | NonStringKeyAsString | | | Base64StringAsByteArray | | +| DisableSingleQuote | Do not allow single quote in key name and values. + # 5. JSONWriter.Feature | JSONWriter.Feature | Description |