in core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreator.java [315:606]
public ObjectWriter createObjectWriter(
final Class objectClass,
final long features,
final ObjectWriterProvider provider
) {
BeanInfo beanInfo = provider.createBeanInfo();
beanInfo.readerFeatures |= FieldInfo.JIT;
provider.getBeanInfo(beanInfo, objectClass);
if (beanInfo.serializer != null && ObjectWriter.class.isAssignableFrom(beanInfo.serializer)) {
try {
return (ObjectWriter) beanInfo.serializer.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new JSONException("create serializer error", e);
}
}
boolean record = BeanUtils.isRecord(objectClass);
long beanFeatures = beanInfo.writerFeatures;
if (beanInfo.seeAlso != null) {
beanFeatures &= ~JSONWriter.Feature.WriteClassName.mask;
}
long writerFieldFeatures = features | beanFeatures;
boolean fieldBased = (writerFieldFeatures & JSONWriter.Feature.FieldBased.mask) != 0;
if (fieldBased && (record || objectClass.isInterface())) {
fieldBased = false;
}
List<FieldWriter> fieldWriters;
final FieldInfo fieldInfo = new FieldInfo();
if (fieldBased) {
Map<String, FieldWriter> fieldWriterMap = new TreeMap<>();
BeanUtils.declaredFields(objectClass, field -> {
fieldInfo.init();
FieldWriter fieldWriter = creteFieldWriter(objectClass, writerFieldFeatures, provider, beanInfo, fieldInfo, field);
if (fieldWriter != null) {
fieldWriterMap.put(fieldWriter.fieldName, fieldWriter);
}
});
fieldWriters = new ArrayList<>(fieldWriterMap.values());
} else {
boolean fieldWritersCreated = false;
fieldWriters = new ArrayList<>();
for (ObjectWriterModule module : provider.modules) {
if (module.createFieldWriters(this, objectClass, fieldWriters)) {
fieldWritersCreated = true;
break;
}
}
if (!fieldWritersCreated) {
Map<String, FieldWriter> fieldWriterMap = new TreeMap<>();
if (!record) {
BeanUtils.declaredFields(objectClass, field -> {
fieldInfo.init();
fieldInfo.ignore = (field.getModifiers() & Modifier.PUBLIC) == 0;
FieldWriter fieldWriter = creteFieldWriter(objectClass, writerFieldFeatures, provider, beanInfo, fieldInfo, field);
if (fieldWriter != null) {
FieldWriter origin = fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);
if (origin != null && origin.compareTo(fieldWriter) > 0) {
fieldWriterMap.put(fieldWriter.fieldName, fieldWriter);
}
}
});
}
Class mixIn = provider.getMixIn(objectClass);
BeanUtils.getters(objectClass, mixIn, beanInfo.kotlin, method -> {
fieldInfo.init();
fieldInfo.features = writerFieldFeatures;
fieldInfo.format = beanInfo.format;
provider.getFieldInfo(beanInfo, fieldInfo, objectClass, method);
if (fieldInfo.ignore) {
return;
}
String fieldName = getFieldName(objectClass, provider, beanInfo, record, fieldInfo, method);
if (beanInfo.includes != null && beanInfo.includes.length > 0) {
boolean match = false;
for (String include : beanInfo.includes) {
if (include.equals(fieldName)) {
match = true;
break;
}
}
if (!match) {
return;
}
}
// skip typeKey field
if ((beanInfo.writerFeatures & WriteClassName.mask) != 0
&& fieldName.equals(beanInfo.typeKey)) {
return;
}
if (beanInfo.orders != null) {
boolean match = false;
for (int i = 0; i < beanInfo.orders.length; i++) {
if (fieldName.equals(beanInfo.orders[i])) {
fieldInfo.ordinal = i;
match = true;
}
}
if (!match) {
if (fieldInfo.ordinal == 0) {
fieldInfo.ordinal = beanInfo.orders.length;
}
}
}
Class<?> returnType = method.getReturnType();
// skip function
if (isFunction(returnType)) {
return;
}
ObjectWriter writeUsingWriter = null;
if (fieldInfo.writeUsing != null) {
try {
Constructor<?> constructor = fieldInfo.writeUsing.getDeclaredConstructor();
constructor.setAccessible(true);
writeUsingWriter = (ObjectWriter) constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new JSONException("create writeUsing Writer error", e);
}
}
if (writeUsingWriter == null && fieldInfo.fieldClassMixIn) {
writeUsingWriter = ObjectWriterBaseModule.VoidObjectWriter.INSTANCE;
}
FieldWriter fieldWriter = null;
if ((beanInfo.readerFeatures & FieldInfo.JIT) != 0) {
try {
fieldWriter = createFieldWriterLambda(
provider,
objectClass,
fieldName,
fieldInfo.ordinal,
fieldInfo.features,
fieldInfo.format,
fieldInfo.label,
method,
writeUsingWriter,
fieldInfo.contentAs
);
} catch (Throwable ignored) {
jitErrorCount.incrementAndGet();
jitErrorLast = ignored;
}
}
if (fieldWriter == null) {
fieldWriter = createFieldWriter(
provider,
objectClass,
fieldName,
fieldInfo.ordinal,
fieldInfo.features,
fieldInfo.format,
fieldInfo.locale,
fieldInfo.label,
method,
writeUsingWriter,
fieldInfo.contentAs
);
}
FieldWriter origin = fieldWriterMap.putIfAbsent(fieldWriter.fieldName, fieldWriter);
if (origin != null && origin.compareTo(fieldWriter) > 0) {
fieldWriterMap.put(fieldName, fieldWriter);
}
// the sameFieldName means only differ in first character that one is upper case the other is lower case
if (origin == null) {
String sameFieldName = null;
char firstChar = fieldName.charAt(0);
if (firstChar >= 'A' && firstChar <= 'Z') {
sameFieldName = (char) (firstChar + 32) + fieldName.substring(1);
} else if (firstChar >= 'a' && firstChar <= 'z') {
sameFieldName = (char) (firstChar - 32) + fieldName.substring(1);
}
if (sameFieldName != null) {
fieldWriterMap.remove(sameFieldName);
}
}
});
fieldWriters = new ArrayList<>(fieldWriterMap.values());
}
}
long writerFeatures = features | beanInfo.writerFeatures;
if ((!fieldBased) && Throwable.class.isAssignableFrom(objectClass)) {
return new ObjectWriterException(objectClass, writerFeatures, fieldWriters);
}
handleIgnores(beanInfo, fieldWriters);
if (beanInfo.alphabetic) {
Collections.sort(fieldWriters);
}
if (BeanUtils.isExtendedMap(objectClass)) {
Type superType = objectClass.getGenericSuperclass();
FieldWriter superWriter = ObjectWriters.fieldWriter(
SUPER,
superType,
objectClass.getSuperclass(),
Function.identity()
);
fieldWriters.add(superWriter);
}
setDefaultValue(fieldWriters, objectClass);
ObjectWriterAdapter writerAdapter = null;
boolean googleCollection;
String typeName = objectClass.getName();
googleCollection =
"com.google.common.collect.AbstractMapBasedMultimap$RandomAccessWrappedList".equals(typeName)
|| "com.google.common.collect.AbstractMapBasedMultimap$WrappedSet".equals(typeName);
if (!googleCollection && beanInfo.rootName == null) {
switch (fieldWriters.size()) {
case 1:
if ((fieldWriters.get(0).features & FieldInfo.VALUE_MASK) == 0) {
writerAdapter = new ObjectWriter1(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
}
break;
case 2:
writerAdapter = new ObjectWriter2(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 3:
writerAdapter = new ObjectWriter3(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 4:
writerAdapter = new ObjectWriter4(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 5:
writerAdapter = new ObjectWriter5(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 6:
writerAdapter = new ObjectWriter6(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 7:
writerAdapter = new ObjectWriter7(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 8:
writerAdapter = new ObjectWriter8(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 9:
writerAdapter = new ObjectWriter9(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 10:
writerAdapter = new ObjectWriter10(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 11:
writerAdapter = new ObjectWriter11(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
case 12:
writerAdapter = new ObjectWriter12(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
break;
default:
break;
}
}
if (writerAdapter == null) {
if (beanInfo.rootName != null) {
writerAdapter = new ObjectWriterRootName(objectClass, beanInfo.typeKey, beanInfo.typeName, beanInfo.rootName, writerFeatures, fieldWriters);
} else {
writerAdapter = new ObjectWriterAdapter(objectClass, beanInfo.typeKey, beanInfo.typeName, writerFeatures, fieldWriters);
}
}
if (beanInfo.serializeFilters != null) {
configSerializeFilters(beanInfo, writerAdapter);
}
return writerAdapter;
}