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>
|
<parent>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
<artifactId>fastjson2-parent</artifactId>
|
<artifactId>fastjson2-parent</artifactId>
|
||||||
<version>2.0.55.android5</version>
|
<version>2.0.56.android5</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
<artifactId>fastjson2-parent</artifactId>
|
<artifactId>fastjson2-parent</artifactId>
|
||||||
<version>2.0.55.android5</version>
|
<version>2.0.56.android5</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
<artifactId>fastjson2-parent</artifactId>
|
<artifactId>fastjson2-parent</artifactId>
|
||||||
<version>2.0.55.android5</version>
|
<version>2.0.56.android5</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ public interface JSON {
|
||||||
/**
|
/**
|
||||||
* fastjson2 version name
|
* fastjson2 version name
|
||||||
*/
|
*/
|
||||||
String VERSION = "2.0.55";
|
String VERSION = "2.0.56";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the json string as a {@link JSONArray} or {@link JSONObject}.
|
* 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 {
|
public enum Feature {
|
||||||
FieldBased(1),
|
FieldBased(1),
|
||||||
|
|
@ -3917,7 +3918,12 @@ public abstract class JSONReader
|
||||||
/**
|
/**
|
||||||
* @since 2.0.53
|
* @since 2.0.53
|
||||||
*/
|
*/
|
||||||
UseDoubleForDecimals(1L << 32L);
|
UseDoubleForDecimals(1L << 32L),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0.56
|
||||||
|
*/
|
||||||
|
DisableReferenceDetect(MASK_DISABLE_REFERENCE_DETECT);
|
||||||
|
|
||||||
public final long mask;
|
public final long mask;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,10 @@ final class JSONReaderUTF16
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isReference() {
|
public final boolean isReference() {
|
||||||
|
if ((context.features & MASK_DISABLE_REFERENCE_DETECT) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// should be codeSize <= FreqInlineSize 325, current is 276
|
// should be codeSize <= FreqInlineSize 325, current is 276
|
||||||
final char[] chars = this.chars;
|
final char[] chars = this.chars;
|
||||||
char ch = this.ch;
|
char ch = this.ch;
|
||||||
|
|
@ -188,6 +190,11 @@ final class JSONReaderUTF16
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isReference0(chars, offset, end, quote);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReference0(char[] chars, int offset, int end, char quote) {
|
||||||
|
char ch;
|
||||||
offset += 6;
|
offset += 6;
|
||||||
ch = chars[offset];
|
ch = chars[offset];
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
|
@ -211,7 +218,9 @@ final class JSONReaderUTF16
|
||||||
ch = chars[offset];
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
class JSONReaderUTF8
|
class JSONReaderUTF8
|
||||||
extends JSONReader {
|
extends JSONReader {
|
||||||
|
static final int REF = BIG_ENDIAN ? 0x24726566 : 0x66657224;
|
||||||
|
|
||||||
protected final byte[] bytes;
|
protected final byte[] bytes;
|
||||||
protected final int length;
|
protected final int length;
|
||||||
protected final int start;
|
protected final int start;
|
||||||
|
|
@ -4683,8 +4685,11 @@ class JSONReaderUTF8
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReference() {
|
public final boolean isReference() {
|
||||||
// should be codeSize <= FreqInlineSize 325, current : 284
|
// should be codeSize <= FreqInlineSize 325, current : 284
|
||||||
|
if ((context.features & MASK_DISABLE_REFERENCE_DETECT) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
final byte[] bytes = this.bytes;
|
final byte[] bytes = this.bytes;
|
||||||
int ch = this.ch;
|
int ch = this.ch;
|
||||||
if (ch != '{') {
|
if (ch != '{') {
|
||||||
|
|
@ -4705,17 +4710,18 @@ class JSONReaderUTF8
|
||||||
ch = bytes[offset];
|
ch = bytes[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
int quote = ch;
|
|
||||||
if (offset + 6 >= end
|
if (offset + 6 >= end
|
||||||
|| bytes[offset + 1] != '$'
|
|| bytes[offset + 5] != ch
|
||||||
|| bytes[offset + 2] != 'r'
|
|| UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset + 1) != REF
|
||||||
|| bytes[offset + 3] != 'e'
|
|
||||||
|| bytes[offset + 4] != 'f'
|
|
||||||
|| bytes[offset + 5] != quote
|
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isReference0(bytes, offset, end, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReference0(byte[] bytes, int offset, int end, int quote) {
|
||||||
|
int ch;
|
||||||
offset += 6;
|
offset += 6;
|
||||||
ch = bytes[offset];
|
ch = bytes[offset];
|
||||||
while (ch >= 0 && ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
while (ch >= 0 && ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
|
@ -4739,7 +4745,9 @@ class JSONReaderUTF8
|
||||||
ch = bytes[offset];
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,4 +121,9 @@ public @interface JSONField {
|
||||||
* @since 2.0.52
|
* @since 2.0.52
|
||||||
*/
|
*/
|
||||||
Class<?> arrayToMapDuplicateHandler() default Void.class;
|
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 DISABLE_REFERENCE_DETECT = 1L << 58;
|
||||||
public static final long BACKR_EFERENCE = 1L << 61;
|
public static final long BACKR_EFERENCE = 1L << 61;
|
||||||
public static final long RECORD = 1L << 62;
|
public static final long RECORD = 1L << 62;
|
||||||
|
public static final long CONTENT_AS = 1L << 63;
|
||||||
|
|
||||||
public String fieldName;
|
public String fieldName;
|
||||||
public String format;
|
public String format;
|
||||||
|
|
@ -44,6 +45,11 @@ public class FieldInfo {
|
||||||
public String arrayToMapKey;
|
public String arrayToMapKey;
|
||||||
public Class<?> arrayToMapDuplicateHandler;
|
public Class<?> arrayToMapDuplicateHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0.56
|
||||||
|
*/
|
||||||
|
public Class<?> contentAs;
|
||||||
|
|
||||||
public ObjectReader getInitReader() {
|
public ObjectReader getInitReader() {
|
||||||
Class<?> calzz = readUsing;
|
Class<?> calzz = readUsing;
|
||||||
if (calzz != null && ObjectReader.class.isAssignableFrom(calzz)) {
|
if (calzz != null && ObjectReader.class.isAssignableFrom(calzz)) {
|
||||||
|
|
@ -94,5 +100,6 @@ public class FieldInfo {
|
||||||
|
|
||||||
arrayToMapKey = null;
|
arrayToMapKey = null;
|
||||||
arrayToMapDuplicateHandler = null;
|
arrayToMapDuplicateHandler = null;
|
||||||
|
contentAs = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ abstract class FieldWriterList<T>
|
||||||
ObjectWriter listWriter;
|
ObjectWriter listWriter;
|
||||||
ObjectWriter itemObjectWriter;
|
ObjectWriter itemObjectWriter;
|
||||||
final boolean writeAsString;
|
final boolean writeAsString;
|
||||||
|
final Class<?> contentAs;
|
||||||
|
|
||||||
FieldWriterList(
|
FieldWriterList(
|
||||||
String name,
|
String name,
|
||||||
|
|
@ -32,9 +33,11 @@ abstract class FieldWriterList<T>
|
||||||
Type fieldType,
|
Type fieldType,
|
||||||
Class fieldClass,
|
Class fieldClass,
|
||||||
Field field,
|
Field field,
|
||||||
Method method
|
Method method,
|
||||||
|
Class<?> contentAs
|
||||||
) {
|
) {
|
||||||
super(name, ordinal, features, format, label, fieldType, fieldClass, field, method);
|
super(name, ordinal, features, format, label, fieldType, fieldClass, field, method);
|
||||||
|
this.contentAs = contentAs;
|
||||||
|
|
||||||
writeAsString = (features & WriteNonStringValueAsString.mask) != 0;
|
writeAsString = (features & WriteNonStringValueAsString.mask) != 0;
|
||||||
|
|
||||||
|
|
@ -74,6 +77,13 @@ abstract class FieldWriterList<T>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectWriter getItemWriter(JSONWriter jsonWriter, Type itemType) {
|
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 (itemType == null || itemType == this.itemType) {
|
||||||
if (itemObjectWriter != null) {
|
if (itemObjectWriter != null) {
|
||||||
return itemObjectWriter;
|
return itemObjectWriter;
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,10 @@ final class FieldWriterListField<T>
|
||||||
String label,
|
String label,
|
||||||
Type fieldType,
|
Type fieldType,
|
||||||
Class fieldClass,
|
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
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,10 @@ final class FieldWriterListFunc<T>
|
||||||
Method method,
|
Method method,
|
||||||
Function<T, List> function,
|
Function<T, List> function,
|
||||||
Type fieldType,
|
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;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,10 @@ final class FieldWriterListMethod<T>
|
||||||
Field field,
|
Field field,
|
||||||
Method method,
|
Method method,
|
||||||
Type fieldType,
|
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
|
@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;
|
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(
|
public ObjectWriter createObjectWriter(
|
||||||
|
|
@ -362,7 +362,8 @@ public class ObjectWriterCreator {
|
||||||
fieldInfo.format,
|
fieldInfo.format,
|
||||||
fieldInfo.label,
|
fieldInfo.label,
|
||||||
method,
|
method,
|
||||||
writeUsingWriter
|
writeUsingWriter,
|
||||||
|
fieldInfo.contentAs
|
||||||
);
|
);
|
||||||
|
|
||||||
FieldWriter origin = fieldWriterMap.get(fieldWriter.fieldName);
|
FieldWriter origin = fieldWriterMap.get(fieldWriter.fieldName);
|
||||||
|
|
@ -574,6 +575,20 @@ public class ObjectWriterCreator {
|
||||||
String label,
|
String label,
|
||||||
Field field,
|
Field field,
|
||||||
ObjectWriter initObjectWriter
|
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();
|
Class<?> declaringClass = field.getDeclaringClass();
|
||||||
Method method = null;
|
Method method = null;
|
||||||
|
|
@ -701,7 +716,11 @@ public class ObjectWriterCreator {
|
||||||
if (fieldType instanceof ParameterizedType) {
|
if (fieldType instanceof ParameterizedType) {
|
||||||
itemType = ((ParameterizedType) fieldType).getActualTypeArguments()[0];
|
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()) {
|
if (fieldClass.isArray() && !fieldClass.getComponentType().isPrimitive()) {
|
||||||
|
|
@ -739,6 +758,21 @@ public class ObjectWriterCreator {
|
||||||
String label,
|
String label,
|
||||||
Method method,
|
Method method,
|
||||||
ObjectWriter initObjectWriter
|
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();
|
Class<?> fieldClass = method.getReturnType();
|
||||||
Type fieldType = method.getGenericReturnType();
|
Type fieldType = method.getGenericReturnType();
|
||||||
|
|
@ -848,7 +882,11 @@ public class ObjectWriterCreator {
|
||||||
} else {
|
} else {
|
||||||
itemType = Object.class;
|
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) {
|
if (fieldClass == Float[].class) {
|
||||||
|
|
@ -933,6 +971,23 @@ public class ObjectWriterCreator {
|
||||||
Class<V> fieldClass,
|
Class<V> fieldClass,
|
||||||
Method method,
|
Method method,
|
||||||
Function<T, V> function
|
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) {
|
if (fieldClass == Byte.class) {
|
||||||
return new FieldWriterInt8Func(fieldName, ordinal, features, format, label, method, function);
|
return new FieldWriterInt8Func(fieldName, ordinal, features, format, label, method, function);
|
||||||
|
|
@ -1008,9 +1063,13 @@ public class ObjectWriterCreator {
|
||||||
if (itemType == String.class) {
|
if (itemType == String.class) {
|
||||||
return new FieldWriterListStrFunc(fieldName, ordinal, features, format, label, method, function, fieldType, fieldClass);
|
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())) {
|
if (Modifier.isFinal(fieldClass.getModifiers())) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.alibaba.fastjson2.writer;
|
package com.alibaba.fastjson2.writer;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.*;
|
import com.alibaba.fastjson2.*;
|
||||||
|
import com.alibaba.fastjson2.codec.FieldInfo;
|
||||||
import com.alibaba.fastjson2.filter.*;
|
import com.alibaba.fastjson2.filter.*;
|
||||||
import com.alibaba.fastjson2.util.*;
|
import com.alibaba.fastjson2.util.*;
|
||||||
|
|
||||||
|
|
@ -43,6 +44,8 @@ public final class ObjectWriterImplMap
|
||||||
final char[] typeInfoUTF16;
|
final char[] typeInfoUTF16;
|
||||||
final byte[] typeInfoUTF8;
|
final byte[] typeInfoUTF8;
|
||||||
|
|
||||||
|
final boolean contentAs;
|
||||||
|
|
||||||
public ObjectWriterImplMap(Class objectClass, long features) {
|
public ObjectWriterImplMap(Class objectClass, long features) {
|
||||||
this(null, null, objectClass, objectClass, features);
|
this(null, null, objectClass, objectClass, features);
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +62,7 @@ public final class ObjectWriterImplMap
|
||||||
} else {
|
} else {
|
||||||
this.valueTypeRefDetect = !ObjectWriterProvider.isNotReferenceDetect(TypeUtils.getClass(valueType));
|
this.valueTypeRefDetect = !ObjectWriterProvider.isNotReferenceDetect(TypeUtils.getClass(valueType));
|
||||||
}
|
}
|
||||||
|
contentAs = (features & FieldInfo.CONTENT_AS) != 0;
|
||||||
|
|
||||||
String typeName = TypeUtils.getTypeName(objectClass);
|
String typeName = TypeUtils.getTypeName(objectClass);
|
||||||
String typeInfoStr = "\"@type\":\"" + objectClass.getName() + "\"";
|
String typeInfoStr = "\"@type\":\"" + objectClass.getName() + "\"";
|
||||||
|
|
@ -148,7 +152,12 @@ public final class ObjectWriterImplMap
|
||||||
|
|
||||||
jsonWriter.writeString(key);
|
jsonWriter.writeString(key);
|
||||||
|
|
||||||
Class<?> valueType = value.getClass();
|
Class valueType;
|
||||||
|
if (contentAs) {
|
||||||
|
valueType = (Class) this.valueType;
|
||||||
|
} else {
|
||||||
|
valueType = value.getClass();
|
||||||
|
}
|
||||||
if (valueType == String.class) {
|
if (valueType == String.class) {
|
||||||
jsonWriter.writeString((String) value);
|
jsonWriter.writeString((String) value);
|
||||||
} else {
|
} 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) {
|
if (valueClass == String.class) {
|
||||||
jsonWriter.writeString((String) value);
|
jsonWriter.writeString((String) value);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -480,7 +494,12 @@ public final class ObjectWriterImplMap
|
||||||
}
|
}
|
||||||
jsonWriter.writeColon();
|
jsonWriter.writeColon();
|
||||||
|
|
||||||
Class<?> valueClass = value.getClass();
|
Class valueClass;
|
||||||
|
if (contentAs) {
|
||||||
|
valueClass = (Class) this.valueType;
|
||||||
|
} else {
|
||||||
|
valueClass = value.getClass();
|
||||||
|
}
|
||||||
if (valueClass == String.class) {
|
if (valueClass == String.class) {
|
||||||
jsonWriter.writeString((String) value);
|
jsonWriter.writeString((String) value);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -654,7 +673,12 @@ public final class ObjectWriterImplMap
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
jsonWriter.writeNull();
|
jsonWriter.writeNull();
|
||||||
} else {
|
} else {
|
||||||
Class<?> valueType = value.getClass();
|
Class valueType;
|
||||||
|
if (contentAs) {
|
||||||
|
valueType = (Class) this.valueType;
|
||||||
|
} else {
|
||||||
|
valueType = value.getClass();
|
||||||
|
}
|
||||||
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueType);
|
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueType);
|
||||||
valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
|
valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -634,6 +634,11 @@ public class ObjectWriterProvider {
|
||||||
) {
|
) {
|
||||||
fieldInfo.writeUsing = ObjectWriterImplToString.class;
|
fieldInfo.writeUsing = ObjectWriterImplToString.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Class<?> contentAs = jsonField.contentAs();
|
||||||
|
if (contentAs != Void.class) {
|
||||||
|
fieldInfo.contentAs = contentAs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processJSONField1x(FieldInfo fieldInfo, Annotation annotation) {
|
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>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
<artifactId>fastjson2-parent</artifactId>
|
<artifactId>fastjson2-parent</artifactId>
|
||||||
<version>2.0.55.android5</version>
|
<version>2.0.56.android5</version>
|
||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
||||||
<description>Fastjson is a JSON processor (JSON parser + JSON generator) written in Java</description>
|
<description>Fastjson is a JSON processor (JSON parser + JSON generator) written in Java</description>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue