mirror of https://github.com/alibaba/fastjson2.git
				
				
				
			2.0.56.android4 release
This commit is contained in:
		
							parent
							
								
									50079d5ea7
								
							
						
					
					
						commit
						c6c7c92369
					
				|  | @ -6,7 +6,7 @@ | |||
|     <parent> | ||||
|         <groupId>com.alibaba.fastjson2</groupId> | ||||
|         <artifactId>fastjson2-parent</artifactId> | ||||
|         <version>2.0.55.android5</version> | ||||
|         <version>2.0.56.android5</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
|     <parent> | ||||
|         <groupId>com.alibaba.fastjson2</groupId> | ||||
|         <artifactId>fastjson2-parent</artifactId> | ||||
|         <version>2.0.55.android5</version> | ||||
|         <version>2.0.56.android5</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
|     <parent> | ||||
|         <groupId>com.alibaba.fastjson2</groupId> | ||||
|         <artifactId>fastjson2-parent</artifactId> | ||||
|         <version>2.0.55.android5</version> | ||||
|         <version>2.0.56.android5</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ public interface JSON { | |||
|     /** | ||||
|      * fastjson2 version name | ||||
|      */ | ||||
|     String VERSION = "2.0.55"; | ||||
|     String VERSION = "2.0.56"; | ||||
| 
 | ||||
|     /** | ||||
|      * Parses the json string as a {@link JSONArray} or {@link JSONObject}. | ||||
|  |  | |||
|  | @ -3794,6 +3794,7 @@ public abstract class JSONReader | |||
|             } | ||||
|         } | ||||
|     } | ||||
|     protected static final long MASK_DISABLE_REFERENCE_DETECT = 1L << 33; | ||||
| 
 | ||||
|     public enum Feature { | ||||
|         FieldBased(1), | ||||
|  | @ -3917,7 +3918,12 @@ public abstract class JSONReader | |||
|         /** | ||||
|          * @since 2.0.53 | ||||
|          */ | ||||
|         UseDoubleForDecimals(1L << 32L); | ||||
|         UseDoubleForDecimals(1L << 32L), | ||||
| 
 | ||||
|         /** | ||||
|          * @since 2.0.56 | ||||
|          */ | ||||
|         DisableReferenceDetect(MASK_DISABLE_REFERENCE_DETECT); | ||||
| 
 | ||||
|         public final long mask; | ||||
| 
 | ||||
|  |  | |||
|  | @ -154,8 +154,10 @@ final class JSONReaderUTF16 | |||
|         return bytes; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public final boolean isReference() { | ||||
|         if ((context.features & MASK_DISABLE_REFERENCE_DETECT) != 0) { | ||||
|             return false; | ||||
|         } | ||||
|         // should be codeSize <= FreqInlineSize 325, current is 276 | ||||
|         final char[] chars = this.chars; | ||||
|         char ch = this.ch; | ||||
|  | @ -188,6 +190,11 @@ final class JSONReaderUTF16 | |||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return isReference0(chars, offset, end, quote); | ||||
|     } | ||||
| 
 | ||||
|     private boolean isReference0(char[] chars, int offset, int end, char quote) { | ||||
|         char ch; | ||||
|         offset += 6; | ||||
|         ch = chars[offset]; | ||||
|         while (ch <= ' ' && ((1L << ch) & SPACE) != 0) { | ||||
|  | @ -211,7 +218,9 @@ final class JSONReaderUTF16 | |||
|             ch = chars[offset]; | ||||
|         } | ||||
| 
 | ||||
|         if (ch != quote || (offset + 1 < end && chars[offset + 1] == '#')) { | ||||
|         if (ch != quote | ||||
|                 || (offset + 1 < end && (ch = chars[offset + 1]) != '$' && ch != '.' && ch != '@') | ||||
|         ) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; | |||
| 
 | ||||
| class JSONReaderUTF8 | ||||
|         extends JSONReader { | ||||
|     static final int REF = BIG_ENDIAN ? 0x24726566 : 0x66657224; | ||||
| 
 | ||||
|     protected final byte[] bytes; | ||||
|     protected final int length; | ||||
|     protected final int start; | ||||
|  | @ -4683,8 +4685,11 @@ class JSONReaderUTF8 | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isReference() { | ||||
|     public final boolean isReference() { | ||||
|         // should be codeSize <= FreqInlineSize 325, current : 284 | ||||
|         if ((context.features & MASK_DISABLE_REFERENCE_DETECT) != 0) { | ||||
|             return false; | ||||
|         } | ||||
|         final byte[] bytes = this.bytes; | ||||
|         int ch = this.ch; | ||||
|         if (ch != '{') { | ||||
|  | @ -4705,17 +4710,18 @@ class JSONReaderUTF8 | |||
|             ch = bytes[offset]; | ||||
|         } | ||||
| 
 | ||||
|         int quote = ch; | ||||
|         if (offset + 6 >= end | ||||
|                 || bytes[offset + 1] != '$' | ||||
|                 || bytes[offset + 2] != 'r' | ||||
|                 || bytes[offset + 3] != 'e' | ||||
|                 || bytes[offset + 4] != 'f' | ||||
|                 || bytes[offset + 5] != quote | ||||
|                 || bytes[offset + 5] != ch | ||||
|                 || UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1) != REF | ||||
|         ) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return isReference0(bytes, offset, end, ch); | ||||
|     } | ||||
| 
 | ||||
|     private boolean isReference0(byte[] bytes, int offset, int end, int quote) { | ||||
|         int ch; | ||||
|         offset += 6; | ||||
|         ch = bytes[offset]; | ||||
|         while (ch >= 0 && ch <= ' ' && ((1L << ch) & SPACE) != 0) { | ||||
|  | @ -4739,7 +4745,9 @@ class JSONReaderUTF8 | |||
|             ch = bytes[offset]; | ||||
|         } | ||||
| 
 | ||||
|         if (ch != quote || (offset + 1 < end && bytes[offset + 1] == '#')) { | ||||
|         if (ch != quote | ||||
|                 || (offset + 1 < end && (ch = bytes[offset + 1]) != '$' && ch != '.' && ch != '@') | ||||
|         ) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -121,4 +121,9 @@ public @interface JSONField { | |||
|      * @since 2.0.52 | ||||
|      */ | ||||
|     Class<?> arrayToMapDuplicateHandler() default Void.class; | ||||
| 
 | ||||
|     /** | ||||
|      * @since 2.0.56 | ||||
|      */ | ||||
|     Class<?> contentAs() default Void.class; | ||||
| } | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ public class FieldInfo { | |||
|     public static final long DISABLE_REFERENCE_DETECT = 1L << 58; | ||||
|     public static final long BACKR_EFERENCE = 1L << 61; | ||||
|     public static final long RECORD = 1L << 62; | ||||
|     public static final long CONTENT_AS = 1L << 63; | ||||
| 
 | ||||
|     public String fieldName; | ||||
|     public String format; | ||||
|  | @ -44,6 +45,11 @@ public class FieldInfo { | |||
|     public String arrayToMapKey; | ||||
|     public Class<?> arrayToMapDuplicateHandler; | ||||
| 
 | ||||
|     /** | ||||
|      * @since 2.0.56 | ||||
|      */ | ||||
|     public Class<?> contentAs; | ||||
| 
 | ||||
|     public ObjectReader getInitReader() { | ||||
|         Class<?> calzz = readUsing; | ||||
|         if (calzz != null && ObjectReader.class.isAssignableFrom(calzz)) { | ||||
|  | @ -94,5 +100,6 @@ public class FieldInfo { | |||
| 
 | ||||
|         arrayToMapKey = null; | ||||
|         arrayToMapDuplicateHandler = null; | ||||
|         contentAs = null; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ abstract class FieldWriterList<T> | |||
|     ObjectWriter listWriter; | ||||
|     ObjectWriter itemObjectWriter; | ||||
|     final boolean writeAsString; | ||||
|     final Class<?> contentAs; | ||||
| 
 | ||||
|     FieldWriterList( | ||||
|             String name, | ||||
|  | @ -32,9 +33,11 @@ abstract class FieldWriterList<T> | |||
|             Type fieldType, | ||||
|             Class fieldClass, | ||||
|             Field field, | ||||
|             Method method | ||||
|             Method method, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(name, ordinal, features, format, label, fieldType, fieldClass, field, method); | ||||
|         this.contentAs = contentAs; | ||||
| 
 | ||||
|         writeAsString = (features & WriteNonStringValueAsString.mask) != 0; | ||||
| 
 | ||||
|  | @ -74,6 +77,13 @@ abstract class FieldWriterList<T> | |||
| 
 | ||||
|     @Override | ||||
|     public ObjectWriter getItemWriter(JSONWriter jsonWriter, Type itemType) { | ||||
|         if (contentAs != null) { | ||||
|             ObjectWriter itemObjectWriter = this.itemObjectWriter; | ||||
|             if (itemObjectWriter != null) { | ||||
|                 return itemObjectWriter; | ||||
|             } | ||||
|             return this.itemObjectWriter = jsonWriter.getObjectWriter(this.contentAs, contentAs); | ||||
|         } | ||||
|         if (itemType == null || itemType == this.itemType) { | ||||
|             if (itemObjectWriter != null) { | ||||
|                 return itemObjectWriter; | ||||
|  |  | |||
|  | @ -19,9 +19,10 @@ final class FieldWriterListField<T> | |||
|             String label, | ||||
|             Type fieldType, | ||||
|             Class fieldClass, | ||||
|             Field field | ||||
|             Field field, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field, null); | ||||
|         super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field, null, contentAs); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  |  | |||
|  | @ -23,9 +23,10 @@ final class FieldWriterListFunc<T> | |||
|             Method method, | ||||
|             Function<T, List> function, | ||||
|             Type fieldType, | ||||
|             Class fieldClass | ||||
|             Class fieldClass, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, null, method); | ||||
|         super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, null, method, contentAs); | ||||
|         this.function = function; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,9 +23,10 @@ final class FieldWriterListMethod<T> | |||
|             Field field, | ||||
|             Method method, | ||||
|             Type fieldType, | ||||
|             Class fieldClass | ||||
|             Class fieldClass, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field, method); | ||||
|         super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field, method, contentAs); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  |  | |||
|  | @ -0,0 +1,86 @@ | |||
| package com.alibaba.fastjson2.writer; | ||||
| 
 | ||||
| import com.alibaba.fastjson2.JSONWriter; | ||||
| import com.alibaba.fastjson2.codec.FieldInfo; | ||||
| import com.alibaba.fastjson2.util.ParameterizedTypeImpl; | ||||
| import com.alibaba.fastjson2.util.TypeUtils; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.ParameterizedType; | ||||
| import java.lang.reflect.Type; | ||||
| 
 | ||||
| abstract class FieldWriterMap | ||||
|         extends FieldWriterObject { | ||||
|     protected final Class<?> contentAs; | ||||
|     protected Type contentAsFieldType; | ||||
|     volatile ObjectWriter mapWriter; | ||||
|     private final Type keyType; | ||||
|     private final Type valueType; | ||||
|     final boolean valueTypeRefDetect; | ||||
|     volatile ObjectWriter valueWriter; | ||||
| 
 | ||||
|     protected FieldWriterMap( | ||||
|             String name, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Type fieldType, | ||||
|             Class fieldClass, | ||||
|             Field field, | ||||
|             Method method, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(name, ordinal, features, format, label, fieldType, fieldClass, field, method); | ||||
|         Type keyType = null, valueType = null; | ||||
|         Type contentAsFieldType = null; | ||||
|         if (fieldType instanceof ParameterizedType) { | ||||
|             ParameterizedType pt = (ParameterizedType) fieldType; | ||||
|             Type[] actualTypeArguments = pt.getActualTypeArguments(); | ||||
|             if (actualTypeArguments.length == 2) { | ||||
|                 keyType = actualTypeArguments[0]; | ||||
|                 valueType = actualTypeArguments[1]; | ||||
|             } | ||||
|         } | ||||
|         if (keyType == null) { | ||||
|             keyType = Object.class; | ||||
|         } | ||||
|         if (valueType == null) { | ||||
|             valueType = Object.class; | ||||
|         } | ||||
|         if (contentAs != null) { | ||||
|             contentAsFieldType = new ParameterizedTypeImpl(fieldClass, String.class, contentAs); | ||||
|         } | ||||
|         this.contentAs = contentAs; | ||||
|         this.contentAsFieldType = contentAsFieldType; | ||||
|         this.keyType = keyType; | ||||
|         this.valueType = valueType; | ||||
|         this.valueTypeRefDetect = !ObjectWriterProvider.isNotReferenceDetect(TypeUtils.getClass(valueType)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ObjectWriter getObjectWriter(JSONWriter jsonWriter, Class valueClass) { | ||||
|         Class<?> contentAs = this.contentAs; | ||||
|         if (contentAs == null || !fieldClass.isAssignableFrom(valueClass)) { | ||||
|             return super.getObjectWriter(jsonWriter, valueClass); | ||||
|         } | ||||
| 
 | ||||
|         ObjectWriter valueWriter = this.valueWriter; | ||||
|         if (valueWriter != null) { | ||||
|             return valueWriter; | ||||
|         } | ||||
| 
 | ||||
|         Type fieldType = this.fieldType; | ||||
|         Type valueType = this.valueType; | ||||
|         long features = this.features; | ||||
|         if (contentAs != null) { | ||||
|             valueType = contentAs; | ||||
|             fieldType = contentAsFieldType; | ||||
|             features |= FieldInfo.CONTENT_AS; | ||||
|         } | ||||
|         valueWriter = new ObjectWriterImplMap(keyType, valueType, valueClass, fieldType, features); | ||||
|         this.mapWriter = valueWriter; | ||||
|         return valueWriter; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,23 @@ | |||
| package com.alibaba.fastjson2.writer; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Type; | ||||
| 
 | ||||
| final class FieldWriterMapField | ||||
|         extends FieldWriterMap { | ||||
|     FieldWriterMapField( | ||||
|             String name, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Type fieldType, | ||||
|             Class fieldClass, | ||||
|             Field field, | ||||
|             Method method, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(name, ordinal, features, format, label, fieldType, fieldClass, field, method, contentAs); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,33 @@ | |||
| package com.alibaba.fastjson2.writer; | ||||
| 
 | ||||
| import com.alibaba.fastjson2.function.Function; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Type; | ||||
| 
 | ||||
| final class FieldWriterMapFunction | ||||
|         extends FieldWriterMap { | ||||
|     final Function function; | ||||
|     FieldWriterMapFunction( | ||||
|             String name, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Type fieldType, | ||||
|             Class fieldClass, | ||||
|             Field field, | ||||
|             Method method, | ||||
|             Function function, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(name, ordinal, features, format, label, fieldType, fieldClass, field, method, contentAs); | ||||
|         this.function = function; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Object getFieldValue(Object object) { | ||||
|         return function.apply(object); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,35 @@ | |||
| package com.alibaba.fastjson2.writer; | ||||
| 
 | ||||
| import com.alibaba.fastjson2.JSONException; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Type; | ||||
| 
 | ||||
| final class FieldWriterMapMethod | ||||
|         extends FieldWriterMap { | ||||
|     FieldWriterMapMethod( | ||||
|             String name, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Type fieldType, | ||||
|             Class fieldClass, | ||||
|             Field field, | ||||
|             Method method, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         super(name, ordinal, features, format, label, fieldType, fieldClass, field, method, contentAs); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Object getFieldValue(Object object) { | ||||
|         try { | ||||
|             return method.invoke(object); | ||||
|         } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { | ||||
|             throw new JSONException("invoke getter method error, " + fieldName, e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -223,7 +223,7 @@ public class ObjectWriterCreator { | |||
|             format = beanInfo.format; | ||||
|         } | ||||
| 
 | ||||
|         return createFieldWriter(provider, fieldName, fieldInfo.ordinal, fieldInfo.features, format, fieldInfo.label, field, writeUsingWriter); | ||||
|         return createFieldWriter(provider, fieldName, fieldInfo.ordinal, fieldInfo.features, format, fieldInfo.label, field, writeUsingWriter, fieldInfo.contentAs); | ||||
|     } | ||||
| 
 | ||||
|     public ObjectWriter createObjectWriter( | ||||
|  | @ -362,7 +362,8 @@ public class ObjectWriterCreator { | |||
|                             fieldInfo.format, | ||||
|                             fieldInfo.label, | ||||
|                             method, | ||||
|                             writeUsingWriter | ||||
|                             writeUsingWriter, | ||||
|                             fieldInfo.contentAs | ||||
|                     ); | ||||
| 
 | ||||
|                     FieldWriter origin = fieldWriterMap.get(fieldWriter.fieldName); | ||||
|  | @ -574,6 +575,20 @@ public class ObjectWriterCreator { | |||
|             String label, | ||||
|             Field field, | ||||
|             ObjectWriter initObjectWriter | ||||
|     ) { | ||||
|         return createFieldWriter(provider, fieldName, ordinal, features, format, label, field, initObjectWriter, null); | ||||
|     } | ||||
| 
 | ||||
|     public <T> FieldWriter<T> createFieldWriter( | ||||
|             ObjectWriterProvider provider, | ||||
|             String fieldName, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Field field, | ||||
|             ObjectWriter initObjectWriter, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         Class<?> declaringClass = field.getDeclaringClass(); | ||||
|         Method method = null; | ||||
|  | @ -701,7 +716,11 @@ public class ObjectWriterCreator { | |||
|             if (fieldType instanceof ParameterizedType) { | ||||
|                 itemType = ((ParameterizedType) fieldType).getActualTypeArguments()[0]; | ||||
|             } | ||||
|             return new FieldWriterListField(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field); | ||||
|             return new FieldWriterListField(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field, contentAs); | ||||
|         } | ||||
| 
 | ||||
|         if (Map.class.isAssignableFrom(fieldClass)) { | ||||
|             return new FieldWriterMapField(fieldName, ordinal, features, format, label, field.getGenericType(), fieldClass, field, null, contentAs); | ||||
|         } | ||||
| 
 | ||||
|         if (fieldClass.isArray() && !fieldClass.getComponentType().isPrimitive()) { | ||||
|  | @ -739,6 +758,21 @@ public class ObjectWriterCreator { | |||
|             String label, | ||||
|             Method method, | ||||
|             ObjectWriter initObjectWriter | ||||
|     ) { | ||||
|         return createFieldWriter(provider, objectType, fieldName, ordinal, features, format, label, method, initObjectWriter, null); | ||||
|     } | ||||
| 
 | ||||
|     public <T> FieldWriter<T> createFieldWriter( | ||||
|             ObjectWriterProvider provider, | ||||
|             Class<T> objectType, | ||||
|             String fieldName, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Method method, | ||||
|             ObjectWriter initObjectWriter, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         Class<?> fieldClass = method.getReturnType(); | ||||
|         Type fieldType = method.getGenericReturnType(); | ||||
|  | @ -848,7 +882,11 @@ public class ObjectWriterCreator { | |||
|             } else { | ||||
|                 itemType = Object.class; | ||||
|             } | ||||
|             return new FieldWriterListMethod(fieldName, itemType, ordinal, features, format, label, field, method, fieldType, fieldClass); | ||||
|             return new FieldWriterListMethod(fieldName, itemType, ordinal, features, format, label, field, method, fieldType, fieldClass, contentAs); | ||||
|         } | ||||
| 
 | ||||
|         if (Map.class.isAssignableFrom(fieldClass)) { | ||||
|             return new FieldWriterMapMethod(fieldName, ordinal, features, format, label, fieldType, fieldClass, field, method, contentAs); | ||||
|         } | ||||
| 
 | ||||
|         if (fieldClass == Float[].class) { | ||||
|  | @ -933,6 +971,23 @@ public class ObjectWriterCreator { | |||
|             Class<V> fieldClass, | ||||
|             Method method, | ||||
|             Function<T, V> function | ||||
|     ) { | ||||
|         return createFieldWriter(provider, objectClass, fieldName, ordinal, features, format, label, fieldType, fieldClass, method, function, null); | ||||
|     } | ||||
| 
 | ||||
|     public <T, V> FieldWriter<T> createFieldWriter( | ||||
|             ObjectWriterProvider provider, | ||||
|             Class<T> objectClass, | ||||
|             String fieldName, | ||||
|             int ordinal, | ||||
|             long features, | ||||
|             String format, | ||||
|             String label, | ||||
|             Type fieldType, | ||||
|             Class<V> fieldClass, | ||||
|             Method method, | ||||
|             Function<T, V> function, | ||||
|             Class<?> contentAs | ||||
|     ) { | ||||
|         if (fieldClass == Byte.class) { | ||||
|             return new FieldWriterInt8Func(fieldName, ordinal, features, format, label, method, function); | ||||
|  | @ -1008,9 +1063,13 @@ public class ObjectWriterCreator { | |||
|                     if (itemType == String.class) { | ||||
|                         return new FieldWriterListStrFunc(fieldName, ordinal, features, format, label, method, function, fieldType, fieldClass); | ||||
|                     } | ||||
|                     return new FieldWriterListFunc(fieldName, ordinal, features, format, label, itemType, method, function, fieldType, fieldClass); | ||||
|                     return new FieldWriterListFunc(fieldName, ordinal, features, format, label, itemType, method, function, fieldType, fieldClass, contentAs); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (rawType instanceof Class && Map.class.isAssignableFrom((Class<?>) rawType)) { | ||||
|                 return new FieldWriterMapFunction(fieldName, ordinal, features, format, label, fieldType, fieldClass, null, method, function, contentAs); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (Modifier.isFinal(fieldClass.getModifiers())) { | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package com.alibaba.fastjson2.writer; | ||||
| 
 | ||||
| import com.alibaba.fastjson2.*; | ||||
| import com.alibaba.fastjson2.codec.FieldInfo; | ||||
| import com.alibaba.fastjson2.filter.*; | ||||
| import com.alibaba.fastjson2.util.*; | ||||
| 
 | ||||
|  | @ -43,6 +44,8 @@ public final class ObjectWriterImplMap | |||
|     final char[] typeInfoUTF16; | ||||
|     final byte[] typeInfoUTF8; | ||||
| 
 | ||||
|     final boolean contentAs; | ||||
| 
 | ||||
|     public ObjectWriterImplMap(Class objectClass, long features) { | ||||
|         this(null, null, objectClass, objectClass, features); | ||||
|     } | ||||
|  | @ -59,6 +62,7 @@ public final class ObjectWriterImplMap | |||
|         } else { | ||||
|             this.valueTypeRefDetect = !ObjectWriterProvider.isNotReferenceDetect(TypeUtils.getClass(valueType)); | ||||
|         } | ||||
|         contentAs = (features & FieldInfo.CONTENT_AS) != 0; | ||||
| 
 | ||||
|         String typeName = TypeUtils.getTypeName(objectClass); | ||||
|         String typeInfoStr = "\"@type\":\"" + objectClass.getName() + "\""; | ||||
|  | @ -148,7 +152,12 @@ public final class ObjectWriterImplMap | |||
| 
 | ||||
|             jsonWriter.writeString(key); | ||||
| 
 | ||||
|             Class<?> valueType = value.getClass(); | ||||
|             Class valueType; | ||||
|             if (contentAs) { | ||||
|                 valueType = (Class) this.valueType; | ||||
|             } else { | ||||
|                 valueType = value.getClass(); | ||||
|             } | ||||
|             if (valueType == String.class) { | ||||
|                 jsonWriter.writeString((String) value); | ||||
|             } else { | ||||
|  | @ -279,7 +288,12 @@ public final class ObjectWriterImplMap | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Class<?> valueClass = value.getClass(); | ||||
|             Class valueClass; | ||||
|             if (contentAs) { | ||||
|                 valueClass = (Class) this.valueType; | ||||
|             } else { | ||||
|                 valueClass = value.getClass(); | ||||
|             } | ||||
|             if (valueClass == String.class) { | ||||
|                 jsonWriter.writeString((String) value); | ||||
|                 continue; | ||||
|  | @ -480,7 +494,12 @@ public final class ObjectWriterImplMap | |||
|             } | ||||
|             jsonWriter.writeColon(); | ||||
| 
 | ||||
|             Class<?> valueClass = value.getClass(); | ||||
|             Class valueClass; | ||||
|             if (contentAs) { | ||||
|                 valueClass = (Class) this.valueType; | ||||
|             } else { | ||||
|                 valueClass = value.getClass(); | ||||
|             } | ||||
|             if (valueClass == String.class) { | ||||
|                 jsonWriter.writeString((String) value); | ||||
|                 continue; | ||||
|  | @ -654,7 +673,12 @@ public final class ObjectWriterImplMap | |||
|                 if (value == null) { | ||||
|                     jsonWriter.writeNull(); | ||||
|                 } else { | ||||
|                     Class<?> valueType = value.getClass(); | ||||
|                     Class valueType; | ||||
|                     if (contentAs) { | ||||
|                         valueType = (Class) this.valueType; | ||||
|                     } else { | ||||
|                         valueType = value.getClass(); | ||||
|                     } | ||||
|                     ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueType); | ||||
|                     valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features); | ||||
|                 } | ||||
|  |  | |||
|  | @ -634,6 +634,11 @@ public class ObjectWriterProvider { | |||
|         ) { | ||||
|             fieldInfo.writeUsing = ObjectWriterImplToString.class; | ||||
|         } | ||||
| 
 | ||||
|         Class<?> contentAs = jsonField.contentAs(); | ||||
|         if (contentAs != Void.class) { | ||||
|             fieldInfo.contentAs = contentAs; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void processJSONField1x(FieldInfo fieldInfo, Annotation annotation) { | ||||
|  |  | |||
|  | @ -0,0 +1,111 @@ | |||
| package com.alibaba.fastjson2.features; | ||||
| 
 | ||||
| import com.alibaba.fastjson2.JSON; | ||||
| import com.alibaba.fastjson2.annotation.JSONField; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| 
 | ||||
| public class ContentAsTest { | ||||
|     class Vehicle { | ||||
|         private String type; | ||||
| 
 | ||||
|         public Vehicle(String type) { this.type = type; } | ||||
|         public String getType() { return type; } | ||||
|     } | ||||
| 
 | ||||
|     class Car | ||||
|             extends Vehicle { | ||||
|         private int seats; | ||||
| 
 | ||||
|         public Car(String type, int seats) { | ||||
|             super(type); | ||||
|             this.seats = seats; | ||||
|         } | ||||
|         public int getSeats() { return seats; } | ||||
|     } | ||||
| 
 | ||||
|     class Garage { | ||||
|         @JSONField(contentAs = Vehicle.class) | ||||
|         private List<Vehicle> vehicles = new ArrayList<>(); | ||||
| 
 | ||||
|         public void addVehicle(Vehicle v) { vehicles.add(v); } | ||||
|         public List<Vehicle> getVehicles() { return vehicles; } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void test() throws Exception { | ||||
|         Garage garage = new Garage(); | ||||
|         garage.addVehicle(new Car("Sedan", 5)); | ||||
|         garage.addVehicle(new Car("SUV", 7)); | ||||
| 
 | ||||
|         assertEquals( | ||||
|                 "{\"vehicles\":[{\"type\":\"Sedan\"},{\"type\":\"SUV\"}]}", | ||||
|                 JSON.toJSONString(garage)); | ||||
|     } | ||||
| 
 | ||||
|     class GarageField { | ||||
|         @JSONField(contentAs = Vehicle.class) | ||||
|         public List<Vehicle> vehicles = new ArrayList<>(); | ||||
| 
 | ||||
|         public void addVehicle(Vehicle v) { vehicles.add(v); } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testField() throws Exception { | ||||
|         GarageField garage = new GarageField(); | ||||
|         garage.addVehicle(new Car("Sedan", 5)); | ||||
|         garage.addVehicle(new Car("SUV", 7)); | ||||
| 
 | ||||
|         assertEquals( | ||||
|                 "{\"vehicles\":[{\"type\":\"Sedan\"},{\"type\":\"SUV\"}]}", | ||||
|                 JSON.toJSONString(garage)); | ||||
|     } | ||||
| 
 | ||||
|     class GarageMap { | ||||
|         @JSONField(contentAs = Vehicle.class) | ||||
|         private Map<String, Vehicle> vehicles = new LinkedHashMap<>(); | ||||
| 
 | ||||
|         public void addVehicle(Vehicle v) { | ||||
|             vehicles.put(v.getType(), v); | ||||
|         } | ||||
| 
 | ||||
|         public Map<String, Vehicle> getVehicles() { | ||||
|             return vehicles; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testMap() throws Exception { | ||||
|         GarageMap garage = new GarageMap(); | ||||
|         garage.addVehicle(new Car("Sedan", 5)); | ||||
|         garage.addVehicle(new Car("SUV", 7)); | ||||
| 
 | ||||
|         String json = JSON.toJSONString(garage); | ||||
|         assertEquals("{\"vehicles\":{\"Sedan\":{\"type\":\"Sedan\"},\"SUV\":{\"type\":\"SUV\"}}}", json); | ||||
|     } | ||||
| 
 | ||||
|     class GarageMapField { | ||||
|         @JSONField(contentAs = Vehicle.class) | ||||
|         public Map<String, Vehicle> vehicles = new LinkedHashMap<>(); | ||||
| 
 | ||||
|         public void addVehicle(Vehicle v) { | ||||
|             vehicles.put(v.getType(), v); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testMapField() throws Exception { | ||||
|         GarageMapField garage = new GarageMapField(); | ||||
|         garage.addVehicle(new Car("Sedan", 5)); | ||||
|         garage.addVehicle(new Car("SUV", 7)); | ||||
| 
 | ||||
|         String json = JSON.toJSONString(garage); | ||||
|         assertEquals("{\"vehicles\":{\"Sedan\":{\"type\":\"Sedan\"},\"SUV\":{\"type\":\"SUV\"}}}", json); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,34 @@ | |||
| package com.alibaba.fastjson2.issues_3300; | ||||
| 
 | ||||
| import com.alibaba.fastjson2.JSON; | ||||
| import com.alibaba.fastjson2.JSONObject; | ||||
| import com.alibaba.fastjson2.JSONReader; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.nio.charset.StandardCharsets; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| 
 | ||||
| public class Issue3347 { | ||||
|     @Test | ||||
|     public void test() { | ||||
|         String json2 = "{\"*/*\":{\"schema\":{\"$ref\":\"Error-ModelName{namespace='javax.servlet.http', name='HttpServletResponse'}\"}}}"; | ||||
|         String expected = "Error-ModelName{namespace='javax.servlet.http', name='HttpServletResponse'}"; | ||||
|         { | ||||
|             JSONObject jsonObject4 = JSON.parseObject(json2); | ||||
|             assertEquals(expected, jsonObject4.getJSONObject("*/*").getJSONObject("schema").getString("$ref")); | ||||
|         } | ||||
|         { | ||||
|             JSONObject jsonObject4 = JSON.parseObject(json2.getBytes(StandardCharsets.UTF_8)); | ||||
|             assertEquals(expected, jsonObject4.getJSONObject("*/*").getJSONObject("schema").getString("$ref")); | ||||
|         } | ||||
|         { | ||||
|             JSONObject jsonObject4 = JSON.parseObject(json2.toCharArray()); | ||||
|             assertEquals(expected, jsonObject4.getJSONObject("*/*").getJSONObject("schema").getString("$ref")); | ||||
|         } | ||||
|         { | ||||
|             JSONObject jsonObject4 = JSON.parseObject(json2, JSONReader.Feature.DisableReferenceDetect); | ||||
|             assertEquals(expected, jsonObject4.getJSONObject("*/*").getJSONObject("schema").getString("$ref")); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										2
									
								
								pom.xml
								
								
								
								
							
							
						
						
									
										2
									
								
								pom.xml
								
								
								
								
							|  | @ -6,7 +6,7 @@ | |||
| 
 | ||||
|     <groupId>com.alibaba.fastjson2</groupId> | ||||
|     <artifactId>fastjson2-parent</artifactId> | ||||
|     <version>2.0.55.android5</version> | ||||
|     <version>2.0.56.android5</version> | ||||
|     <name>${project.artifactId}</name> | ||||
|     <description>Fastjson is a JSON processor (JSON parser + JSON generator) written in Java</description> | ||||
|     <packaging>pom</packaging> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue