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