Skip to content

Commit

Permalink
support read empty string as null, for issue #998
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Dec 9, 2022
1 parent 3e6e23e commit c9f8367
Show file tree
Hide file tree
Showing 17 changed files with 146 additions and 37 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/com/alibaba/fastjson2/JSONReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ public boolean nextIfObjectStart() {
return true;
}

public abstract boolean nextIfEmptyString();
public abstract boolean nextIfNullOrEmptyString();

public boolean nextIfObjectEnd() {
if (this.ch != '}') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,13 @@ public boolean nextIfMatch(char ch) {
}

@Override
public boolean nextIfEmptyString() {
public boolean nextIfNullOrEmptyString() {
final char first = this.ch;
if (first == 'n' && offset + 2 < end && bytes[offset] == 'u') {
this.readNull();
return true;
}

if ((first != '"' && first != '\'') || offset >= end || bytes[offset] != first) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,12 @@ public final boolean nextIfObjectEnd() {
}

@Override
public final boolean nextIfEmptyString() {
public final boolean nextIfNullOrEmptyString() {
if (bytes[offset] == BC_NULL) {
offset++;
return true;
}

if (bytes[offset] != BC_STR_ASCII_FIX_MIN) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,13 @@ public boolean nextIfMatch(char ch) {
}

@Override
public boolean nextIfEmptyString() {
public boolean nextIfNullOrEmptyString() {
final char first = this.ch;
if (first == 'n' && offset + 2 < end && chars[offset] == 'u') {
this.readNull();
return true;
}

if ((first != '"' && first != '\'') || offset >= end || chars[offset] != first) {
return false;
}
Expand Down
7 changes: 6 additions & 1 deletion core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java
Original file line number Diff line number Diff line change
Expand Up @@ -7159,8 +7159,13 @@ public String readPattern() {
}

@Override
public boolean nextIfEmptyString() {
public boolean nextIfNullOrEmptyString() {
final char first = this.ch;
if (first == 'n' && offset + 2 < end && bytes[offset] == 'u') {
this.readNull();
return true;
}

if ((first != '"' && first != '\'') || offset >= end || this.bytes[offset] != first) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public void readFieldValue(JSONReader jsonReader, T object) {
}
fieldValue = new java.util.Date(millis);
}
} else if (jsonReader.nextIfEmptyString()) {
} else if (jsonReader.nextIfNullOrEmptyString()) {
fieldValue = null;
} else {
long millis = jsonReader.readMillisFromString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public Object readObject(JSONReader jsonReader, Type fieldType, Object fieldName
return readJSONBObject(jsonReader, fieldType, fieldName, 0);
}

if (jsonReader.readIfNull() || jsonReader.nextIfEmptyString()) {
if (jsonReader.nextIfNullOrEmptyString()) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public T readObject(JSONReader jsonReader, Type fieldType, Object fieldName, lon
return readJSONBObject(jsonReader, fieldType, fieldName, 0);
}

if (jsonReader.nextIfNull() || jsonReader.nextIfEmptyString()) {
if (jsonReader.nextIfNullOrEmptyString()) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,11 @@ protected void initDefaultValue(T object) {
}

public void readObject(JSONReader jsonReader, Object object, long features) {
if (jsonReader.isJSONB()) {
// return readJSONBObject(jsonReader, features);
}

if (jsonReader.nextIfNull()) {
jsonReader.nextIfMatch(',');
return;
}

if (jsonReader.isArray() && jsonReader.isSupportBeanArray(getFeatures() | features)) {
// return readArrayMappingObject(jsonReader);
}

boolean objectStart = jsonReader.nextIfMatch('{');
if (!objectStart) {
throw new JSONException(jsonReader.info());
Expand Down Expand Up @@ -210,7 +202,7 @@ public T readObject(JSONReader jsonReader, Type fieldType, Object fieldName, lon
return readJSONBObject(jsonReader, fieldType, fieldName, features);
}

if (jsonReader.nextIfNull()) {
if (jsonReader.nextIfNullOrEmptyString()) {
jsonReader.nextIfMatch(',');
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1554,7 +1554,7 @@ private <T> void genMethodReadObject(
mw.visitJumpInsn(Opcodes.IFNE, notNull_);

mw.visitVarInsn(Opcodes.ALOAD, JSON_READER);
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_JSON_READER, "nextIfNull", "()Z", false);
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_JSON_READER, "nextIfNullOrEmptyString", "()Z", false);
mw.visitJumpInsn(Opcodes.IFEQ, notNull_);

mw.visitInsn(Opcodes.ACONST_NULL);
Expand Down Expand Up @@ -2151,10 +2151,10 @@ private <T> int genReadFieldValue(
mw.visitJumpInsn(Opcodes.GOTO, loadList_);
} else if (itemType instanceof Class) {
mw.visitVarInsn(Opcodes.ALOAD, JSON_READER);
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_JSON_READER, "nextIfEmptyString", "()Z", false);
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_JSON_READER, "nextIfNullOrEmptyString", "()Z", false);
mw.visitJumpInsn(Opcodes.IFNE, loadNull_);

// nextIfEmptyString
// nextIfNullOrEmptyString
mw.visitTypeInsn(Opcodes.NEW, LIST_TYPE);
mw.visitInsn(Opcodes.DUP);
if (initCapacity) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ protected ObjectReaderException(
public T readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
boolean objectStart = jsonReader.nextIfObjectStart();
if (!objectStart) {
if (jsonReader.nextIfEmptyString()) {
if (jsonReader.nextIfNullOrEmptyString()) {
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private Object readDate(JSONReader jsonReader) {
}
}

if (jsonReader.nextIfEmptyString()) {
if (jsonReader.nextIfNullOrEmptyString()) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public T readObject(JSONReader jsonReader, Type fieldType, Object fieldName, lon

boolean objectStart = jsonReader.nextIfObjectStart();
if (!objectStart && !jsonReader.isTypeRedirect()) {
if (jsonReader.nextIfEmptyString()) {
if (jsonReader.nextIfNullOrEmptyString()) {
return null;
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/java/com/alibaba/fastjson2/JSONBTest5.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ public void nextIfEmptyString() {
JSONReader.ofJSONB(
JSONB.toBytes("")
)
.nextIfEmptyString()
.nextIfNullOrEmptyString()
);
assertFalse(JSONReader.ofJSONB(JSONB.toBytes("1")).nextIfEmptyString());
assertFalse(JSONReader.ofJSONB(JSONB.toBytes("1")).nextIfNullOrEmptyString());
}
}
6 changes: 5 additions & 1 deletion core/src/test/java/com/alibaba/fastjson2/JSONReaderStr.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,12 @@ public boolean nextIfMatch(char ch) {
}

@Override
public boolean nextIfEmptyString() {
public boolean nextIfNullOrEmptyString() {
final char first = this.ch;
if (first == 'n' && offset + 2 < end && str.charAt(offset) == 'u') {
this.readNull();
return true;
}
if ((first != '"' && first != '\'') || offset >= end || str.charAt(offset) != first) {
return false;
}
Expand Down
22 changes: 11 additions & 11 deletions core/src/test/java/com/alibaba/fastjson2/JSONReaderTest1.java
Original file line number Diff line number Diff line change
Expand Up @@ -293,58 +293,58 @@ public void testNextIfSet() {
@Test
public void testNextIfEmptyString() {
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\'\',1")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals('1', jsonReader.ch);
assertTrue(jsonReader.comma);
}

for (JSONReader jsonReader : TestUtils.createJSONReaders4("\'\' , 1")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals('1', jsonReader.ch);
assertTrue(jsonReader.comma);
}

for (JSONReader jsonReader : TestUtils.createJSONReaders("\'\' , 中")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals('中', jsonReader.ch);
assertTrue(jsonReader.comma);
}
for (JSONReader jsonReader : TestUtils.createJSONReaders("\'\' , ®")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals('®', jsonReader.ch);
assertTrue(jsonReader.comma);
}

for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"\"")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals(JSONReader.EOI, jsonReader.ch);
assertFalse(jsonReader.comma);
}
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"\",")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals(JSONReader.EOI, jsonReader.ch);
assertTrue(jsonReader.comma);
}
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"\" ,")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals(JSONReader.EOI, jsonReader.ch);
assertTrue(jsonReader.comma);
}
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"\" , ")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals(JSONReader.EOI, jsonReader.ch);
assertTrue(jsonReader.comma);
}
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"\" ")) {
assertTrue(jsonReader.nextIfEmptyString());
assertTrue(jsonReader.nextIfNullOrEmptyString());
assertEquals(JSONReader.EOI, jsonReader.ch);
assertFalse(jsonReader.comma);
}
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"")) {
assertFalse(jsonReader.nextIfEmptyString());
assertFalse(jsonReader.nextIfNullOrEmptyString());
}
for (JSONReader jsonReader : TestUtils.createJSONReaders4("\"a\"")) {
assertFalse(jsonReader.nextIfEmptyString());
assertFalse(jsonReader.nextIfNullOrEmptyString());
}
}

Expand Down
93 changes: 93 additions & 0 deletions core/src/test/java/com/alibaba/fastjson2/issues/Issue998.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.alibaba.fastjson2.issues;

import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.Test;

import java.io.Serializable;

import static org.junit.jupiter.api.Assertions.assertNull;

public class Issue998 {
@Test
public void test() {
String str = "{\"cloudServiceName\":\"xxx\",\"enterpriseCode\":\"xxx\",\"enterpriseName\":\"xxx\",\"serviceCode\":\"IT_MONITOR_MANAGER_SYSTEM\",\"cloudStyle\":\"\"}";
EnterpriseCloudServiceVO enterpriseCloudServiceVO = JSON.parseObject(str, EnterpriseCloudServiceVO.class);
assertNull(enterpriseCloudServiceVO.cloudStyle);
}

@Test
public void test1() {
String str = "{\"cloudServiceName\":\"xxx\",\"enterpriseCode\":\"xxx\",\"enterpriseName\":\"xxx\",\"serviceCode\":\"IT_MONITOR_MANAGER_SYSTEM\",\"cloudStyle\":\"\"}";
EnterpriseCloudServiceVO1 enterpriseCloudServiceVO = JSON.parseObject(str, EnterpriseCloudServiceVO1.class);
assertNull(enterpriseCloudServiceVO.cloudStyle);
}

public static class EnterpriseCloudServiceVO {
private String enterpriseCode;
private String enterpriseName;
private String serviceCode;
private String cloudServiceName;
private CloudStyle cloudStyle;

public String getEnterpriseCode() {
return enterpriseCode;
}

public void setEnterpriseCode(String enterpriseCode) {
this.enterpriseCode = enterpriseCode;
}

public String getEnterpriseName() {
return enterpriseName;
}

public void setEnterpriseName(String enterpriseName) {
this.enterpriseName = enterpriseName;
}

public String getServiceCode() {
return serviceCode;
}

public void setServiceCode(String serviceCode) {
this.serviceCode = serviceCode;
}

public String getCloudServiceName() {
return cloudServiceName;
}

public void setCloudServiceName(String cloudServiceName) {
this.cloudServiceName = cloudServiceName;
}

public CloudStyle getCloudStyle() {
return cloudStyle;
}

public void setCloudStyle(CloudStyle cloudStyle) {
this.cloudStyle = cloudStyle;
}
}

private static class EnterpriseCloudServiceVO1 {
public String enterpriseCode;
public String enterpriseName;
public String serviceCode;
public String cloudServiceName;
public CloudStyle cloudStyle;
}

public static class CloudStyle
implements Serializable {
private Integer modelId;

public Integer getModelId() {
return modelId;
}

public void setModelId(Integer modelId) {
this.modelId = modelId;
}
}
}

0 comments on commit c9f8367

Please # to comment.