Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f8186d8378 | ||
![]() |
d772d2cd9f | ||
![]() |
20b47d44b8 | ||
![]() |
6b68529a7f | ||
![]() |
25006c75e6 | ||
![]() |
a6cdd59d06 | ||
![]() |
b7cc4438ca | ||
![]() |
fce3b4c445 | ||
![]() |
57fa6b5e77 |
@ -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;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ public class FieldInfo {
|
||||
public static final long DISABLE_JSONB = 1L << 60;
|
||||
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;
|
||||
@ -46,6 +47,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)) {
|
||||
@ -97,5 +103,6 @@ public class FieldInfo {
|
||||
|
||||
arrayToMapKey = null;
|
||||
arrayToMapDuplicateHandler = null;
|
||||
contentAs = null;
|
||||
}
|
||||
}
|
||||
|
@ -1308,10 +1308,16 @@ public class ObjectReaderBaseModule
|
||||
if (!keyName.isEmpty()) {
|
||||
fieldInfo.arrayToMapKey = keyName;
|
||||
}
|
||||
|
||||
Class<?> arrayToMapDuplicateHandler = jsonField.arrayToMapDuplicateHandler();
|
||||
if (arrayToMapDuplicateHandler != Void.class) {
|
||||
fieldInfo.arrayToMapDuplicateHandler = arrayToMapDuplicateHandler;
|
||||
}
|
||||
|
||||
Class<?> contentAs = jsonField.contentAs();
|
||||
if (contentAs != Void.class) {
|
||||
fieldInfo.contentAs = contentAs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ abstract class FieldWriterList<T>
|
||||
ObjectWriter listWriter;
|
||||
ObjectWriter itemObjectWriter;
|
||||
final boolean writeAsString;
|
||||
final Class<?> contentAs;
|
||||
|
||||
FieldWriterList(
|
||||
String name,
|
||||
@ -35,9 +36,11 @@ abstract class FieldWriterList<T>
|
||||
Type fieldType,
|
||||
Class fieldClass,
|
||||
Field field,
|
||||
Method method
|
||||
Method method,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
super(name, ordinal, features, format, null, label, fieldType, fieldClass, field, method);
|
||||
this.contentAs = contentAs;
|
||||
|
||||
writeAsString = (features & WriteNonStringValueAsString.mask) != 0;
|
||||
|
||||
@ -77,6 +80,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
|
||||
|
@ -25,9 +25,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, field, method);
|
||||
super(fieldName, itemType, ordinal, features, format, label, fieldType, fieldClass, field, 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,88 @@
|
||||
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;
|
||||
import java.util.Locale;
|
||||
|
||||
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,
|
||||
Locale locale,
|
||||
String label,
|
||||
Type fieldType,
|
||||
Class fieldClass,
|
||||
Field field,
|
||||
Method method,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
super(name, ordinal, features, format, locale, 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, format, valueClass, fieldType, features);
|
||||
this.mapWriter = valueWriter;
|
||||
return valueWriter;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.alibaba.fastjson2.writer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Locale;
|
||||
|
||||
final class FieldWriterMapField
|
||||
extends FieldWriterMap {
|
||||
FieldWriterMapField(
|
||||
String name,
|
||||
int ordinal,
|
||||
long features,
|
||||
String format,
|
||||
Locale locale,
|
||||
String label,
|
||||
Type fieldType,
|
||||
Class fieldClass,
|
||||
Field field,
|
||||
Method method,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
super(name, ordinal, features, format, locale, label, fieldType, fieldClass, field, method, contentAs);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.alibaba.fastjson2.writer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
|
||||
final class FieldWriterMapFunction
|
||||
extends FieldWriterMap {
|
||||
final Function function;
|
||||
FieldWriterMapFunction(
|
||||
String name,
|
||||
int ordinal,
|
||||
long features,
|
||||
String format,
|
||||
Locale locale,
|
||||
String label,
|
||||
Type fieldType,
|
||||
Class fieldClass,
|
||||
Field field,
|
||||
Method method,
|
||||
Function function,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
super(name, ordinal, features, format, locale, label, fieldType, fieldClass, field, method, contentAs);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getFieldValue(Object object) {
|
||||
return function.apply(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function getFunction() {
|
||||
return function;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
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;
|
||||
import java.util.Locale;
|
||||
|
||||
final class FieldWriterMapMethod
|
||||
extends FieldWriterMap {
|
||||
FieldWriterMapMethod(
|
||||
String name,
|
||||
int ordinal,
|
||||
long features,
|
||||
String format,
|
||||
Locale locale,
|
||||
String label,
|
||||
Type fieldType,
|
||||
Class fieldClass,
|
||||
Field field,
|
||||
Method method,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
super(name, ordinal, features, format, locale, 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -97,7 +97,7 @@ public class FieldWriterObject<T>
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectWriter getObjectWriterVoid(JSONWriter jsonWriter, Class valueClass) {
|
||||
protected final ObjectWriter getObjectWriterVoid(JSONWriter jsonWriter, Class valueClass) {
|
||||
ObjectWriter formattedWriter = null;
|
||||
if (BeanUtils.isExtendedMap(valueClass) && SUPER.equals(fieldName)) {
|
||||
JSONWriter.Context context = jsonWriter.context;
|
||||
|
@ -541,6 +541,12 @@ public class ObjectWriterBaseModule
|
||||
fieldInfo.valueUsing = valueUsing;
|
||||
}
|
||||
break;
|
||||
case "contentAs":
|
||||
Class<?> contentAs = (Class) result;
|
||||
if (contentAs != Void.class) {
|
||||
fieldInfo.contentAs = contentAs;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -967,6 +973,11 @@ public class ObjectWriterBaseModule
|
||||
if (ObjectWriter.class.isAssignableFrom(serializeUsing)) {
|
||||
fieldInfo.writeUsing = serializeUsing;
|
||||
}
|
||||
|
||||
Class contentAs = jsonField.contentAs();
|
||||
if (contentAs != Void.class) {
|
||||
fieldInfo.contentAs = contentAs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +258,17 @@ public class ObjectWriterCreator {
|
||||
format = beanInfo.format;
|
||||
}
|
||||
|
||||
return createFieldWriter(provider, fieldName, fieldInfo.ordinal, fieldInfo.features, format, fieldInfo.locale, fieldInfo.label, field, writeUsingWriter);
|
||||
return createFieldWriter(
|
||||
provider,
|
||||
fieldName,
|
||||
fieldInfo.ordinal,
|
||||
fieldInfo.features,
|
||||
format,
|
||||
fieldInfo.locale,
|
||||
fieldInfo.label,
|
||||
field,
|
||||
writeUsingWriter,
|
||||
fieldInfo.contentAs);
|
||||
}
|
||||
|
||||
public ObjectWriter createObjectWriter(
|
||||
@ -456,7 +466,8 @@ public class ObjectWriterCreator {
|
||||
fieldInfo.format,
|
||||
fieldInfo.label,
|
||||
method,
|
||||
writeUsingWriter
|
||||
writeUsingWriter,
|
||||
fieldInfo.contentAs
|
||||
);
|
||||
} catch (Throwable ignored) {
|
||||
jitErrorCount.incrementAndGet();
|
||||
@ -471,9 +482,11 @@ public class ObjectWriterCreator {
|
||||
fieldInfo.ordinal,
|
||||
fieldInfo.features,
|
||||
fieldInfo.format,
|
||||
fieldInfo.locale,
|
||||
fieldInfo.label,
|
||||
method,
|
||||
writeUsingWriter
|
||||
writeUsingWriter,
|
||||
fieldInfo.contentAs
|
||||
);
|
||||
}
|
||||
|
||||
@ -732,6 +745,32 @@ public class ObjectWriterCreator {
|
||||
String label,
|
||||
Field field,
|
||||
ObjectWriter initObjectWriter
|
||||
) {
|
||||
return createFieldWriter(
|
||||
provider,
|
||||
fieldName,
|
||||
ordinal,
|
||||
features,
|
||||
format,
|
||||
locale,
|
||||
label,
|
||||
field,
|
||||
initObjectWriter,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public <T> FieldWriter<T> createFieldWriter(
|
||||
ObjectWriterProvider provider,
|
||||
String fieldName,
|
||||
int ordinal,
|
||||
long features,
|
||||
String format,
|
||||
Locale locale,
|
||||
String label,
|
||||
Field field,
|
||||
ObjectWriter initObjectWriter,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
Class<?> declaringClass = field.getDeclaringClass();
|
||||
Method method = null;
|
||||
@ -859,7 +898,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, locale, label, field.getGenericType(), fieldClass, field, null, contentAs);
|
||||
}
|
||||
|
||||
if (fieldClass.isArray() && !fieldClass.getComponentType().isPrimitive()) {
|
||||
@ -867,7 +910,7 @@ public class ObjectWriterCreator {
|
||||
return new FieldWriterObjectArrayField(fieldName, itemClass, ordinal, features, format, label, itemClass, fieldClass, field);
|
||||
}
|
||||
|
||||
return new FieldWriterObject(fieldName, ordinal, features, format, null, label, field.getGenericType(), fieldClass, field, null);
|
||||
return new FieldWriterObject(fieldName, ordinal, features, format, locale, label, field.getGenericType(), fieldClass, field, null);
|
||||
}
|
||||
|
||||
public <T> FieldWriter<T> createFieldWriter(Class<T> objectType,
|
||||
@ -907,7 +950,8 @@ public class ObjectWriterCreator {
|
||||
format,
|
||||
null,
|
||||
label,
|
||||
method, initObjectWriter
|
||||
method,
|
||||
initObjectWriter
|
||||
);
|
||||
}
|
||||
|
||||
@ -922,6 +966,22 @@ public class ObjectWriterCreator {
|
||||
String label,
|
||||
Method method,
|
||||
ObjectWriter initObjectWriter
|
||||
) {
|
||||
return createFieldWriter(provider, objectType, fieldName, ordinal, features, format, locale, label, method, initObjectWriter, null);
|
||||
}
|
||||
|
||||
public <T> FieldWriter<T> createFieldWriter(
|
||||
ObjectWriterProvider provider,
|
||||
Class<T> objectType,
|
||||
String fieldName,
|
||||
int ordinal,
|
||||
long features,
|
||||
String format,
|
||||
Locale locale,
|
||||
String label,
|
||||
Method method,
|
||||
ObjectWriter initObjectWriter,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
method.setAccessible(true);
|
||||
Class<?> fieldClass = method.getReturnType();
|
||||
@ -1021,7 +1081,11 @@ public class ObjectWriterCreator {
|
||||
} else {
|
||||
itemType = Object.class;
|
||||
}
|
||||
return new FieldWriterListMethod(fieldName, itemType, ordinal, features, format, label, null, method, fieldType, fieldClass);
|
||||
return new FieldWriterListMethod(fieldName, itemType, ordinal, features, format, label, null, method, fieldType, fieldClass, contentAs);
|
||||
}
|
||||
|
||||
if (Map.class.isAssignableFrom(fieldClass)) {
|
||||
return new FieldWriterMapMethod(fieldName, ordinal, features, format, locale, label, fieldType, fieldClass, null, method, contentAs);
|
||||
}
|
||||
|
||||
if (fieldClass == Float[].class || fieldClass == Double[].class || fieldClass == BigDecimal[].class) {
|
||||
@ -1166,6 +1230,40 @@ public class ObjectWriterCreator {
|
||||
Field field,
|
||||
Method method,
|
||||
Function<T, V> function
|
||||
) {
|
||||
return createFieldWriter(
|
||||
provider,
|
||||
objectClass,
|
||||
fieldName,
|
||||
ordinal,
|
||||
features,
|
||||
format,
|
||||
locale,
|
||||
label,
|
||||
fieldType,
|
||||
fieldClass,
|
||||
field,
|
||||
method,
|
||||
function,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public <T, V> FieldWriter<T> createFieldWriter(
|
||||
ObjectWriterProvider provider,
|
||||
Class<T> objectClass,
|
||||
String fieldName,
|
||||
int ordinal,
|
||||
long features,
|
||||
String format,
|
||||
Locale locale,
|
||||
String label,
|
||||
Type fieldType,
|
||||
Class<V> fieldClass,
|
||||
Field field,
|
||||
Method method,
|
||||
Function<T, V> function,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
if (fieldClass == Byte.class) {
|
||||
return new FieldWriterInt8Func(fieldName, ordinal, features, format, label, field, method, function);
|
||||
@ -1249,9 +1347,13 @@ public class ObjectWriterCreator {
|
||||
if (itemType == String.class) {
|
||||
return new FieldWriterListStrFunc(fieldName, ordinal, features, format, label, field, method, function, fieldType, fieldClass);
|
||||
}
|
||||
return new FieldWriterListFunc(fieldName, ordinal, features, format, label, itemType, field, method, function, fieldType, fieldClass);
|
||||
return new FieldWriterListFunc(fieldName, ordinal, features, format, label, itemType, field, method, function, fieldType, fieldClass, contentAs);
|
||||
}
|
||||
}
|
||||
|
||||
if (rawType instanceof Class && Map.class.isAssignableFrom((Class) rawType)) {
|
||||
return new FieldWriterMapFunction(fieldName, ordinal, features, format, locale, label, fieldType, fieldClass, field, method, function, contentAs);
|
||||
}
|
||||
}
|
||||
|
||||
if (Modifier.isFinal(fieldClass.getModifiers())) {
|
||||
@ -1368,7 +1470,8 @@ public class ObjectWriterCreator {
|
||||
String format,
|
||||
String label,
|
||||
Method method,
|
||||
ObjectWriter initObjectWriter
|
||||
ObjectWriter initObjectWriter,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
Class<?> fieldClass = method.getReturnType();
|
||||
Type fieldType = method.getGenericReturnType();
|
||||
@ -1439,6 +1542,6 @@ public class ObjectWriterCreator {
|
||||
}
|
||||
|
||||
Function function = (Function) lambda;
|
||||
return createFieldWriter(provider, objectClass, fieldName, ordinal, features, format, label, fieldType, fieldClass, field, method, function);
|
||||
return createFieldWriter(provider, objectClass, fieldName, ordinal, features, format, null, label, fieldType, fieldClass, field, method, function, contentAs);
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,8 @@ public class ObjectWriterCreatorASM
|
||||
fieldInfo.format,
|
||||
fieldInfo.label,
|
||||
method,
|
||||
writeUsingWriter
|
||||
writeUsingWriter,
|
||||
fieldInfo.contentAs
|
||||
);
|
||||
} catch (Throwable e) {
|
||||
jitErrorCount.incrementAndGet();
|
||||
@ -341,7 +342,8 @@ public class ObjectWriterCreatorASM
|
||||
fieldInfo.locale,
|
||||
fieldInfo.label,
|
||||
method,
|
||||
writeUsingWriter
|
||||
writeUsingWriter,
|
||||
fieldInfo.contentAs
|
||||
);
|
||||
}
|
||||
|
||||
@ -4397,13 +4399,14 @@ public class ObjectWriterCreatorASM
|
||||
Locale locale,
|
||||
String label,
|
||||
Field field,
|
||||
ObjectWriter initObjectWriter
|
||||
ObjectWriter initObjectWriter,
|
||||
Class<?> contentAs
|
||||
) {
|
||||
Class<?> declaringClass = field.getDeclaringClass();
|
||||
if (Throwable.class.isAssignableFrom(declaringClass)
|
||||
|| declaringClass.getName().startsWith("java.lang")
|
||||
) {
|
||||
return super.createFieldWriter(provider, fieldName, ordinal, features, format, locale, label, field, initObjectWriter);
|
||||
return super.createFieldWriter(provider, fieldName, ordinal, features, format, locale, label, field, initObjectWriter, contentAs);
|
||||
}
|
||||
|
||||
Class<?> fieldClass = field.getType();
|
||||
@ -4535,7 +4538,11 @@ public class ObjectWriterCreatorASM
|
||||
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, locale, label, field.getGenericType(), fieldClass, field, null, contentAs);
|
||||
}
|
||||
|
||||
if (fieldClass.isArray()) {
|
||||
|
@ -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.*;
|
||||
|
||||
@ -54,6 +55,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);
|
||||
}
|
||||
@ -75,6 +78,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() + "\"";
|
||||
@ -288,7 +292,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;
|
||||
@ -491,7 +500,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;
|
||||
@ -667,8 +681,13 @@ public final class ObjectWriterImplMap
|
||||
if (value == null) {
|
||||
jsonWriter.writeNull();
|
||||
} else {
|
||||
Class<?> valueType = value.getClass();
|
||||
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueType);
|
||||
Class valueClass;
|
||||
if (contentAs) {
|
||||
valueClass = (Class) this.valueType;
|
||||
} else {
|
||||
valueClass = value.getClass();
|
||||
}
|
||||
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueClass);
|
||||
valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
|
||||
}
|
||||
} finally {
|
||||
|
@ -21,6 +21,8 @@ public class MapGhostTest {
|
||||
byte[] bytes1 = JSONB.toBytes(map, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.FieldBased);
|
||||
assertArrayEquals(bytes, bytes1);
|
||||
|
||||
System.out.println(JSONB.toJSONString(bytes, true));
|
||||
|
||||
MapGhost mapGhost = (MapGhost) JSONB.parseObject(
|
||||
bytes, Object.class,
|
||||
JSONReader.Feature.FieldBased,
|
||||
|
@ -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,133 @@
|
||||
package com.alibaba.fastjson2.jackson_support;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
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 JsonSerializeTest {
|
||||
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 {
|
||||
@JsonSerialize(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));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jackson = mapper.writeValueAsString(garage);
|
||||
assertEquals("{\"vehicles\":[{\"type\":\"Sedan\"},{\"type\":\"SUV\"}]}", jackson);
|
||||
assertEquals(jackson, JSON.toJSONString(garage));
|
||||
}
|
||||
|
||||
class GarageMap {
|
||||
@JsonSerialize(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));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jackson = mapper.writeValueAsString(garage);
|
||||
assertEquals("{\"vehicles\":{\"Sedan\":{\"type\":\"Sedan\"},\"SUV\":{\"type\":\"SUV\"}}}", jackson);
|
||||
assertEquals(jackson, JSON.toJSONString(garage));
|
||||
}
|
||||
|
||||
class GarageField {
|
||||
@JsonSerialize(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));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jackson = mapper.writeValueAsString(garage);
|
||||
assertEquals("{\"vehicles\":[{\"type\":\"Sedan\"},{\"type\":\"SUV\"}]}", jackson);
|
||||
assertEquals(jackson, JSON.toJSONString(garage));
|
||||
}
|
||||
|
||||
class GarageMapField {
|
||||
@JsonSerialize(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));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jackson = mapper.writeValueAsString(garage);
|
||||
assertEquals("{\"vehicles\":{\"Sedan\":{\"type\":\"Sedan\"},\"SUV\":{\"type\":\"SUV\"}}}", jackson);
|
||||
assertEquals(jackson, JSON.toJSONString(garage));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user