shade.com.alibaba.fastjson2.writer.ObjectWriterAdapter Maven / Gradle / Ivy
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.BeanUtils;
import com.alibaba.fastjson2.util.DateUtils;
import com.alibaba.fastjson2.util.Fnv;
import com.alibaba.fastjson2.util.TypeUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import static com.alibaba.fastjson2.JSONB.Constants.BC_TYPED_ANY;
import static com.alibaba.fastjson2.JSONWriter.Feature.*;
public class ObjectWriterAdapter
implements ObjectWriter {
boolean hasFilter;
PropertyPreFilter propertyPreFilter;
PropertyFilter propertyFilter;
NameFilter nameFilter;
ValueFilter valueFilter;
static final String TYPE = "@type";
final Class objectClass;
final List fieldWriters;
protected final FieldWriter[] fieldWriterArray;
final String typeKey;
byte[] typeKeyJSONB;
protected final String typeName;
protected final long typeNameHash;
protected long typeNameSymbolCache;
protected final byte[] typeNameJSONB;
byte[] nameWithColonUTF8;
char[] nameWithColonUTF16;
final long features;
final long[] hashCodes;
final short[] mapping;
final boolean hasValueField;
final boolean serializable;
final boolean containsNoneFieldGetter;
final boolean googleCollection;
public ObjectWriterAdapter(Class objectClass, List fieldWriters) {
this(objectClass, null, null, 0, fieldWriters);
}
public ObjectWriterAdapter(
Class objectClass,
String typeKey,
String typeName,
long features,
List fieldWriters
) {
if (typeName == null && objectClass != null) {
if (Enum.class.isAssignableFrom(objectClass) && !objectClass.isEnum()) {
typeName = objectClass.getSuperclass().getName();
} else {
typeName = TypeUtils.getTypeName(objectClass);
}
}
this.objectClass = objectClass;
this.typeKey = typeKey == null || typeKey.isEmpty() ? TYPE : typeKey;
this.typeName = typeName;
this.typeNameHash = typeName != null ? Fnv.hashCode64(typeName) : 0;
this.typeNameJSONB = JSONB.toBytes(typeName);
this.features = features;
this.fieldWriters = fieldWriters;
this.serializable = objectClass == null || java.io.Serializable.class.isAssignableFrom(objectClass);
this.googleCollection =
"com.google.common.collect.AbstractMapBasedMultimap$RandomAccessWrappedList".equals(typeName)
|| "com.google.common.collect.AbstractMapBasedMultimap$WrappedSet".equals(typeName);
this.fieldWriterArray = new FieldWriter[fieldWriters.size()];
fieldWriters.toArray(fieldWriterArray);
this.hasValueField = fieldWriterArray.length == 1 && (fieldWriterArray[0].features & FieldInfo.VALUE_MASK) != 0;
boolean containsNoneFieldGetter = false;
long[] hashCodes = new long[fieldWriterArray.length];
for (int i = 0; i < fieldWriterArray.length; i++) {
FieldWriter fieldWriter = fieldWriterArray[i];
long hashCode = Fnv.hashCode64(fieldWriter.fieldName);
hashCodes[i] = hashCode;
if (fieldWriter.method != null && (fieldWriter.features & FieldInfo.FIELD_MASK) == 0) {
containsNoneFieldGetter = true;
}
}
this.containsNoneFieldGetter = containsNoneFieldGetter;
this.hashCodes = Arrays.copyOf(hashCodes, hashCodes.length);
Arrays.sort(this.hashCodes);
mapping = new short[this.hashCodes.length];
for (int i = 0; i < hashCodes.length; i++) {
long hashCode = hashCodes[i];
int index = Arrays.binarySearch(this.hashCodes, hashCode);
mapping[index] = (short) i;
}
}
@Override
public long getFeatures() {
return features;
}
@Override
public FieldWriter getFieldWriter(long hashCode) {
int m = Arrays.binarySearch(hashCodes, hashCode);
if (m < 0) {
return null;
}
int index = this.mapping[m];
return fieldWriterArray[index];
}
@Override
public final boolean hasFilter(JSONWriter jsonWriter) {
return hasFilter || jsonWriter.hasFilter(containsNoneFieldGetter);
}
public void setPropertyFilter(PropertyFilter propertyFilter) {
this.propertyFilter = propertyFilter;
if (propertyFilter != null) {
hasFilter = true;
}
}
public void setValueFilter(ValueFilter valueFilter) {
this.valueFilter = valueFilter;
if (valueFilter != null) {
hasFilter = true;
}
}
public void setNameFilter(NameFilter nameFilter) {
this.nameFilter = nameFilter;
if (nameFilter != null) {
hasFilter = true;
}
}
public void setPropertyPreFilter(PropertyPreFilter propertyPreFilter) {
this.propertyPreFilter = propertyPreFilter;
if (propertyPreFilter != null) {
hasFilter = true;
}
}
@Override
public void writeArrayMappingJSONB(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
if (jsonWriter.isWriteTypeInfo(object, fieldType, features)) {
writeClassInfo(jsonWriter);
}
int size = fieldWriters.size();
jsonWriter.startArray(size);
for (int i = 0; i < size; ++i) {
FieldWriter fieldWriter = fieldWriters.get(i);
fieldWriter.writeValue(jsonWriter, object);
}
}
@Override
public void writeJSONB(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
long featuresAll = features | this.features | jsonWriter.getFeatures();
if (!serializable) {
if ((featuresAll & JSONWriter.Feature.ErrorOnNoneSerializable.mask) != 0) {
errorOnNoneSerializable();
return;
}
if ((featuresAll & JSONWriter.Feature.IgnoreNoneSerializable.mask) != 0) {
jsonWriter.writeNull();
return;
}
}
if ((featuresAll & JSONWriter.Feature.IgnoreNoneSerializable.mask) != 0) {
writeWithFilter(jsonWriter, object, fieldName, fieldType, features);
return;
}
int size = fieldWriterArray.length;
if (jsonWriter.isWriteTypeInfo(object, fieldType, features)) {
writeClassInfo(jsonWriter);
}
jsonWriter.startObject();
for (int i = 0; i < size; ++i) {
FieldWriter fieldWriter = fieldWriters.get(i);
fieldWriter.write(jsonWriter, object);
}
jsonWriter.endObject();
}
protected final void writeClassInfo(JSONWriter jsonWriter) {
SymbolTable symbolTable = jsonWriter.symbolTable;
if (symbolTable != null) {
if (writeClassInfoSymbol(jsonWriter, symbolTable)) {
return;
}
}
jsonWriter.writeTypeName(typeNameJSONB, typeNameHash);
}
private boolean writeClassInfoSymbol(JSONWriter jsonWriter, SymbolTable symbolTable) {
int symbolTableIdentity = System.identityHashCode(symbolTable);
int symbol;
if (typeNameSymbolCache == 0) {
symbol = symbolTable.getOrdinalByHashCode(typeNameHash);
if (symbol != -1) {
typeNameSymbolCache = ((long) symbol << 32) | symbolTableIdentity;
}
} else {
int identity = (int) typeNameSymbolCache;
if (identity == symbolTableIdentity) {
symbol = (int) (typeNameSymbolCache >> 32);
} else {
symbol = symbolTable.getOrdinalByHashCode(typeNameHash);
if (symbol != -1) {
typeNameSymbolCache = ((long) symbol << 32) | symbolTableIdentity;
}
}
}
if (symbol != -1) {
jsonWriter.writeRaw(BC_TYPED_ANY);
jsonWriter.writeInt32(-symbol);
return true;
}
return false;
}
@Override
public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
if (hasValueField) {
FieldWriter fieldWriter = fieldWriterArray[0];
fieldWriter.writeValue(jsonWriter, object);
return;
}
long featuresAll = features | this.features | jsonWriter.getFeatures();
boolean beanToArray = (featuresAll & BeanToArray.mask) != 0;
if (jsonWriter.jsonb) {
if (beanToArray) {
writeArrayMappingJSONB(jsonWriter, object, fieldName, fieldType, features);
return;
}
writeJSONB(jsonWriter, object, fieldName, fieldType, features);
return;
}
if (googleCollection) {
Collection collection = (Collection) object;
ObjectWriterImplCollection.INSTANCE.write(jsonWriter, collection, fieldName, fieldType, features);
return;
}
if (beanToArray) {
writeArrayMapping(jsonWriter, object, fieldName, fieldType, features);
return;
}
if (!serializable) {
if ((featuresAll & JSONWriter.Feature.ErrorOnNoneSerializable.mask) != 0) {
errorOnNoneSerializable();
return;
}
if ((featuresAll & JSONWriter.Feature.IgnoreNoneSerializable.mask) != 0) {
jsonWriter.writeNull();
return;
}
}
if (hasFilter(jsonWriter)) {
writeWithFilter(jsonWriter, object, fieldName, fieldType, features);
return;
}
jsonWriter.startObject();
if (((features | this.features) & WriteClassName.mask) != 0 || jsonWriter.isWriteTypeInfo(object, features)) {
writeTypeInfo(jsonWriter);
}
final int size = fieldWriters.size();
for (int i = 0; i < size; i++) {
FieldWriter fieldWriter = fieldWriters.get(i);
fieldWriter.write(jsonWriter, object);
}
jsonWriter.endObject();
}
public Map toMap(Object object) {
final int size = fieldWriters.size();
JSONObject map = new JSONObject(size, 1F);
for (int i = 0; i < size; i++) {
FieldWriter fieldWriter = fieldWriters.get(i);
map.put(
fieldWriter.fieldName,
fieldWriter.getFieldValue(object)
);
}
return map;
}
@Override
public List getFieldWriters() {
return fieldWriters;
}
byte[] jsonbClassInfo;
@Override
public boolean writeTypeInfo(JSONWriter jsonWriter) {
if (jsonWriter.utf8) {
if (nameWithColonUTF8 == null) {
byte[] chars = new byte[typeKey.length() + typeName.length() + 5];
chars[0] = '"';
typeKey.getBytes(0, typeKey.length(), chars, 1);
chars[typeKey.length() + 1] = '"';
chars[typeKey.length() + 2] = ':';
chars[typeKey.length() + 3] = '"';
typeName.getBytes(0, typeName.length(), chars, typeKey.length() + 4);
chars[typeKey.length() + typeName.length() + 4] = '"';
nameWithColonUTF8 = chars;
}
jsonWriter.writeNameRaw(nameWithColonUTF8);
return true;
} else if (jsonWriter.utf16) {
if (nameWithColonUTF16 == null) {
char[] chars = new char[typeKey.length() + typeName.length() + 5];
chars[0] = '"';
typeKey.getChars(0, typeKey.length(), chars, 1);
chars[typeKey.length() + 1] = '"';
chars[typeKey.length() + 2] = ':';
chars[typeKey.length() + 3] = '"';
typeName.getChars(0, typeName.length(), chars, typeKey.length() + 4);
chars[typeKey.length() + typeName.length() + 4] = '"';
nameWithColonUTF16 = chars;
}
jsonWriter.writeNameRaw(nameWithColonUTF16);
return true;
} else if (jsonWriter.jsonb) {
if (typeKeyJSONB == null) {
typeKeyJSONB = JSONB.toBytes(typeKey);
}
jsonWriter.writeRaw(typeKeyJSONB);
jsonWriter.writeRaw(typeNameJSONB);
return true;
}
jsonWriter.writeString(typeKey);
jsonWriter.writeColon();
jsonWriter.writeString(typeName);
return true;
}
@Override
public void writeWithFilter(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
if (object == null) {
jsonWriter.writeNull();
return;
}
if (jsonWriter.isWriteTypeInfo(object, fieldType, features)) {
if (jsonWriter.jsonb) {
writeClassInfo(jsonWriter);
jsonWriter.startObject();
} else {
jsonWriter.startObject();
writeTypeInfo(jsonWriter);
}
} else {
jsonWriter.startObject();
}
JSONWriter.Context context = jsonWriter.context;
long features2 = context.getFeatures() | features;
boolean refDetect = (features2 & ReferenceDetection.mask) != 0;
boolean ignoreNonFieldGetter = (features2 & IgnoreNonFieldGetter.mask) != 0;
BeforeFilter beforeFilter = context.getBeforeFilter();
if (beforeFilter != null) {
beforeFilter.writeBefore(jsonWriter, object);
}
PropertyPreFilter propertyPreFilter = context.getPropertyPreFilter();
if (propertyPreFilter == null) {
propertyPreFilter = this.propertyPreFilter;
}
NameFilter nameFilter = context.getNameFilter();
if (nameFilter == null) {
nameFilter = this.nameFilter;
} else {
if (this.nameFilter != null) {
nameFilter = NameFilter.compose(this.nameFilter, nameFilter);
}
}
ContextNameFilter contextNameFilter = context.getContextNameFilter();
ValueFilter valueFilter = context.getValueFilter();
if (valueFilter == null) {
valueFilter = this.valueFilter;
} else {
if (this.valueFilter != null) {
valueFilter = ValueFilter.compose(this.valueFilter, valueFilter);
}
}
ContextValueFilter contextValueFilter = context.getContextValueFilter();
PropertyFilter propertyFilter = context.getPropertyFilter();
if (propertyFilter == null) {
propertyFilter = this.propertyFilter;
}
LabelFilter labelFilter = context.getLabelFilter();
for (int i = 0; i < fieldWriters.size(); i++) {
FieldWriter fieldWriter = fieldWriters.get(i);
Field field = fieldWriter.field;
if (ignoreNonFieldGetter
&& fieldWriter.method != null
&& (fieldWriter.features & FieldInfo.FIELD_MASK) == 0) {
continue;
}
// pre property filter
final String fieldWriterFieldName = fieldWriter.fieldName;
if (propertyPreFilter != null
&& !propertyPreFilter.process(jsonWriter, object, fieldWriterFieldName)) {
continue;
}
if (labelFilter != null) {
String label = fieldWriter.label;
if (label != null && !label.isEmpty()) {
if (!labelFilter.apply(label)) {
continue;
}
}
}
// fast return
if (nameFilter == null
&& propertyFilter == null
&& contextValueFilter == null
&& contextNameFilter == null
&& valueFilter == null
) {
fieldWriter.write(jsonWriter, object);
continue;
}
Object fieldValue;
try {
fieldValue = fieldWriter.getFieldValue(object);
} catch (Throwable e) {
if ((context.getFeatures() & JSONWriter.Feature.IgnoreErrorGetter.mask) != 0) {
continue;
}
throw e;
}
if (fieldValue == null && !jsonWriter.isWriteNulls()) {
continue;
}
if (!refDetect && ("this$0".equals(fieldWriterFieldName) || "this$1".equals(fieldWriterFieldName) || "this$2".equals(fieldWriterFieldName))) {
continue;
}
BeanContext beanContext = null;
// name filter
String filteredName = fieldWriterFieldName;
if (nameFilter != null) {
filteredName = nameFilter.process(object, filteredName, fieldValue);
}
if (contextNameFilter != null) {
if (beanContext == null) {
if (field == null && fieldWriter.method != null) {
field = BeanUtils.getDeclaredField(objectClass, fieldWriter.fieldName);
}
beanContext = new BeanContext(
objectClass,
fieldWriter.method,
field,
fieldWriter.fieldName,
fieldWriter.label,
fieldWriter.fieldClass,
fieldWriter.fieldType,
fieldWriter.features,
fieldWriter.format
);
filteredName = contextNameFilter.process(beanContext, object, filteredName, fieldValue);
}
}
// property filter
if (propertyFilter != null
&& !propertyFilter.apply(object, fieldWriterFieldName, fieldValue)) {
continue;
}
boolean nameChanged = filteredName != null && filteredName != fieldWriterFieldName;
Object filteredValue = fieldValue;
if (valueFilter != null) {
filteredValue = valueFilter.apply(object, fieldWriterFieldName, fieldValue);
}
if (contextValueFilter != null) {
if (beanContext == null) {
if (field == null && fieldWriter.method != null) {
field = BeanUtils.getDeclaredField(objectClass, fieldWriter.fieldName);
}
beanContext = new BeanContext(
objectClass,
fieldWriter.method,
field,
fieldWriter.fieldName,
fieldWriter.label,
fieldWriter.fieldClass,
fieldWriter.fieldType,
fieldWriter.features,
fieldWriter.format
);
}
filteredValue = contextValueFilter.process(beanContext, object, filteredName, filteredValue);
}
if (filteredValue != fieldValue) {
if (nameChanged) {
jsonWriter.writeName(filteredName);
jsonWriter.writeColon();
} else {
fieldWriter.writeFieldName(jsonWriter);
}
if (filteredValue == null) {
jsonWriter.writeNull();
} else {
ObjectWriter fieldValueWriter = fieldWriter.getObjectWriter(jsonWriter, filteredValue.getClass());
fieldValueWriter.write(jsonWriter, filteredValue, fieldName, fieldType, features);
}
} else {
if (!nameChanged) {
fieldWriter.write(jsonWriter, object);
} else {
jsonWriter.writeName(filteredName);
jsonWriter.writeColon();
if (fieldValue == null) {
ObjectWriter fieldValueWriter = fieldWriter.getObjectWriter(jsonWriter, fieldWriter.fieldClass);
fieldValueWriter.write(jsonWriter, null, fieldName, fieldType, features);
} else {
ObjectWriter fieldValueWriter = fieldWriter.getObjectWriter(jsonWriter, fieldValue.getClass());
fieldValueWriter.write(jsonWriter, fieldValue, fieldName, fieldType, features);
}
}
}
}
AfterFilter afterFilter = context.getAfterFilter();
if (afterFilter != null) {
afterFilter.writeAfter(jsonWriter, object);
}
jsonWriter.endObject();
}
public JSONObject toJSONObject(T object) {
return toJSONObject(object, 0);
}
public JSONObject toJSONObject(T object, long features) {
JSONObject jsonObject = new JSONObject();
for (int i = 0, size = fieldWriters.size(); i < size; i++) {
FieldWriter fieldWriter = fieldWriters.get(i);
Object fieldValue = fieldWriter.getFieldValue(object);
String format = fieldWriter.format;
Class fieldClass = fieldWriter.fieldClass;
if (format != null) {
if (fieldClass == Date.class) {
fieldValue = DateUtils.format((Date) fieldValue, format);
} else if (fieldClass == LocalDate.class) {
fieldValue = DateUtils.format((LocalDate) fieldValue, format);
} else if (fieldClass == LocalDateTime.class) {
fieldValue = DateUtils.format((LocalDateTime) fieldValue, format);
}
}
long fieldFeatures = fieldWriter.features;
if ((fieldFeatures & FieldInfo.UNWRAPPED_MASK) != 0) {
if (fieldValue instanceof Map) {
jsonObject.putAll((Map) fieldValue);
continue;
}
ObjectWriter fieldObjectWriter = fieldWriter.getInitWriter();
if (fieldObjectWriter == null) {
fieldObjectWriter = JSONFactory.getDefaultObjectWriterProvider().getObjectWriter(fieldClass);
}
List unwrappedFieldWriters = fieldObjectWriter.getFieldWriters();
for (int j = 0, unwrappedSize = unwrappedFieldWriters.size(); j < unwrappedSize; j++) {
FieldWriter unwrappedFieldWriter = unwrappedFieldWriters.get(j);
Object unwrappedFieldValue = unwrappedFieldWriter.getFieldValue(fieldValue);
jsonObject.put(unwrappedFieldWriter.fieldName, unwrappedFieldValue);
}
continue;
}
if (fieldValue != null) {
String fieldValueClassName = fieldValue.getClass().getName();
if (Collection.class.isAssignableFrom(fieldClass)
&& fieldValue.getClass() != JSONObject.class
&& !fieldValueClassName.equals("com.alibaba.fastjson.JSONObject")
) {
Collection collection = (Collection) fieldValue;
JSONArray array = new JSONArray(collection.size());
for (Object item : collection) {
Object itemJSON = item == object ? jsonObject : JSON.toJSON(item);
array.add(itemJSON);
}
fieldValue = array;
}
}
if (fieldValue == null && ((this.features | features) & WriteNulls.mask) == 0) {
continue;
}
if (fieldValue == object) {
fieldValue = jsonObject;
}
jsonObject.put(fieldWriter.fieldName, fieldValue);
}
return jsonObject;
}
@Override
public String toString() {
return objectClass.getName();
}
protected void errorOnNoneSerializable() {
throw new JSONException("not support none serializable class " + objectClass.getName());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy