mirror of https://github.com/alibaba/fastjson2.git
* fix: issue #3293 and issue #3328 * refactor: simply some redundant code
This commit is contained in:
parent
62e344f5d9
commit
ca10dea7ec
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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\":"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue