Fix issue #3293 and issue #3328 (#3392)

* fix: issue #3293 and issue #3328

* refactor: simply some redundant code
This commit is contained in:
CodePlayer 2025-03-15 12:38:51 +08:00 committed by GitHub
parent 62e344f5d9
commit ca10dea7ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 170 additions and 77 deletions

View File

@ -392,6 +392,60 @@ public final class ObjectWriterImplMap
jsonWriter.endObject(); jsonWriter.endObject();
} }
static boolean isWriteAsString(Object val, long features) {
return (features & (WriteNonStringKeyAsString.mask | BrowserCompatible.mask)) != 0
&& ObjectWriterProvider.isPrimitiveOrEnum(val.getClass())
&& !(val instanceof Temporal || val instanceof Date);
}
String mapKeyToString(Object key, JSONWriter jsonWriter, long features) {
if (key == null) {
return null;
} else if (key instanceof String) {
return (String) key;
} else if (key instanceof Integer || key instanceof Long) {
return key.toString();
}
if (isWriteAsString(key, features)) {
return key.toString();
}
final JSONWriter.Context context = jsonWriter.getContext();
String str = JSON.toJSONString(key, context);
if (str != null) {
final int length = str.length();
if (length > 1) {
final char quote = jsonWriter.useSingleQuote ? '\'' : '"';
if (str.charAt(0) == quote && str.charAt(length - 1) == quote) {
return str.substring(1, length - 1);
}
}
}
return str;
}
String writeMapKey(Object key, JSONWriter jsonWriter, long features) {
String strKey = null;
if (key == null) {
jsonWriter.writeName("null");
} else if (key instanceof String) {
jsonWriter.writeName(strKey = (String) key);
} else {
if (isWriteAsString(key, features)) {
jsonWriter.writeName(strKey = key.toString());
} else {
if (key instanceof Integer) {
jsonWriter.writeName((Integer) key);
} else if (key instanceof Long) {
jsonWriter.writeName((Long) key);
} else {
jsonWriter.writeNameAny(key);
}
}
}
return strKey;
}
@Override @Override
public boolean writeTypeInfo(JSONWriter jsonWriter) { public boolean writeTypeInfo(JSONWriter jsonWriter) {
if (jsonWriter.utf8) { if (jsonWriter.utf8) {
@ -438,28 +492,12 @@ public final class ObjectWriterImplMap
ObjectWriterProvider provider = jsonWriter.context.provider; ObjectWriterProvider provider = jsonWriter.context.provider;
for (Map.Entry entry : (Iterable<Map.Entry>) map.entrySet()) { for (Map.Entry entry : (Iterable<Map.Entry>) map.entrySet()) {
Object value = entry.getValue(); final Object value = entry.getValue();
Object key = entry.getKey(); Object key = entry.getKey();
if (value == null) { if (value == null) {
if ((features & JSONWriter.Feature.WriteNulls.mask) != 0) { if ((features & JSONWriter.Feature.WriteNulls.mask) != 0) {
if (key == null) { writeMapKey(key, jsonWriter, features);
jsonWriter.writeName("null");
} else if (key instanceof String) {
jsonWriter.writeName((String) key);
} else {
if ((features & (WriteNonStringKeyAsString.mask | BrowserCompatible.mask)) != 0) {
jsonWriter.writeName(key.toString());
} else {
if (key instanceof Integer) {
jsonWriter.writeName((Integer) key);
} else if (key instanceof Long) {
jsonWriter.writeName((Long) key);
} else {
jsonWriter.writeNameAny(key);
}
}
}
jsonWriter.writeColon(); jsonWriter.writeColon();
jsonWriter.writeNull(); jsonWriter.writeNull();
} }
@ -476,33 +514,14 @@ public final class ObjectWriterImplMap
String strKey = null; String strKey = null;
if (keyWriter != null) { if (keyWriter != null) {
keyWriter.write(jsonWriter, key, null, null, 0); keyWriter.write(jsonWriter, key, null, null, 0);
} else if (key == null) {
jsonWriter.writeName("null");
} else if (key instanceof String) {
jsonWriter.writeName(strKey = (String) key);
} else { } else {
boolean writeAsString = (features & (WriteNonStringKeyAsString.mask | BrowserCompatible.mask)) != 0 && ObjectWriterProvider.isPrimitiveOrEnum(key.getClass()); strKey = writeMapKey(key, jsonWriter, features);
if (writeAsString && (key instanceof Temporal || key instanceof Date)) {
writeAsString = false;
}
if (writeAsString) {
jsonWriter.writeName(strKey = key.toString());
} else {
if (key instanceof Integer) {
jsonWriter.writeName((Integer) key);
} else if (key instanceof Long) {
long longKey = (Long) key;
jsonWriter.writeName(longKey);
} else {
jsonWriter.writeNameAny(key);
}
}
} }
jsonWriter.writeColon(); jsonWriter.writeColon();
Class valueClass; Class<?> valueClass;
if (contentAs) { if (contentAs) {
valueClass = (Class) this.valueType; valueClass = (Class<?>) this.valueType;
} else { } else {
valueClass = value.getClass(); valueClass = value.getClass();
} }
@ -516,7 +535,7 @@ public final class ObjectWriterImplMap
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT64_MASK) == 0) { if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT64_MASK) == 0) {
jsonWriter.writeInt64((Long) value); jsonWriter.writeInt64((Long) value);
} else { } else {
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass); ObjectWriter<?> valueWriter = jsonWriter.getObjectWriter(valueClass);
valueWriter.write(jsonWriter, value, strKey, Long.class, features); valueWriter.write(jsonWriter, value, strKey, Long.class, features);
} }
continue; continue;
@ -527,14 +546,14 @@ public final class ObjectWriterImplMap
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DECIMAL_MASK) == 0) { if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DECIMAL_MASK) == 0) {
jsonWriter.writeDecimal((BigDecimal) value, features, null); jsonWriter.writeDecimal((BigDecimal) value, features, null);
} else { } else {
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass); ObjectWriter<?> valueWriter = jsonWriter.getObjectWriter(valueClass);
valueWriter.write(jsonWriter, value, key, this.valueType, this.features); valueWriter.write(jsonWriter, value, key, this.valueType, this.features);
} }
continue; continue;
} }
boolean isPrimitiveOrEnum; boolean isPrimitiveOrEnum;
ObjectWriter valueWriter; ObjectWriter<?> valueWriter;
if (valueClass == this.valueType) { if (valueClass == this.valueType) {
if (this.valueWriter != null) { if (this.valueWriter != null) {
valueWriter = this.valueWriter; valueWriter = this.valueWriter;
@ -559,7 +578,7 @@ public final class ObjectWriterImplMap
isPrimitiveOrEnum = false; isPrimitiveOrEnum = false;
} else { } else {
valueWriter = jsonWriter.getObjectWriter(valueClass); valueWriter = jsonWriter.getObjectWriter(valueClass);
isPrimitiveOrEnum = ObjectWriterProvider.isPrimitiveOrEnum(value.getClass()); isPrimitiveOrEnum = ObjectWriterProvider.isPrimitiveOrEnum(valueClass);
} }
} }
@ -628,14 +647,7 @@ public final class ObjectWriterImplMap
} }
Object entryKey = entry.getKey(); Object entryKey = entry.getKey();
String key; String key = mapKeyToString(entryKey, jsonWriter, features);
if (entryKey == null) {
key = null;
} else if (entryKey instanceof String) {
key = (String) entryKey;
} else {
key = JSON.toJSONString(entryKey, jsonWriter.getContext());
}
if (refDetect) { if (refDetect) {
String refPath = jsonWriter.setPath(key, value); String refPath = jsonWriter.setPath(key, value);
@ -681,13 +693,13 @@ public final class ObjectWriterImplMap
if (value == null) { if (value == null) {
jsonWriter.writeNull(); jsonWriter.writeNull();
} else { } else {
Class valueClass; Class<?> valueClass;
if (contentAs) { if (contentAs) {
valueClass = (Class) this.valueType; valueClass = (Class<?>) this.valueType;
} else { } else {
valueClass = value.getClass(); valueClass = value.getClass();
} }
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass); ObjectWriter<?> valueWriter = jsonWriter.getObjectWriter(valueClass);
valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features); valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
} }
} finally { } finally {

View File

@ -0,0 +1,86 @@
package com.alibaba.fastjson2.issues_3200;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.ValueFilter;
import org.junit.Test;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class Issue3293 {
public interface ValueEnum<V> {
/**
* 获取枚举的 value
*/
V getValue();
}
public enum MemberType implements ValueEnum<Integer> {
USER(1),
ADMIN(2),
AGENT(3);
final Integer value;
MemberType(Integer value) {
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
}
@Test
public void test() {
final ValueFilter valueFilter = (object, name, value) -> {
if (value instanceof Enum<?>) {
if (value instanceof ValueEnum<?>) {
return ((ValueEnum<?>) value).getValue();
}
return ((Enum<?>) value).ordinal();
}
return value;
};
LocalDateTime localDateTime = LocalDateTime.of(2006, 1, 2, 15, 4, 5);
Map<Object, Object> map = new HashMap<>(4);
map.put(MemberType.USER, 1);
map.put(MemberType.ADMIN, 2);
map.put(123, "a");
map.put("key", "value");
map.put(localDateTime, false);
Date date = Date.from(localDateTime.plusDays(1).atZone(ZoneId.systemDefault()).toInstant());
map.put(date, true);
map.put(BigDecimal.TEN, 10);
map.put(Collections.emptyList(), 3L);
map.put(Collections.emptyMap(), "null");
// {"USER":1,{}:"null",[]:3,"ADMIN":2,"2006-01-03 15:04:05":true,10:10,123:"a","2006-01-02 15:04:05":false,"key":"value"}
String rawJsonStr = JSON.toJSONString(map);
// System.out.println(rawJsonStr);
assertTrue(rawJsonStr.contains("\"USER\""));
assertTrue(rawJsonStr.contains("{}:"));
assertTrue(rawJsonStr.contains("[]:"));
assertTrue(rawJsonStr.contains("10:"));
assertTrue(rawJsonStr.contains("\"2006-01-02 15:04:05\":"));
// {"USER":1,"{}":"null","[]":3,"ADMIN":2,"2006-01-03 15:04:05":true,"10":10,"123":"a","2006-01-02 15:04:05":false,"key":"value"}
String jsonStr1 = JSON.toJSONString(map, JSONWriter.Feature.WriteNonStringKeyAsString);
String jsonStr2 = JSON.toJSONString(map, valueFilter, JSONWriter.Feature.BrowserCompatible);
// System.out.println(jsonStr1);
assertEquals(jsonStr1, jsonStr2);
assertTrue(jsonStr1.contains("\"USER\""));
assertTrue(jsonStr1.contains("\"[]\":"));
assertTrue(jsonStr1.contains("\"{}\":"));
assertTrue(jsonStr1.contains("\"10\":"));
assertTrue(jsonStr1.contains("\"2006-01-02 15:04:05\":"));
}
}

View File

@ -15,16 +15,16 @@ public class BigDecimalUtil {
} }
int scale = value.scale(); int scale = value.scale();
DecimalFormat decimalFormat = null; DecimalFormat decimalFormat;
if (scale <= 2) { if (scale <= 2) {
decimalFormat = DF_TWO; decimalFormat = DF_TWO;
} else if (scale > 2 && scale <= 4) { } else if (scale <= 4) {
// 保留四位小数 // 保留四位小数
decimalFormat = DF_FOUR; decimalFormat = DF_FOUR;
} else if (scale > 4 && scale <= 6) { } else if (scale <= 6) {
// 保留六位小数 // 保留六位小数
decimalFormat = DF_SIX; decimalFormat = DF_SIX;
} else if (scale > 6 && scale <= 8) { } else if (scale <= 8) {
decimalFormat = EIGHT_SIX; decimalFormat = EIGHT_SIX;
} else { } else {
decimalFormat = null; decimalFormat = null;
@ -32,37 +32,32 @@ public class BigDecimalUtil {
if (null == decimalFormat) { if (null == decimalFormat) {
return value.toString(); return value.toString();
} else {
return decimalFormat.format(value);
} }
// FIXME: decimalFormat is NOT thread safe
return decimalFormat.format(value);
} }
public static BigDecimal castToBigDecimal(String value) { public static BigDecimal castToBigDecimal(String value) {
if (null == value || value.length() < 1) { final int len;
if (value == null || (len = value.length()) == 0) {
return null; return null;
} }
// 只保留数字和小数点 // 只保留数字和小数点
StringBuilder sb = new StringBuilder(); final char[] validChars = new char[len];
char[] charArr = value.toCharArray(); int i = 0;
for (char c : charArr) { for (int j = 0; j < len; j++) {
// 0-9 final char c = value.charAt(j);
if (c >= 48 && c <= 57) { if (c >= '0' && c <= '9' || c == '.') {
sb.append((char) c); validChars[i++] = c;
}
// .
if (c == 46) {
sb.append((char) c);
} }
} }
if (sb.length() < 1) { if (i == 0) {
return null; return null;
} }
String decimal = sb.toString(); // new BigDecimal( stringBuilder.toString() ) will call new BigDecimal( str.toCharArray() ) internally
BigDecimal result = new BigDecimal(decimal); return new BigDecimal(validChars, 0, i);
return result;
} }
} }