com.aliyun.openservices.shade.com.alibaba.fastjson.serializer.JavaBeanSerializer Maven / Gradle / Ivy
/*
* Copyright 1999-2018 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.serializer;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.JSON;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.JSONException;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.PropertyNamingStrategy;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.annotation.JSONField;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.util.FieldInfo;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.com.alibaba.fastjson.util.TypeUtils;
/**
* @author wenshao[[email protected]]
*/
public class JavaBeanSerializer extends SerializeFilterable implements ObjectSerializer {
// serializers
protected final FieldSerializer[] getters;
protected final FieldSerializer[] sortedGetters;
protected SerializeBeanInfo beanInfo;
private transient volatile long[] hashArray;
private transient volatile short[] hashArrayMapping;
public JavaBeanSerializer(Class> beanType){
this(beanType, (Map) null);
}
public JavaBeanSerializer(Class> beanType, String... aliasList){
this(beanType, createAliasMap(aliasList));
}
static Map createAliasMap(String... aliasList) {
Map aliasMap = new HashMap();
for (String alias : aliasList) {
aliasMap.put(alias, alias);
}
return aliasMap;
}
/**
* @since 1.2.42
*/
public Class> getType() {
return beanInfo.beanType;
}
public JavaBeanSerializer(Class> beanType, Map aliasMap){
this(TypeUtils.buildBeanInfo(beanType, aliasMap, null));
}
public JavaBeanSerializer(SerializeBeanInfo beanInfo) {
this.beanInfo = beanInfo;
sortedGetters = new FieldSerializer[beanInfo.sortedFields.length];
for (int i = 0; i < sortedGetters.length; ++i) {
sortedGetters[i] = new FieldSerializer(beanInfo.beanType, beanInfo.sortedFields[i]);
}
if (beanInfo.fields == beanInfo.sortedFields) {
getters = sortedGetters;
} else {
getters = new FieldSerializer[beanInfo.fields.length];
boolean hashNotMatch = false;
for (int i = 0; i < getters.length; ++i) {
FieldSerializer fieldSerializer = getFieldSerializer(beanInfo.fields[i].name);
if (fieldSerializer == null) {
hashNotMatch = true;
break;
}
getters[i] = fieldSerializer;
}
if (hashNotMatch) {
System.arraycopy(sortedGetters, 0, getters, 0, sortedGetters.length);
}
}
if (beanInfo.jsonType != null) {
for (Class extends SerializeFilter> filterClass : beanInfo.jsonType.serialzeFilters()) {
try {
SerializeFilter filter = filterClass.getConstructor().newInstance();
this.addFilter(filter);
} catch (Exception e) {
// skip
}
}
}
if (beanInfo.jsonType != null) {
for (Class extends SerializeFilter> filterClass : beanInfo.jsonType.serialzeFilters()) {
try {
SerializeFilter filter = filterClass.getConstructor().newInstance();
this.addFilter(filter);
} catch (Exception e) {
// skip
}
}
}
}
public void writeDirectNonContext(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
write(serializer, object, fieldName, fieldType, features);
}
public void writeAsArray(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
write(serializer, object, fieldName, fieldType, features);
}
public void writeAsArrayNonContext(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
write(serializer, object, fieldName, fieldType, features);
}
public void write(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
write(serializer, object, fieldName, fieldType, features, false);
}
public void writeNoneASM(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
write(serializer, object, fieldName, fieldType, features, false);
}
protected void write(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features,
boolean unwrapped
) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
return;
}
if (writeReference(serializer, object, features)) {
return;
}
final FieldSerializer[] getters;
if (out.sortField) {
getters = this.sortedGetters;
} else {
getters = this.getters;
}
SerialContext parent = serializer.context;
if (!this.beanInfo.beanType.isEnum()) {
serializer.setContext(parent, object, fieldName, this.beanInfo.features, features);
}
final boolean writeAsArray = isWriteAsArray(serializer, features);
FieldSerializer errorFieldSerializer = null;
try {
final char startSeperator = writeAsArray ? '[' : '{';
final char endSeperator = writeAsArray ? ']' : '}';
if (!unwrapped) {
out.append(startSeperator);
}
if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.incrementIndent();
serializer.println();
}
boolean commaFlag = false;
if ((this.beanInfo.features & SerializerFeature.WriteClassName.mask) != 0
||(features & SerializerFeature.WriteClassName.mask) != 0
|| serializer.isWriteClassName(fieldType, object)) {
Class> objClass = object.getClass();
final Type type;
if (objClass != fieldType && fieldType instanceof WildcardType) {
type = TypeUtils.getClass(fieldType);
} else {
type = fieldType;
}
if (objClass != type) {
writeClassName(serializer, beanInfo.typeKey, object);
commaFlag = true;
}
}
char seperator = commaFlag ? ',' : '\0';
final boolean writeClassName = out.isEnabled(SerializerFeature.WriteClassName);
final boolean directWritePrefix = out.quoteFieldNames && !out.useSingleQuotes;
char newSeperator = this.writeBefore(serializer, object, seperator);
commaFlag = newSeperator == ',';
final boolean skipTransient = out.isEnabled(SerializerFeature.SkipTransientField);
final boolean ignoreNonFieldGetter = out.isEnabled(SerializerFeature.IgnoreNonFieldGetter);
for (int i = 0; i < getters.length; ++i) {
FieldSerializer fieldSerializer = getters[i];
Field field = fieldSerializer.fieldInfo.field;
FieldInfo fieldInfo = fieldSerializer.fieldInfo;
String fieldInfoName = fieldInfo.name;
Class> fieldClass = fieldInfo.fieldClass;
if (skipTransient) {
if (field != null) {
if (fieldInfo.fieldTransient) {
continue;
}
}
}
if (ignoreNonFieldGetter) {
if (field == null) {
continue;
}
}
boolean notApply = false;
if ((!this.applyName(serializer, object, fieldInfoName)) //
|| !this.applyLabel(serializer, fieldInfo.label)) {
if (writeAsArray) {
notApply = true;
} else {
continue;
}
}
if (beanInfo.typeKey != null
&& fieldInfoName.equals(beanInfo.typeKey)
&& serializer.isWriteClassName(fieldType, object)) {
continue;
}
Object propertyValue;
if (notApply) {
propertyValue = null;
} else {
try {
propertyValue = fieldSerializer.getPropertyValueDirect(object);
} catch (InvocationTargetException ex) {
errorFieldSerializer = fieldSerializer;
if (out.isEnabled(SerializerFeature.IgnoreErrorGetter)) {
propertyValue = null;
} else {
throw ex;
}
}
}
if (!this.apply(serializer, object, fieldInfoName, propertyValue)) {
continue;
}
if (fieldClass == String.class && "trim".equals(fieldInfo.format)) {
if (propertyValue != null) {
propertyValue = ((String) propertyValue).trim();
}
}
String key = fieldInfoName;
key = this.processKey(serializer, object, key, propertyValue);
Object originalValue = propertyValue;
propertyValue = this.processValue(serializer, fieldSerializer.fieldContext, object, fieldInfoName,
propertyValue);
if (propertyValue == null) {
int serialzeFeatures = fieldInfo.serialzeFeatures;
if (beanInfo.jsonType != null) {
serialzeFeatures |= SerializerFeature.of(beanInfo.jsonType.serialzeFeatures());
}
// beanInfo.jsonType
if (fieldClass == Boolean.class) {
int defaultMask = SerializerFeature.WriteNullBooleanAsFalse.mask;
final int mask = defaultMask | SerializerFeature.WriteMapNullValue.mask;
if ((!writeAsArray) && (serialzeFeatures & mask) == 0 && (out.features & mask) == 0) {
continue;
} else if ((serialzeFeatures & defaultMask) != 0 || (out.features & defaultMask) != 0) {
propertyValue = false;
}
} else if (fieldClass == String.class) {
int defaultMask = SerializerFeature.WriteNullStringAsEmpty.mask;
final int mask = defaultMask | SerializerFeature.WriteMapNullValue.mask;
if ((!writeAsArray) && (serialzeFeatures & mask) == 0 && (out.features & mask) == 0) {
continue;
} else if ((serialzeFeatures & defaultMask) != 0 || (out.features & defaultMask) != 0) {
propertyValue = "";
}
} else if (Number.class.isAssignableFrom(fieldClass)) {
int defaultMask = SerializerFeature.WriteNullNumberAsZero.mask;
final int mask = defaultMask | SerializerFeature.WriteMapNullValue.mask;
if ((!writeAsArray) && (serialzeFeatures & mask) == 0 && (out.features & mask) == 0) {
continue;
} else if ((serialzeFeatures & defaultMask) != 0 || (out.features & defaultMask) != 0) {
propertyValue = 0;
}
} else if (Collection.class.isAssignableFrom(fieldClass)) {
int defaultMask = SerializerFeature.WriteNullListAsEmpty.mask;
final int mask = defaultMask | SerializerFeature.WriteMapNullValue.mask;
if ((!writeAsArray) && (serialzeFeatures & mask) == 0 && (out.features & mask) == 0) {
continue;
} else if ((serialzeFeatures & defaultMask) != 0 || (out.features & defaultMask) != 0) {
propertyValue = Collections.emptyList();
}
} else if ((!writeAsArray) && (!fieldSerializer.writeNull) && !out.isEnabled(SerializerFeature.WriteMapNullValue.mask)){
continue;
}
}
if (propertyValue != null //
&& (out.notWriteDefaultValue //
|| (fieldInfo.serialzeFeatures & SerializerFeature.NotWriteDefaultValue.mask) != 0 //
|| (beanInfo.features & SerializerFeature.NotWriteDefaultValue.mask) != 0 //
)) {
Class> fieldCLass = fieldInfo.fieldClass;
if (fieldCLass == byte.class && propertyValue instanceof Byte
&& ((Byte) propertyValue).byteValue() == 0) {
continue;
} else if (fieldCLass == short.class && propertyValue instanceof Short
&& ((Short) propertyValue).shortValue() == 0) {
continue;
} else if (fieldCLass == int.class && propertyValue instanceof Integer
&& ((Integer) propertyValue).intValue() == 0) {
continue;
} else if (fieldCLass == long.class && propertyValue instanceof Long
&& ((Long) propertyValue).longValue() == 0L) {
continue;
} else if (fieldCLass == float.class && propertyValue instanceof Float
&& ((Float) propertyValue).floatValue() == 0F) {
continue;
} else if (fieldCLass == double.class && propertyValue instanceof Double
&& ((Double) propertyValue).doubleValue() == 0D) {
continue;
} else if (fieldCLass == boolean.class && propertyValue instanceof Boolean
&& !((Boolean) propertyValue).booleanValue()) {
continue;
}
}
if (commaFlag) {
if (fieldInfo.unwrapped
&& propertyValue instanceof Map
&& ((Map) propertyValue).size() == 0) {
continue;
}
out.write(',');
if (out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.println();
}
}
if (key != fieldInfoName) {
if (!writeAsArray) {
out.writeFieldName(key, true);
}
serializer.write(propertyValue);
} else if (originalValue != propertyValue) {
if (!writeAsArray) {
fieldSerializer.writePrefix(serializer);
}
serializer.write(propertyValue);
} else {
if (!writeAsArray) {
if (writeClassName || !fieldInfo.unwrapped) {
if (directWritePrefix) {
out.write(fieldInfo.name_chars, 0, fieldInfo.name_chars.length);
} else {
fieldSerializer.writePrefix(serializer);
}
}
}
if (!writeAsArray) {
JSONField fieldAnnotation = fieldInfo.getAnnotation();
if (fieldClass == String.class && (fieldAnnotation == null || fieldAnnotation.serializeUsing() == Void.class)) {
if (propertyValue == null) {
if ((out.features & SerializerFeature.WriteNullStringAsEmpty.mask) != 0
|| (fieldSerializer.features & SerializerFeature.WriteNullStringAsEmpty.mask) != 0) {
out.writeString("");
} else {
out.writeNull();
}
} else {
String propertyValueString = (String) propertyValue;
if (out.useSingleQuotes) {
out.writeStringWithSingleQuote(propertyValueString);
} else {
out.writeStringWithDoubleQuote(propertyValueString, (char) 0);
}
}
} else {
if (fieldInfo.unwrapped
&& propertyValue instanceof Map
&& ((Map) propertyValue).size() == 0) {
commaFlag = false;
continue;
}
fieldSerializer.writeValue(serializer, propertyValue);
}
} else {
fieldSerializer.writeValue(serializer, propertyValue);
}
}
boolean fieldUnwrappedNull = false;
if (fieldInfo.unwrapped
&& propertyValue instanceof Map) {
Map map = ((Map) propertyValue);
if (map.size() == 0) {
fieldUnwrappedNull = true;
} else if (!serializer.isEnabled(SerializerFeature.WriteMapNullValue)){
boolean hasNotNull = false;
for (Object value : map.values()) {
if (value != null) {
hasNotNull = true;
break;
}
}
if (!hasNotNull) {
fieldUnwrappedNull = true;
}
}
}
if (!fieldUnwrappedNull) {
commaFlag = true;
}
}
this.writeAfter(serializer, object, commaFlag ? ',' : '\0');
if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.decrementIdent();
serializer.println();
}
if (!unwrapped) {
out.append(endSeperator);
}
} catch (Exception e) {
String errorMessage = "write javaBean error, fastjson version " + JSON.VERSION;
if (object != null) {
errorMessage += ", class " + object.getClass().getName();
}
if (fieldName != null) {
errorMessage += ", fieldName : " + fieldName;
} else if (errorFieldSerializer != null && errorFieldSerializer.fieldInfo != null) {
FieldInfo fieldInfo = errorFieldSerializer.fieldInfo;
if (fieldInfo.method != null) {
errorMessage += ", method : " + fieldInfo.method.getName();
} else {
errorMessage += ", fieldName : " + errorFieldSerializer.fieldInfo.name;
}
}
if (e.getMessage() != null) {
errorMessage += (", " + e.getMessage());
}
Throwable cause = null;
if (e instanceof InvocationTargetException) {
cause = e.getCause();
}
if (cause == null) {
cause = e;
}
throw new JSONException(errorMessage, cause);
} finally {
serializer.context = parent;
}
}
protected void writeClassName(JSONSerializer serializer, String typeKey, Object object) {
if (typeKey == null) {
typeKey = serializer.config.typeKey;
}
serializer.out.writeFieldName(typeKey, false);
String typeName = this.beanInfo.typeName;
if (typeName == null) {
Class> clazz = object.getClass();
if (TypeUtils.isProxy(clazz)) {
clazz = clazz.getSuperclass();
}
typeName = clazz.getName();
}
serializer.write(typeName);
}
public boolean writeReference(JSONSerializer serializer, Object object, int fieldFeatures) {
SerialContext context = serializer.context;
int mask = SerializerFeature.DisableCircularReferenceDetect.mask;
if (context == null || (context.features & mask) != 0 || (fieldFeatures & mask) != 0) {
return false;
}
if (serializer.references != null && serializer.references.containsKey(object)) {
serializer.writeReference(object);
return true;
} else {
return false;
}
}
protected boolean isWriteAsArray(JSONSerializer serializer) {
return isWriteAsArray(serializer, 0);
}
protected boolean isWriteAsArray(JSONSerializer serializer, int fieldFeatrues) {
final int mask = SerializerFeature.BeanToArray.mask;
return (beanInfo.features & mask) != 0 //
|| serializer.out.beanToArray //
|| (fieldFeatrues & mask) != 0;
}
public Object getFieldValue(Object object, String key) {
FieldSerializer fieldDeser = getFieldSerializer(key);
if (fieldDeser == null) {
throw new JSONException("field not found. " + key);
}
try {
return fieldDeser.getPropertyValue(object);
} catch (InvocationTargetException ex) {
throw new JSONException("getFieldValue error." + key, ex);
} catch (IllegalAccessException ex) {
throw new JSONException("getFieldValue error." + key, ex);
}
}
public Object getFieldValue(Object object, String key, long keyHash, boolean throwFieldNotFoundException) {
FieldSerializer fieldDeser = getFieldSerializer(keyHash);
if (fieldDeser == null) {
if (throwFieldNotFoundException) {
throw new JSONException("field not found. " + key);
}
return null;
}
try {
return fieldDeser.getPropertyValue(object);
} catch (InvocationTargetException ex) {
throw new JSONException("getFieldValue error." + key, ex);
} catch (IllegalAccessException ex) {
throw new JSONException("getFieldValue error." + key, ex);
}
}
public FieldSerializer getFieldSerializer(String key) {
if (key == null) {
return null;
}
int low = 0;
int high = sortedGetters.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
String fieldName = sortedGetters[mid].fieldInfo.name;
int cmp = fieldName.compareTo(key);
if (cmp < 0) {
low = mid + 1;
} else if (cmp > 0) {
high = mid - 1;
} else {
return sortedGetters[mid]; // key found
}
}
return null; // key not found.
}
public FieldSerializer getFieldSerializer(long hash) {
PropertyNamingStrategy[] namingStrategies = null;
if (this.hashArray == null) {
namingStrategies = PropertyNamingStrategy.values();
long[] hashArray = new long[sortedGetters.length * namingStrategies.length];
int index = 0;
for (int i = 0; i < sortedGetters.length; i++) {
String name = sortedGetters[i].fieldInfo.name;
hashArray[index++] = TypeUtils.fnv1a_64(name);
for (int j = 0; j < namingStrategies.length; j++) {
String name_t = namingStrategies[j].translate(name);
if (name.equals(name_t)) {
continue;
}
hashArray[index++] = TypeUtils.fnv1a_64(name_t);
}
}
Arrays.sort(hashArray, 0, index);
this.hashArray = new long[index];
System.arraycopy(hashArray, 0, this.hashArray, 0, index);
}
int pos = Arrays.binarySearch(hashArray, hash);
if (pos < 0) {
return null;
}
if (hashArrayMapping == null) {
if (namingStrategies == null) {
namingStrategies = PropertyNamingStrategy.values();
}
short[] mapping = new short[hashArray.length];
Arrays.fill(mapping, (short) -1);
for (int i = 0; i < sortedGetters.length; i++) {
String name = sortedGetters[i].fieldInfo.name;
int p = Arrays.binarySearch(hashArray
, TypeUtils.fnv1a_64(name));
if (p >= 0) {
mapping[p] = (short) i;
}
for (int j = 0; j < namingStrategies.length; j++) {
String name_t = namingStrategies[j].translate(name);
if (name.equals(name_t)) {
continue;
}
int p_t = Arrays.binarySearch(hashArray
, TypeUtils.fnv1a_64(name_t));
if (p_t >= 0) {
mapping[p_t] = (short) i;
}
}
}
hashArrayMapping = mapping;
}
int getterIndex = hashArrayMapping[pos];
if (getterIndex != -1) {
return sortedGetters[getterIndex];
}
return null; // key not found.
}
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy