shade.com.alibaba.fastjson2.reader.ObjectReaderImplEnum Maven / Gradle / Ivy
package com.alibaba.fastjson2.reader;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.util.Fnv;
import com.alibaba.fastjson2.util.TypeUtils;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;
import static com.alibaba.fastjson2.JSONB.Constants.*;
public final class ObjectReaderImplEnum
implements ObjectReader {
final Method createMethod;
final Type createMethodParamType;
final Member valueField;
final Type valueFieldType;
final Class enumClass;
final long typeNameHash;
private final Enum[] enums;
private final Enum[] ordinalEnums;
private final long[] enumNameHashCodes;
private String[] stringValues;
private long[] intValues;
public ObjectReaderImplEnum(
Class enumClass,
Method createMethod,
Member valueField,
Enum[] enums,
Enum[] ordinalEnums,
long[] enumNameHashCodes
) {
this.enumClass = enumClass;
this.createMethod = createMethod;
if (valueField instanceof AccessibleObject) {
((AccessibleObject) valueField).setAccessible(true);
}
this.valueField = valueField;
Type valueFieldType = null;
if (valueField instanceof Field) {
valueFieldType = ((Field) valueField).getType();
} else if (valueField instanceof Method) {
valueFieldType = ((Method) valueField).getReturnType();
}
this.valueFieldType = valueFieldType;
if (valueFieldType != null) {
if (valueFieldType == String.class) {
stringValues = new String[enums.length];
} else {
intValues = new long[enums.length];
}
for (int i = 0; i < enums.length; i++) {
Enum e = enums[i];
try {
Object fieldValue;
if (valueField instanceof Field) {
fieldValue = ((Field) valueField).get(e);
} else {
fieldValue = ((Method) valueField).invoke(e);
}
if (valueFieldType == String.class) {
stringValues[i] = (String) fieldValue;
} else if (fieldValue instanceof Number) {
intValues[i] = ((Number) fieldValue).longValue();
}
} catch (Exception ignored) {
// ignored
}
}
}
Type createMethodParamType = null;
if (createMethod != null && createMethod.getParameterCount() == 1) {
createMethodParamType = createMethod.getParameterTypes()[0];
}
this.createMethodParamType = createMethodParamType;
this.typeNameHash = Fnv.hashCode64(TypeUtils.getTypeName(enumClass));
this.enums = enums;
this.ordinalEnums = ordinalEnums;
this.enumNameHashCodes = enumNameHashCodes;
}
@Override
public Class getObjectClass() {
return enumClass;
}
public Enum getEnumByHashCode(long hashCode) {
if (enums == null) {
return null;
}
int enumIndex = Arrays.binarySearch(this.enumNameHashCodes, hashCode);
if (enumIndex < 0) {
return null;
}
return enums[enumIndex];
}
public Enum getEnum(String name) {
if (name == null) {
return null;
}
return getEnumByHashCode(Fnv.hashCode64(name));
}
public Enum getEnumByOrdinal(int ordinal) {
if (ordinal < 0 || ordinal >= ordinalEnums.length) {
throw new JSONException("No enum ordinal " + enumClass.getCanonicalName() + "." + ordinal);
}
return ordinalEnums[ordinal];
}
public Enum of(int intValue) {
Enum enumValue = null;
if (valueField == null) {
if (intValue >= 0 && intValue < ordinalEnums.length) {
enumValue = ordinalEnums[intValue];
}
return enumValue;
}
try {
if (valueField instanceof Field) {
for (int i = 0; i < enums.length; i++) {
Enum e = enums[i];
if (((Field) valueField).getInt(e) == intValue) {
enumValue = e;
break;
}
}
} else {
Method valueMethod = (Method) valueField;
for (int i = 0; i < enums.length; i++) {
Enum e = enums[i];
if (((Number) valueMethod.invoke(e)).intValue() == intValue) {
enumValue = e;
break;
}
}
}
} catch (Exception error) {
throw new JSONException("parse enum error, class " + enumClass.getName() + ", value " + intValue, error);
}
if (enumValue == null) {
throw new JSONException("None enum ordinal or value " + intValue);
}
return enumValue;
}
@Override
public Object readJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
int start = jsonReader.getOffset();
byte type = jsonReader.getType();
if (type == BC_TYPED_ANY) {
ObjectReader autoTypeObjectReader = jsonReader.checkAutoType(enumClass, 0L, features);
if (autoTypeObjectReader != null) {
if (autoTypeObjectReader != this) {
return autoTypeObjectReader.readJSONBObject(jsonReader, fieldType, fieldName, features);
}
} else if (jsonReader.isEnabled(JSONReader.Feature.ErrorOnNotSupportAutoType)) {
throw new JSONException(jsonReader.info("not support enumType : " + jsonReader.getString()));
}
}
Enum fieldValue;
boolean isInt = (type >= BC_INT32_NUM_MIN && type <= BC_INT32);
if (isInt) {
int ordinal;
if (type <= BC_INT32_NUM_MAX) {
ordinal = type;
jsonReader.next();
} else {
ordinal = jsonReader.readInt32Value();
}
if (ordinal < 0 || ordinal >= ordinalEnums.length) {
throw new JSONException("No enum ordinal " + enumClass.getCanonicalName() + "." + ordinal);
}
fieldValue = ordinalEnums[ordinal];
} else if (jsonReader.nextIfNullOrEmptyString()) {
return null;
} else {
fieldValue = getEnumByHashCode(
jsonReader.readValueHashCode()
);
if (fieldValue == null) {
long nameHash = jsonReader.getNameHashCodeLCase();
fieldValue = getEnumByHashCode(nameHash);
}
}
if (fieldValue == null && jsonReader.getOffset() == start) {
oomCheck(fieldType);
}
return fieldValue;
}
private void oomCheck(Type fieldType) {
if (fieldType instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) fieldType).getRawType();
if (List.class.isAssignableFrom((Class>) rawType)) {
throw new JSONException(this.getClass().getSimpleName() + " parses error, JSONReader not forward when field type belongs to collection to avoid OOM");
}
}
}
@Override
public Object readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
int start = jsonReader.getOffset();
if (createMethodParamType != null) {
Object paramValue = jsonReader.read(createMethodParamType);
try {
return createMethod.invoke(null, paramValue);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new JSONException(jsonReader.info("create enum error, enumClass " + enumClass.getName() + ", paramValue " + paramValue), e);
}
}
Enum> fieldValue = null;
if (jsonReader.isInt()) {
int intValue = jsonReader.readInt32Value();
if (valueField == null) {
if (intValue < 0 || intValue >= ordinalEnums.length) {
throw new JSONException("No enum ordinal " + enumClass.getCanonicalName() + "." + intValue);
}
fieldValue = ordinalEnums[intValue];
} else {
if (intValues != null) {
for (int i = 0; i < intValues.length; i++) {
if (intValues[i] == intValue) {
fieldValue = enums[i];
break;
}
}
}
if (fieldValue == null && jsonReader.isEnabled(JSONReader.Feature.ErrorOnEnumNotMatch)) {
throw new JSONException(jsonReader.info("parse enum error, class " + enumClass.getName() + ", " + valueField.getName() + " " + intValue));
}
}
} else if (!jsonReader.nextIfNullOrEmptyString()) {
if (stringValues != null && jsonReader.isString()) {
String str = jsonReader.readString();
for (int i = 0; i < stringValues.length; i++) {
if (str.equals(stringValues[i])) {
fieldValue = enums[i];
break;
}
}
if (fieldValue == null && valueField != null) {
try {
fieldValue = Enum.valueOf(enumClass, str);
} catch (IllegalArgumentException ignored) {
// ignored
}
}
} else if (intValues != null && jsonReader.isString()) {
int intValue = jsonReader.readInt32Value();
for (int i = 0; i < intValues.length; i++) {
if (intValues[i] == intValue) {
fieldValue = enums[i];
break;
}
}
} else {
long hashCode = jsonReader.readValueHashCode();
if (hashCode == Fnv.MAGIC_HASH_CODE) {
return null;
}
fieldValue = getEnumByHashCode(hashCode);
if (fieldValue == null) {
fieldValue = getEnumByHashCode(
jsonReader.getNameHashCodeLCase()
);
}
if (fieldValue == null) {
String str = jsonReader.getString();
if (TypeUtils.isInteger(str)) {
int ordinal = Integer.parseInt(str);
if (ordinal >= 0 && ordinal < ordinalEnums.length) {
fieldValue = ordinalEnums[ordinal];
}
}
}
}
if (fieldValue == null && jsonReader.isEnabled(JSONReader.Feature.ErrorOnEnumNotMatch)) {
String strVal = jsonReader.getString();
throw new JSONException(jsonReader.info("parse enum error, class " + enumClass.getName() + ", value " + strVal));
}
}
if (fieldValue == null && jsonReader.getOffset() == start) {
oomCheck(fieldType);
}
return fieldValue;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy