package com.alibaba.fastjson.parser.deserializer; import java.lang.reflect.Type; import java.util.Arrays; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.parser.DefaultJSONParser; import com.alibaba.fastjson.parser.JSONLexer; import com.alibaba.fastjson.parser.JSONToken; @SuppressWarnings("rawtypes") public class EnumDeserializer implements ObjectDeserializer { private final Class<?> enumClass; protected final Enum[] enums; protected final Enum[] ordinalEnums; protected long[] enumNameHashCodes; public EnumDeserializer(Class<?> enumClass){ this.enumClass = enumClass; ordinalEnums = (Enum[]) enumClass.getEnumConstants(); long[] enumNameHashCodes = new long[ordinalEnums.length]; this.enumNameHashCodes = new long[ordinalEnums.length]; for (int i = 0; i < ordinalEnums.length; ++i) { String name = ordinalEnums[i].name(); long hash = 0x811c9dc5; for (int j = 0; j < name.length(); ++j) { char ch = name.charAt(j); hash ^= ch; hash *= 0x1000193; } enumNameHashCodes[i] = hash; this.enumNameHashCodes[i] = hash; } Arrays.sort(this.enumNameHashCodes); this.enums = new Enum[ordinalEnums.length]; for (int i = 0; i < this.enumNameHashCodes.length; ++i) { for (int j = 0; j < enumNameHashCodes.length; ++j) { if (this.enumNameHashCodes[i] == enumNameHashCodes[j]) { this.enums[i] = ordinalEnums[j]; break; } } } } 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<?> valueOf(int ordinal) { return ordinalEnums[ordinal]; } @SuppressWarnings("unchecked") public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { try { Object value; final JSONLexer lexer = parser.lexer; final int token = lexer.token(); if (token == JSONToken.LITERAL_INT) { int intValue = lexer.intValue(); lexer.nextToken(JSONToken.COMMA); if (intValue < 0 || intValue > ordinalEnums.length) { throw new JSONException("parse enum " + enumClass.getName() + " error, value : " + intValue); } return (T) ordinalEnums[intValue]; } else if (token == JSONToken.LITERAL_STRING) { String strVal = lexer.stringVal(); lexer.nextToken(JSONToken.COMMA); if (strVal.length() == 0) { return (T) null; } return (T) Enum.valueOf((Class<Enum>) enumClass, strVal); } else if (token == JSONToken.NULL) { value = null; lexer.nextToken(JSONToken.COMMA); return null; } else { value = parser.parse(); } throw new JSONException("parse enum " + enumClass.getName() + " error, value : " + value); } catch (JSONException e) { throw e; } catch (Exception e) { throw new JSONException(e.getMessage(), e); } } public int getFastMatchToken() { return JSONToken.LITERAL_INT; } }