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();
|
||||
}
|
||||
|
||||
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
|
||||
public boolean writeTypeInfo(JSONWriter jsonWriter) {
|
||||
if (jsonWriter.utf8) {
|
||||
|
|
@ -438,28 +492,12 @@ public final class ObjectWriterImplMap
|
|||
|
||||
ObjectWriterProvider provider = jsonWriter.context.provider;
|
||||
for (Map.Entry entry : (Iterable<Map.Entry>) map.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
final Object value = entry.getValue();
|
||||
Object key = entry.getKey();
|
||||
|
||||
if (value == null) {
|
||||
if ((features & JSONWriter.Feature.WriteNulls.mask) != 0) {
|
||||
if (key == null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeMapKey(key, jsonWriter, features);
|
||||
jsonWriter.writeColon();
|
||||
jsonWriter.writeNull();
|
||||
}
|
||||
|
|
@ -476,33 +514,14 @@ public final class ObjectWriterImplMap
|
|||
String strKey = null;
|
||||
if (keyWriter != null) {
|
||||
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 {
|
||||
boolean writeAsString = (features & (WriteNonStringKeyAsString.mask | BrowserCompatible.mask)) != 0 && ObjectWriterProvider.isPrimitiveOrEnum(key.getClass());
|
||||
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);
|
||||
}
|
||||
}
|
||||
strKey = writeMapKey(key, jsonWriter, features);
|
||||
}
|
||||
jsonWriter.writeColon();
|
||||
|
||||
Class valueClass;
|
||||
Class<?> valueClass;
|
||||
if (contentAs) {
|
||||
valueClass = (Class) this.valueType;
|
||||
valueClass = (Class<?>) this.valueType;
|
||||
} else {
|
||||
valueClass = value.getClass();
|
||||
}
|
||||
|
|
@ -516,7 +535,7 @@ public final class ObjectWriterImplMap
|
|||
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT64_MASK) == 0) {
|
||||
jsonWriter.writeInt64((Long) value);
|
||||
} else {
|
||||
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
ObjectWriter<?> valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
valueWriter.write(jsonWriter, value, strKey, Long.class, features);
|
||||
}
|
||||
continue;
|
||||
|
|
@ -527,14 +546,14 @@ public final class ObjectWriterImplMap
|
|||
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DECIMAL_MASK) == 0) {
|
||||
jsonWriter.writeDecimal((BigDecimal) value, features, null);
|
||||
} else {
|
||||
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
ObjectWriter<?> valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
valueWriter.write(jsonWriter, value, key, this.valueType, this.features);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean isPrimitiveOrEnum;
|
||||
ObjectWriter valueWriter;
|
||||
ObjectWriter<?> valueWriter;
|
||||
if (valueClass == this.valueType) {
|
||||
if (this.valueWriter != null) {
|
||||
valueWriter = this.valueWriter;
|
||||
|
|
@ -559,7 +578,7 @@ public final class ObjectWriterImplMap
|
|||
isPrimitiveOrEnum = false;
|
||||
} else {
|
||||
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();
|
||||
String key;
|
||||
if (entryKey == null) {
|
||||
key = null;
|
||||
} else if (entryKey instanceof String) {
|
||||
key = (String) entryKey;
|
||||
} else {
|
||||
key = JSON.toJSONString(entryKey, jsonWriter.getContext());
|
||||
}
|
||||
String key = mapKeyToString(entryKey, jsonWriter, features);
|
||||
|
||||
if (refDetect) {
|
||||
String refPath = jsonWriter.setPath(key, value);
|
||||
|
|
@ -681,13 +693,13 @@ public final class ObjectWriterImplMap
|
|||
if (value == null) {
|
||||
jsonWriter.writeNull();
|
||||
} else {
|
||||
Class valueClass;
|
||||
Class<?> valueClass;
|
||||
if (contentAs) {
|
||||
valueClass = (Class) this.valueType;
|
||||
valueClass = (Class<?>) this.valueType;
|
||||
} else {
|
||||
valueClass = value.getClass();
|
||||
}
|
||||
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
ObjectWriter<?> valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
|
||||
}
|
||||
} 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();
|
||||
DecimalFormat decimalFormat = null;
|
||||
DecimalFormat decimalFormat;
|
||||
if (scale <= 2) {
|
||||
decimalFormat = DF_TWO;
|
||||
} else if (scale > 2 && scale <= 4) {
|
||||
} else if (scale <= 4) {
|
||||
// 保留四位小数
|
||||
decimalFormat = DF_FOUR;
|
||||
} else if (scale > 4 && scale <= 6) {
|
||||
} else if (scale <= 6) {
|
||||
// 保留六位小数
|
||||
decimalFormat = DF_SIX;
|
||||
} else if (scale > 6 && scale <= 8) {
|
||||
} else if (scale <= 8) {
|
||||
decimalFormat = EIGHT_SIX;
|
||||
} else {
|
||||
decimalFormat = null;
|
||||
|
|
@ -32,37 +32,32 @@ public class BigDecimalUtil {
|
|||
|
||||
if (null == decimalFormat) {
|
||||
return value.toString();
|
||||
} else {
|
||||
return decimalFormat.format(value);
|
||||
}
|
||||
// FIXME: decimalFormat is NOT thread safe
|
||||
return decimalFormat.format(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;
|
||||
}
|
||||
|
||||
// 只保留数字和小数点
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] charArr = value.toCharArray();
|
||||
for (char c : charArr) {
|
||||
// 0-9
|
||||
if (c >= 48 && c <= 57) {
|
||||
sb.append((char) c);
|
||||
}
|
||||
|
||||
// .
|
||||
if (c == 46) {
|
||||
sb.append((char) c);
|
||||
final char[] validChars = new char[len];
|
||||
int i = 0;
|
||||
for (int j = 0; j < len; j++) {
|
||||
final char c = value.charAt(j);
|
||||
if (c >= '0' && c <= '9' || c == '.') {
|
||||
validChars[i++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (sb.length() < 1) {
|
||||
if (i == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String decimal = sb.toString();
|
||||
BigDecimal result = new BigDecimal(decimal);
|
||||
return result;
|
||||
// new BigDecimal( stringBuilder.toString() ) will call new BigDecimal( str.toCharArray() ) internally
|
||||
return new BigDecimal(validChars, 0, i);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue