一、枚舉值轉換成徹底的json;java
二、對象中的枚舉成員徹底轉換成json;json
三、枚舉類的所有值轉換成json;api
public enum SongsEnum { SAFE_AND_SOUND(1,"Taylor Swift","Safe&Sound","2011-12-26") ,SHAKE_IT_OFF(2,"Taylor Swift","Shake It Off","2014-08-19") ,STYLE(3,"Taylor Swift","Style","2015-02-09") ,SOUND_OF_SILENCE(4,"Simon & Garfunkel","The Sound Of Silence","1966-01-17") ,BETTER_MAN(5,"Little Big Town","Better Man","2016-10-20") ,YESTERDAY_ONCE_MORE(6,"Carpenters","Yesterday Once More","1973-05-16") ; public final int index; public final String singer; public final String name; public final String date; private SongsEnum(int seq, String singer, String name, String date) { this.index = seq; this.singer = singer; this.name = name; this.date = date; } public int getIndex() { return index; } public String getSinger() { return singer; } public String getName() { return name; } public String getDate() { return date; } }
指望結果:SongsEnum.SAFE_AND_SOUND -> {"date":"2011-12-26","index":1,"name":"Safe&Sound","singer":"Taylor Swift"}數組
## 默認調用結果
JSON.toJSONString(SongsEnum.SAFE_AND_SOUND) -> "SAFE_AND_SOUND" JSON.toJSONString(SongsEnum.BETTER_MAN,SerializerFeature.WriteEnumUsingName) -> "BETTER_MAN" JSON.toJSONString(SongsEnum.STYLE,SerializerFeature.WriteEnumUsingToString) -> "STYLE"
默認的使用fastjson轉換enum,那麼獲得的enum json可能不是想要的.ide
(1) 重寫enum的toString()測試
@Override public String toString() { return "{'name':"+this.name+",'singer':"+this.singer+"}"; } JSON.toJSONString(SongsEnum.STYLE,SerializerFeature.WriteEnumUsingToString) -> "{'name':Style,'singer':Taylor Swift}"
雖然能夠這樣獲得想要的結果,但相對來講太麻煩,每一個enum類都要從寫toString().ui
(此種方式並無研究,因此以上重寫toString()的代碼可能存在問題)this
(2) fastjson的config設置spa
fastjson提供的JSON.toJSONString(...)有不少重載的方法,例如:debug
public static String toJSONString(Object object, SerializeConfig config, SerializerFeature... features)
因此,fastjson能夠經過設置SerializeConfig來配置enum的序列化。
public static void main(String[] args) { SerializeConfig config = new SerializeConfig(); config.configEnumAsJavaBean(SongsEnum.class); String s = JSON.toJSONString(SongsEnum.SOUND_OF_SILENCE, config); System.out.println(s); // {"date":"1966-01-17","index":4,"name":"The Sound Of Silence","singer":"Simon & Garfunkel"} }
public enum StatusEnum { STATUS_A(0,"狀態A"), STATUS_B(1,"狀態B"), STATUS_C(2,"狀態C"); public final int index; public final String status; StatusEnum(int i, String status) { this.index = i; this.status = status; } public int getIndex() { return index; } public String getStatus() { return status; } }
class JavaBean{ private String name; private SongsEnum song; private StatusEnum status; public JavaBean(String name,SongsEnum song,StatusEnum status){ this.name = name; this.song = song; this.status = status; } //省略setter/getter }
指望: {"name":"vegilyn","song":{"date":"2014-08-19","index":2,"name":"Shake It Off","singer":"Taylor Swift"},"status":{"index":1,"status":"狀態B"}}
默認結果:
JSON.toJSONString(new JavaBean("vegilyn",SongsEnum.SHAKE_IT_OFF,StatusEnum.STATUS_B)) -> {"name":"vegilyn","song":"SHAKE_IT_OFF","status":"STATUS_B"}
能夠看出此結果和目的1中的結果同樣的,因此經過目的1的方式也能夠解決。
SerializeConfig config = new SerializeConfig();
config.configEnumAsJavaBean(SongsEnum.class); // 配置enum轉換 String s = JSON.toJSONString(new JavaBean("vegilyn",SongsEnum.SHAKE_IT_OFF,StatusEnum.STATUS_B),config); System.out.println(s); // {"name":"vegilyn","song":{"date":"2014-08-19","index":2,"name":"Shake It Off","singer":"Taylor Swift"},"status":"STATUS_B"}
SerializeConfig config = new SerializeConfig(); config.configEnumAsJavaBean(SongsEnum.class,StatusEnum.class); // 配置enum轉換 String s = JSON.toJSONString(new JavaBean("vegilyn",SongsEnum.SHAKE_IT_OFF,StatusEnum.STATUS_B),config); System.out.println(s); // {"name":"vegilyn","song":{"date":"2014-08-19","index":2,"name":"Shake It Off","singer":"Taylor Swift"},"status":{"index":1,"status":"狀態B"}}
特別枚舉數組轉換的json:(注意重複值的json值)
public static void main(String[] args) { SongsEnum[] songsEnums = {SongsEnum.BETTER_MAN, SongsEnum.SAFE_AND_SOUND, SongsEnum.BETTER_MAN}; SerializeConfig config = new SerializeConfig(); config.configEnumAsJavaBean(SongsEnum.class); System.out.println(JSON.toJSONString(songsEnums,config));
}
// [{"date":"2016-10-20","index":5,"name":"Better Man","singer":"Little Big Town"},{"date":"2011-12-26","index":1,"name":"Safe&Sound","singer":"Taylor Swift"},{"$ref":"$[0]"}]
指望結果:
[ {"index": 1, "singer": "Taylor Swift", "name": "Safe&Sound", "date": "2011-12-26"}, {"index": 2, "singer": "Taylor Swift", "name": "Shake It Off", "date": "2014-08-19"}, {"index": 3, "singer": "Taylor Swift", "name": "Style", "date": "2015-02-09"}, {"index": 4, "singer": "Simon & Garfunkel", "name": "The Sound Of Silence", "date": "1966-01-17"}, {"index": 5, "singer": "Little Big Town", "name": "Better Man", "date": "2016-10-20"}, {"index": 6, "singer": "Carpenters", "name": "Yesterday Once More", "date": "1973-05-16"} ]
實現代碼:
public static void main(String[] args) { SongsEnum[] values = SongsEnum.values(); List<SongsEnum> songsEnums = new ArrayList<SongsEnum>(); for (SongsEnum value : values) { songsEnums.add(value); } SerializeConfig config = new SerializeConfig(); config.configEnumAsJavaBean(SongsEnum.class); System.out.println(JSON.toJSONString(songsEnums, config)); }
以上能達到想要的效果,可是,每一個enum類都要重複寫以上代碼。因此,利用反射來寫一個公共的方法。
public static String toJson(Class<? extends Enum> enumClass) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Method methodValues = enumClass.getMethod("values"); Object invoke = methodValues.invoke(null); int length = java.lang.reflect.Array.getLength(invoke); List<Object> values = new ArrayList<Object>(); for (int i=0; i<length; i++) { values.add(java.lang.reflect.Array.get(invoke, i)); } SerializeConfig config = new SerializeConfig(); config.configEnumAsJavaBean(enumClass); return JSON.toJSONString(values,config); }
public static void main(String[] args) { try { System.out.println(EnumJsonUtil.toJson(StatusEnum.class)); // [{"index":0,"status":"狀態A"},{"index":1,"status":"狀態B"},{"index":2,"status":"狀態C"}] } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
經過jdk反射機制獲得的field。
public static void main(String[] args) { Field[] fields = SongsEnum.class.getFields(); for (Field field : fields) { System.out.println(field.getName()); } } SAFE_AND_SOUND SHAKE_IT_OFF STYLE SOUND_OF_SILENCE BETTER_MAN YESTERDAY_ONCE_MORE index singer name date
如上,若是是經過jdk反射機制獲得class的filed。會發現獲得了不想要的結果,ex: SAFE_AND_SOUND 、SHAKE_IT_OFF 等。
想獲得的field其實只想要: index、singer、name、date。
固然也能夠本身分析,而後過濾出本身想要的class的field。
但下面看下fastjson中怎麼獲得enum中指望的field。(fastjson版本:1.2.31)
(1) 跟蹤代碼: new SerializeConfig().configEnumAsJavaBean(enumClass)
public void configEnumAsJavaBean(Class<? extends Enum>... enumClasses) { for (Class<? extends Enum> enumClass : enumClasses) { put(enumClass, createJavaBeanSerializer(enumClass)); } }
private final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) { SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBase); if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) { return MiscCodec.instance; } return createJavaBeanSerializer(beanInfo); }
public class SerializeBeanInfo { protected final Class<?> beanType; protected final String typeName; protected final JSONType jsonType; protected final FieldInfo[] fields; protected final FieldInfo[] sortedFields; protected int features; public SerializeBeanInfo(Class<?> beanType, // JSONType jsonType, // String typeName, // int features, FieldInfo[] fields, // FieldInfo[] sortedFields ){ this.beanType = beanType; this.jsonType = jsonType; this.typeName = typeName; this.features = features; this.fields = fields; this.sortedFields = sortedFields; } }
能夠看到SerializeBeanInfo 中定義的有 fields 。
(很好奇爲何定義成 protected , TyoeUtils.buildBeanInfo(...)是public的,返回的SerializeBeanInfo 也是public。
可是,SerializeBeanInfo. fields倒是protected 的。
致使我知道fastjson中有這麼一個util方法,能夠獲得我想要的enum信息(更確切的是能夠獲得class的信息)。
可是,最後我並不能直接在個人代碼中使用SerializeBeanInfo。)。
經過debug能夠看到SerializeBeanInfo對象的屬性,就是我想要的結果。
接着進去看TyoeUtils.buildBeanInfo(...)的實現:
public static SerializeBeanInfo buildBeanInfo(Class<?> beanType // , Map<String, String> aliasMap // , PropertyNamingStrategy propertyNamingStrategy // , boolean fieldBased // ) { JSONType jsonType = beanType.getAnnotation(JSONType.class); // fieldName,field ,先生成fieldName的快照,減小以後的findField的輪詢 Map<String, Field> fieldCacheMap = new HashMap<String, Field>(); ParserConfig.parserAllFieldToCache(beanType, fieldCacheMap); List<FieldInfo> fieldInfoList = fieldBased ? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) // : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy); // 省略... }
執行computeGetters(...)的結果:
public static List<FieldInfo> computeGetters(Class<?> clazz, // JSONType jsonType, // Map<String, String> aliasMap, // Map<String, Field> fieldCacheMap, // boolean sorted, // PropertyNamingStrategy propertyNamingStrategy // ) { Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<String, FieldInfo>(); for (Method method : clazz.getMethods()) { String methodName = method.getName(); int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0; String label = null; if (Modifier.isStatic(method.getModifiers())) { continue; } // 跳過static method if (method.getReturnType().equals(Void.TYPE)) { continue; } if (method.getParameterTypes().length != 0) { continue; } if (method.getReturnType() == ClassLoader.class) { continue; } if (method.getName().equals("getMetaClass") && method.getReturnType().getName().equals("groovy.lang.MetaClass")) { continue; } JSONField annotation = method.getAnnotation(JSONField.class); if (annotation == null) { annotation = getSuperMethodAnnotation(clazz, method); } if (annotation != null) { if (!annotation.serialize()) { continue; } ordinal = annotation.ordinal(); serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures()); parserFeatures = Feature.of(annotation.parseFeatures()); if (annotation.name().length() != 0) { String propertyName = annotation.name(); if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } FieldInfo fieldInfo = new FieldInfo(propertyName, method, null, clazz, null, ordinal, serialzeFeatures, parserFeatures, annotation, null, label); fieldInfoMap.put(propertyName, fieldInfo); continue; } if (annotation.label().length() != 0) { label = annotation.label(); } } if (methodName.startsWith("get")) { if (methodName.length() < 4) { continue; } if (methodName.equals("getClass")) { continue;} if (methodName.equals("getDeclaringClass") && clazz.isEnum()) { continue; } char c3 = methodName.charAt(3); String propertyName; if (Character.isUpperCase(c3) // || c3 > 512 // for unicode method name ) { if (compatibleWithJavaBean) { propertyName = decapitalize(methodName.substring(3)); } else { propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); } propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName,3); } else if (c3 == '_') { propertyName = methodName.substring(4); } else if (c3 == 'f') { propertyName = methodName.substring(3); } else if (methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))) { propertyName = decapitalize(methodName.substring(3)); } else { continue; } boolean ignore = isJSONTypeIgnore(clazz, propertyName); if (ignore) { continue; } //假如bean的field不少的狀況一下,輪詢時將大大下降效率 Field field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap); if (field == null && propertyName.length() > 1) { char ch = propertyName.charAt(1); if (ch >= 'A' && ch <= 'Z') { String javaBeanCompatiblePropertyName = decapitalize(methodName.substring(3)); field = ParserConfig.getFieldFromCache(javaBeanCompatiblePropertyName, fieldCacheMap); } } JSONField fieldAnnotation = null; if (field != null) { fieldAnnotation = field.getAnnotation(JSONField.class); if (fieldAnnotation != null) { if (!fieldAnnotation.serialize()) { continue; } ordinal = fieldAnnotation.ordinal(); serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); parserFeatures = Feature.of(fieldAnnotation.parseFeatures()); if (fieldAnnotation.name().length() != 0) { propertyName = fieldAnnotation.name(); if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } } if (fieldAnnotation.label().length() != 0) { label = fieldAnnotation.label(); } } } if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } if (propertyNamingStrategy != null) { propertyName = propertyNamingStrategy.translate(propertyName); } FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures, annotation, fieldAnnotation, label); fieldInfoMap.put(propertyName, fieldInfo); } if (methodName.startsWith("is")) { if (methodName.length() < 3) { continue; } if (method.getReturnType() != Boolean.TYPE && method.getReturnType() != Boolean.class) { continue; } char c2 = methodName.charAt(2); String propertyName; if (Character.isUpperCase(c2)) { if (compatibleWithJavaBean) { propertyName = decapitalize(methodName.substring(2)); } else { propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3); } propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName,2); } else if (c2 == '_') { propertyName = methodName.substring(3); } else if (c2 == 'f') { propertyName = methodName.substring(2); } else { continue; } Field field = ParserConfig.getFieldFromCache(propertyName,fieldCacheMap); if (field == null) { field = ParserConfig.getFieldFromCache(methodName,fieldCacheMap); } JSONField fieldAnnotation = null; if (field != null) { fieldAnnotation = field.getAnnotation(JSONField.class); if (fieldAnnotation != null) { if (!fieldAnnotation.serialize()) { continue; } ordinal = fieldAnnotation.ordinal(); serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); parserFeatures = Feature.of(fieldAnnotation.parseFeatures()); if (fieldAnnotation.name().length() != 0) { propertyName = fieldAnnotation.name(); if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } } if (fieldAnnotation.label().length() != 0) { label = fieldAnnotation.label(); } } } if (aliasMap != null) { propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } if (propertyNamingStrategy != null) { propertyName = propertyNamingStrategy.translate(propertyName); } //優先選擇get if (fieldInfoMap.containsKey(propertyName)) { continue; } FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures, annotation, fieldAnnotation, label); fieldInfoMap.put(propertyName, fieldInfo); } } // for methods end
// for methods : 優先經過定義的method來獲取FieldInfo。
// 而後,才經過Fields獲得沒有定義相似getXXX的field。
Field[] fields = clazz.getFields();
computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
return getFieldInfos(clazz, sorted, fieldInfoMap);
}
若是枚舉中的: index、singer、name、date。沒有定義getter方法,那麼fieldInfoMap在for methods end以後是empty的。
而且通過測試發現, 若是class中定義了: public final static String testName = "test";
只有提供了 : public String getTestName(){return testName;} 纔會被fastjson轉換。注:不能是public static方法。(緣由看上面的源碼)
或者 定義成 public final String testName = "test"; (但明顯沒有static的含義所在,緣由看下面源碼)
private static void computeFields( Class<?> clazz, // Map<String, String> aliasMap, // PropertyNamingStrategy propertyNamingStrategy, // Map<String, FieldInfo> fieldInfoMap, // Field[] fields) { for (Field field : fields) { if (Modifier.isStatic(field.getModifiers())) { // 若是是static 修飾的field 跳過。 continue; } JSONField fieldAnnotation = field.getAnnotation(JSONField.class); // fastjson提供的註解 int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0; String propertyName = field.getName(); String label = null; if (fieldAnnotation != null) { if (!fieldAnnotation.serialize()) { continue; } ordinal = fieldAnnotation.ordinal(); serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures()); parserFeatures = Feature.of(fieldAnnotation.parseFeatures()); if (fieldAnnotation.name().length() != 0) { propertyName = fieldAnnotation.name(); } if (fieldAnnotation.label().length() != 0) { label = fieldAnnotation.label(); } } if (aliasMap != null) { // 別名定義 propertyName = aliasMap.get(propertyName); if (propertyName == null) { continue; } } if (propertyNamingStrategy != null) { propertyName = propertyNamingStrategy.translate(propertyName); } if (!fieldInfoMap.containsKey(propertyName)) {// map中不存在該field的FieldInfo, 則建立一個 FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, clazz, null, ordinal, serialzeFeatures, parserFeatures, null, fieldAnnotation, label); fieldInfoMap.put(propertyName, fieldInfo); } } }
因此,根據枚舉的特性。ex: SAFE_AND_SOUND 、SHAKE_IT_OFF 等。在enum中的定義都是 public static final ...
而且在methods中也不存在getXXX。
若是,我在enum中定義一個method: getSAFE_AND_SOUND(),則field中會出現。