Skip to content

Instantly share code, notes, and snippets.

@pfmiles
Last active January 12, 2018 09:35
Show Gist options
  • Save pfmiles/0c9abadfd82f9783f211 to your computer and use it in GitHub Desktop.
Save pfmiles/0c9abadfd82f9783f211 to your computer and use it in GitHub Desktop.
完整保留类型信息的json序列化/反序列化工具
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.fastjson.JSON;
/**
* @author pf-miles Feb 4, 2016 3:20:59 PM
*/
public class RuleSerializationUtilTest {
public static final class Apple {
private Apple inner;
public Apple getInner() {
return inner;
}
public void setInner(Apple inner) {
this.inner = inner;
}
@Override
public String toString() {
return "Apple [inner=" + inner + "]";
}
}
public static final class Box {
private Apple apple;
private List<Apple> apples;
private Apple[] appleArr;
private Map<String, String> map;
private Set<Apple> appleSet;
private Queue<Apple> appleQueue;
public Queue<Apple> getAppleQueue() {
return appleQueue;
}
public void setAppleQueue(Queue<Apple> appleQueue) {
this.appleQueue = appleQueue;
}
public Apple getApple() {
return apple;
}
public void setApple(Apple apple) {
this.apple = apple;
}
public List<Apple> getApples() {
return apples;
}
public void setApples(List<Apple> apples) {
this.apples = apples;
}
public Apple[] getAppleArr() {
return appleArr;
}
public void setAppleArr(Apple[] appleArr) {
this.appleArr = appleArr;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public Set<Apple> getAppleSet() {
return appleSet;
}
public void setAppleSet(Set<Apple> appleSet) {
this.appleSet = appleSet;
}
@Override
public String toString() {
return "Box [apple=" + apple + ", apples=" + apples + ", appleArr="
+ Arrays.toString(appleArr) + ", map=" + map + ", appleSet=" + appleSet
+ ", appleQueue=" + appleQueue + "]";
}
}
// 单个object
private Box box;
// object list
private List<Box> boxes;
@Before
public void init() {
Apple a = new Apple();
this.box = new Box();
List<Apple> alist = new ArrayList<Apple>();
alist.add(a);
Apple[] aArr = new Apple[1];
aArr[0] = a;
Map<String, String> map = new HashMap<String, String>();
map.put("test", "test");
Set<Apple> aSet = new HashSet<Apple>();
aSet.add(a);
Queue<Apple> aQueue = new LinkedList<Apple>();
aQueue.add(a);
this.box.setApple(a);
this.box.setAppleArr(aArr);
this.box.setApples(alist);
this.box.setAppleSet(aSet);
this.box.setMap(map);
this.box.setAppleQueue(aQueue);
this.boxes = new ArrayList<Box>();
this.boxes.add(box);
}
@Test
public void testToJavaObject() {
// obj
String jsonStr = JSON.toJSONString(this.box);
Box b = RuleSerializationUtil.toJavaObject(jsonStr, Box.class);
System.out.println(b);
// list
jsonStr = JSON.toJSONString(this.boxes);
List<Box> bs = RuleSerializationUtil.toJavaList(jsonStr, Box.class);
System.out.println(bs);
// list用toJavaObject, 虽然能成功,但无法做强类型转换
jsonStr = JSON.toJSONString(this.boxes);
bs = RuleSerializationUtil.toJavaObject(jsonStr, List.class);
System.out.println(bs);
}
// 测试to json string
@Test
public void testToJsonString() {
System.out.println(RuleSerializationUtil.toJsonString(this.box));
System.out.println(RuleSerializationUtil.toJsonString(this.boxes));
}
}
package test;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.slf4j.Logger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
public abstract class TypeSafeSerializationUtil {
/**
* json对象类型标记
*/
public static final String CLAZZ = "_clazz";
//老数据兼容
private static final String CLASS = "class";
private static final Set<Class<?>> primitiveClasses = new HashSet<Class<?>>();
static {
primitiveClasses.add(boolean.class);
primitiveClasses.add(Boolean.class);
primitiveClasses.add(char.class);
primitiveClasses.add(Character.class);
primitiveClasses.add(byte.class);
primitiveClasses.add(Byte.class);
primitiveClasses.add(short.class);
primitiveClasses.add(Short.class);
primitiveClasses.add(int.class);
primitiveClasses.add(Integer.class);
primitiveClasses.add(long.class);
primitiveClasses.add(Long.class);
primitiveClasses.add(float.class);
primitiveClasses.add(Float.class);
primitiveClasses.add(double.class);
primitiveClasses.add(Double.class);
primitiveClasses.add(BigInteger.class);
primitiveClasses.add(BigDecimal.class);
primitiveClasses.add(String.class);
primitiveClasses.add(java.util.Date.class);
primitiveClasses.add(java.sql.Date.class);
primitiveClasses.add(java.sql.Time.class);
primitiveClasses.add(java.sql.Timestamp.class);
}
private static final Logger LOGGER = org.slf4j.LoggerFactory
.getLogger(TypeSafeSerializationUtil.class);
/**
* 将java对象序列化为json字符串, 带类型信息
*/
public static String toJsonString(Object javaObj) {
if (javaObj == null)
return null;
// 先将传入参数转换为带“class”key的map或List
Object toFastJson = toClassKnowingMapOrArray(javaObj);
// 再由fastJson输出
return JSON.toJSONString(toFastJson);
}
/**
* 将对象、list转换为list/map结构树, 带类型信息
*/
public static Object toMapOrList(Object javaObj) {
if (javaObj == null)
return null;
// 先将传入参数转换为带“class”key的map或List
return toClassKnowingMapOrArray(javaObj);
}
@SuppressWarnings("unchecked")
private static Object toClassKnowingMapOrArray(Object javaObj) {
if (javaObj == null)
return null;
Class<?> cls = javaObj.getClass();
if (cls.isArray()) {
List<Object> ret = new ArrayList<Object>();
int l = Array.getLength(javaObj);
for (int i = 0; i < l; i++) {
ret.add(toClassKnowingMapOrArray(Array.get(javaObj, i)));
}
return ret;
} else if (Collection.class.isAssignableFrom(cls)) {
List<Object> ret = new ArrayList<Object>();
for (Object o : ((Collection<?>) javaObj)) {
ret.add(toClassKnowingMapOrArray(o));
}
return ret;
} else if (Map.class.isAssignableFrom(cls)) {
for (Map.Entry<Object, Object> e : ((Map<Object, Object>) javaObj).entrySet()) {
e.setValue(toClassKnowingMapOrArray(e.getValue()));
}
return javaObj;
} else if (Enum.class.isAssignableFrom(cls)) {
return javaObj;
} else if (Class.class.equals(cls)) {
return javaObj;
} else if (isPrimitive(cls)) {
return javaObj;
} else if (cls.isAnnotation()) {
return javaObj;
} else {// 'normal' object, treated as the java-bean spec. goes.
Map<String, Object> ret = new HashMap<String, Object>();
try {
BeanInfo bi = Introspector.getBeanInfo(cls);
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
if (pd.getReadMethod() != null) {
if (CLASS.equals(pd.getName())) {
ret.put(CLAZZ,
((Class<?>) pd.getReadMethod().invoke(javaObj)).getName());
} else {
ret.put(pd.getName(),
toClassKnowingMapOrArray(pd.getReadMethod().invoke(javaObj)));
}
}
}
} catch (Throwable e) {
LOGGER.error("", e);
}
return ret;
}
}
private static boolean isPrimitive(Class<?> cls) {
return primitiveClasses.contains(cls);
}
/**
* json字符串解析并映射到指定类型的对象类型上
* @param jsonStr 要解析的json字符串
* @param retCls 期望返回的对象类型
* @return 指定类型的映射好的对象
*/
public static <T> T toJavaObject(String jsonStr, Class<T> retCls) {
return toJavaObject(jsonStr, retCls, null);
}
/**
* json字符串解析并映射到指定类型的对象类型上
* @param jsonStr 要解析的json字符串
* @param retCls 期望返回的对象类型
* @param cl 反序列化对象时期望使用的classloader
* @return 指定类型的映射好的对象
*/
public static <T> T toJavaObject(String jsonStr, Class<T> retCls, ClassLoader cl) {
if (jsonStr == null)
return null;
// 先由JSON转为JSONObject/JSONArray
Object obj = JSON.parse(jsonStr);
// 再由bean mapping映射为类
return toJavaObject(obj, retCls, cl);
}
// 将list以反射形式转换成array
private static <T> Object listToArray(Class<?> arrayComponentType, List<?> list) {
Object arr = Array.newInstance(arrayComponentType, list.size());
for (int i = 0; i < list.size(); i++)
Array.set(arr, i, list.get(i));
return arr;
}
private static Object typeMappingFromJsonObj(Object jsonObj, ClassLoader cl) {
if (jsonObj == null)
return null;
Class<?> cls = jsonObj.getClass();
Object ret = null;
if (JSONArray.class.equals(cls)) {// collection或array
List<Object> list = new ArrayList<Object>();
JSONArray arr = (JSONArray) jsonObj;
for (int i = 0; i < arr.size(); i++)
list.add(typeMappingFromJsonObj(arr.get(i), cl));
ret = list;
} else if (JSONObject.class.equals(cls)) {// map或pojo
JSONObject m = (JSONObject) jsonObj;
if (m.containsKey(CLAZZ)) {
Object clsStr = m.get(CLAZZ);
try {
// pojo
Class<?> pojoCls = null;
if (cl != null) {
pojoCls = cl.loadClass(clsStr.toString());
} else {
pojoCls = Class.forName(clsStr.toString());
}
ret = pojoCls.newInstance();
// mapping properties, reflectively
BeanInfo bi = Introspector.getBeanInfo(pojoCls);
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
if (CLASS.equals(pd.getName()))
continue;
if (pd.getWriteMethod() != null && m.containsKey(pd.getName())) {
Object jsonVal = m.get(pd.getName());
Class<?> propertyType = pd.getPropertyType();
if (jsonVal instanceof JSONObject) {
// 若是json map, 且目标侧的属性类型不是map或primitive,且数据本身不带clazz,则尝试辅助刷上类型
JSONObject jo = ((JSONObject) jsonVal);
if (!jo.containsKey(CLAZZ)
&& !Map.class.isAssignableFrom(propertyType)
&& !isPrimitive(propertyType)) {
jo.put(CLAZZ, propertyType.getName());
}
} else if (jsonVal instanceof JSONArray) {
// 若是json array,且目标侧的属性类型是带明确泛型实参的list/set或类型明确的pojo数组, 且不是primitive或map, 且数据本身不带clazz,则尝试辅助刷上类型
JSONArray ja = (JSONArray) jsonVal;
if (Collection.class.isAssignableFrom(propertyType)
|| propertyType.isArray()) {
Class<?> eleType = getEleType(propertyType,
pd.getWriteMethod());
if (eleType != null && !Map.class.isAssignableFrom(eleType)
&& !isPrimitive(eleType)) {
ListIterator<Object> os = ja.listIterator();
while (os.hasNext()) {
Object o = os.next();
if (o instanceof JSONObject
&& !((JSONObject) o).containsKey(CLAZZ)) {
((JSONObject) o).put(CLAZZ, eleType.getName());
} else if (o instanceof String && eleType != null) {
os.set(resolveEnumOrCls((String) o, eleType, cl));
}
}
}
}
} else if (jsonVal instanceof String && propertyType != null) {
// 处理enum和class属性的情况
jsonVal = resolveEnumOrCls((String) jsonVal, propertyType, cl);
}
Object val = typeMappingFromJsonObj(jsonVal, cl);
val = arrSetQueCompatible(val, propertyType);
try {
pd.getWriteMethod().invoke(ret, val);
} catch (IllegalArgumentException e) {
// ignore...
}
}
}
} catch (Throwable e) {
LOGGER.error("jsonObject " + jsonObj, e);
}
} else {// map
Map<String, Object> map = new HashMap<String, Object>();
JSONObject jo = (JSONObject) jsonObj;
for (Map.Entry<String, Object> e : jo.entrySet()) {
map.put(e.getKey(), typeMappingFromJsonObj(e.getValue(), cl));
}
ret = map;
}
} else if (Enum.class.isAssignableFrom(cls)) {// enum
ret = jsonObj;
} else if (Class.class.equals(cls)) {// class
ret = jsonObj;
} else if (cls.isAnnotation()) {// annotation
ret = jsonObj;
} else { // primitive
ret = jsonObj;
}
return ret;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object resolveEnumOrCls(String str, Class<?> cls,
ClassLoader cl) throws ClassNotFoundException {
if (Enum.class.isAssignableFrom(cls)) {
return Enum.valueOf((Class<Enum>) cls, str);
} else if (Class.class.equals(cls)) {
if (cl != null) {
return cl.loadClass(str);
} else {
return Class.forName(str);
}
}
return str;
}
// 尝试将val转换为指定的类型, 用于支持反序列化目标类型为array, set, queue的场景
private static Object arrSetQueCompatible(Object val, Class<?> type) {
// 兼容array
if (type.isArray() && val instanceof List) {
val = listToArray(type.getComponentType(), (List<?>) val);
}
// 兼容set/queue场景
if (Set.class.isAssignableFrom(type) && val instanceof Collection) {
val = new HashSet<Object>((Collection<?>) val);
} else if (Queue.class.isAssignableFrom(type) && val instanceof Collection) {
val = new LinkedList<Object>((Collection<?>) val);
}
return val;
}
// 获取list或array类型的元素类型
private static Class<?> getEleType(Class<?> col, Method writer) {
if (col.isArray()) {
return col.getComponentType();
} else if (Collection.class.isAssignableFrom(col)) {
// 尝试从writer method身上获取参数的泛型实参类型
try {
return (Class<?>) ((ParameterizedType) writer.getGenericParameterTypes()[0])
.getActualTypeArguments()[0];
} catch (Exception e) {
// ignore...
return null;
}
} else {
return null;
}
}
/**
* 将parse好的fast json对象映射到指定类型的对象类型上
* @param json parse好的fast json对象
* @param retCls 期望返回的目标对象类型
* @return 指定类型的对象实例
*/
public static <T> T toJavaObject(Object json, Class<?> retCls) {
return toJavaObject(json, retCls, null);
}
/**
* 将parse好的fast json对象映射到指定类型的对象类型上
* @param json parse好的fast json对象
* @param retCls 期望返回的目标对象类型
* @param cl 反序列化类时期望使用的classloader
* @return 指定类型的对象实例
*/
@SuppressWarnings("unchecked")
public static <T> T toJavaObject(Object json, Class<?> retCls, ClassLoader cl) {
// 若指定cls不是array或collection或map或primitive或interface或abstract cls, 且数据本身不带clazz, 则尝试主动为json刷上类型
if (retCls != null && !retCls.isArray() && !Collection.class.isAssignableFrom(retCls)
&& !Map.class.isAssignableFrom(retCls) && !isPrimitive(retCls)
&& !Class.class.equals(retCls) && !Enum.class.isAssignableFrom(retCls)
&& !retCls.isAnnotation() && !retCls.isInterface()
&& !Modifier.isAbstract(retCls.getModifiers()) && json instanceof JSONObject
&& !((JSONObject) json).containsKey(CLAZZ)) {
((JSONObject) json).put(CLAZZ, retCls.getName());
}
// 由bean mapping映射为类
Object ret = typeMappingFromJsonObj(json, cl);
// 支持一下retCls为array, set, queue时的场景
ret = arrSetQueCompatible(ret, retCls);
return (T) ret;
}
/**
* 将jsonArray格式的字符串反序列化为List
* @param jsonStr
* @param eleType list的元素类型
*/
public static <T> List<T> toJavaList(String jsonStr, Class<T> eleType) {
if (jsonStr == null)
return null;
JSONArray arr = JSON.parseArray(jsonStr);
return toJavaList(arr, eleType);
}
/**
* 将指定的fast json array转换为指定元素类型的list
* @param jsonArr 指定的fast json array
* @param eleType 期望得到的list的元素类型
*/
@SuppressWarnings("unchecked")
public static <T> List<T> toJavaList(JSONArray jsonArr, Class<T> eleType) {
if (jsonArr == null)
return null;
if (jsonArr.isEmpty())
return Collections.emptyList();
List<Object> ret = new ArrayList<Object>();
for (Object ele : jsonArr) {
T object = toJavaObject(ele, eleType);
if (object != null) {
ret.add(object);
}
}
return (List<T>) ret;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment