版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxin09/article/details/86688282
首先要说的是,笔者之前着实足够奇葩,净干别人未干过的事情,居然会想到用 JS 引擎来转换 JSON( 《用 Rhino/Nashorn 代替第三方 JSON 转换库》 、 《使用 Rhino 作为 Java 的 JSON 解析/转换包》 ),几经思考后,还是决然毅然放弃这个不切实际的想法,老老实实去写转换函数,几经打磨,有了下面“序列化” JSON 的 toJSON() 函数。
请先过目源码。
完整源码在:
https://gitee.com/sp42_admin/ajaxjs/blob/master/ajaxjs-base/src/main/java/com/ajaxjs/js/JsonHelper.java/** * 对 Object 尝试类型检测,将其合适地转换为 JSON 字符串返回。 * * @param obj 任意对象 * @return JSON 字符串 */ public static String toJson(Object obj) { if (obj == null) { return null; } else if (obj instanceof String) { return '/"' + obj.toString().replace("//", "////").replace("/"", "///"").replace("/n", "//n").replace("/r", "//r") + '/"'; } else if (obj instanceof Double) { return obj + ""; } else if (obj instanceof Boolean || obj instanceof Number) { return obj.toString(); } else if (obj instanceof Date) { return '/"' + CommonUtil.SimpleDateFormatFactory(CommonUtil.commonDateFormat).format((Date) obj) + '/"'; } else if (obj.getClass() == Integer[].class) { return jsonArr((Integer[]) obj, v -> v + ""); } else if (obj.getClass() == int[].class) { Integer[] arr = Arrays.stream((int[]) obj).boxed().toArray(Integer[]::new); return jsonArr(arr, v -> v + ""); } else if (obj instanceof Long[]) { return jsonArr((Long[]) obj, v -> v.toString()); } else if (obj instanceof long[]) { Long[] arr = Arrays.stream((long[]) obj).boxed().toArray(Long[]::new); return jsonArr(arr, v -> v.toString()); } else if (obj instanceof String[]) { return jsonArr((String[]) obj, v -> "/"" + v + "/""); } else if (obj instanceof Map) { return stringifyMap((Map<?, ?>) obj); } else if (obj instanceof Map[]) { return jsonArr((Map<?, ?>[]) obj, JsonHelper::stringifyMap); } else if (obj instanceof BaseModel) { return beanToJson((BaseModel) obj); } else if (obj instanceof BaseModel[]) { return jsonArr((BaseModel[]) obj, JsonHelper::beanToJson); } else if (obj instanceof List) { List<?> list = (List<?>) obj; if (list.size() > 0) { if (list.get(0) instanceof Integer) { return toJson(list.toArray(new Integer[list.size()])); } else if (list.get(0) instanceof String) { return toJson(list.toArray(new String[list.size()])); } else if (list.get(0) instanceof Map) { // Map 类型的输出 return toJson(list.toArray(new Map[list.size()])); } else if (list.get(0) instanceof BaseModel) { // Bean return toJson(list.toArray(new BaseModel[list.size()])); } } else { return "[]"; } } else if (obj instanceof Object[]) { return jsonArr((Object[]) obj, JsonHelper::toJson); } else if (obj instanceof Object) { // 普通 Java Object List<String> arr = new ArrayList<>(); for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); String key = field.getName(); if (key.indexOf("this$") != -1) continue; Object _obj = null; try { _obj = field.get(obj); } catch (IllegalAccessException e) { e.printStackTrace(); } arr.add('/"' + key + "/":" + toJson(_obj)); } return '{' + String.join(",", arr) + '}'; } else { throw new RuntimeException("不支持数据类型"); } return null; }
这函数比较长,很多的 if else 判断,目的是一个方法包办所有常见类型到 JSON 的转换。他可以涵盖下面类型,作为输入的参数:
null
boolean/Boolean
String, String[], List<String>
int/Integer, int[]/Integer[], List<Integer>
long/Long, long[]/Long[], List<Long>
Date 日期
Map/Map[]/List<Map>
BaseModel/BaseModel[]/List<BaseModel>
BaseModel 是我框架所有 Bean 的基类 Object
, 普通 Java Object 数组判断的话,首先有两种写法,是等价的,一种是 obj instanceof String[],另外一种是 obj.getClass() == int[].class,而且注意 Integer[] 和 int[] 类型的判断是不同的,要两种情况都要考虑。
JSON 中没有区分 Array 和 List,它只有 List。即使在 Java, Array 和 List 都离不开遍历的操作,我们把弄一块遍历好了。
/** * 输入任意类型数组,在 fn 作适当的转换,返回 JSON 字符串 * * @param o 数组 * @param fn 元素处理器,返回元素 JSON 字符串 * @return 数组的 JSON 字符串 */ public static <T> String jsonArr(T[] o, Function<T, String> fn) { if (o.length == 0) return "[]"; StringBuilder sb = new StringBuilder(); for (int i = 0; i < o.length; i++) { sb.append(fn.apply((T) o[i])); if (i != (o.length - 1)) sb.append(", "); } return '[' + sb.toString() + ']'; }
int[]/long[] 这些类型不能直接放在函数接口里面使用,因为 Java 的泛型就是要装箱类型的,故先转换一下,例如 Integer[] arr = Arrays.stream((int[]) obj).boxed().toArray(Integer[]::new);
。值得一提的是,如果集合元素个数为零,那么返回空数组 [],而不是 null 或者空字符串。
Map 和 Bean 都有直接的转换函数,分别是 JsonHelper::stringifyMap 和 JsonHelper::beanToJson,都是些常规性的操作,比较多的是递归操作,其它亮点不多,——可自行看源码了解。若是数组的话则递归一下即可。
至于 List<?>
的判断,则是取出其第一个元素作为类型的判断,然后归纳到数组的处理方法中(你不能依然还是拿 List 去递归,那样会死循环)。
下面是用法简介:
assertEquals(null, JsonHelper.toJson(null)); assertEquals("1.0", JsonHelper.toJson(1D)); assertEquals("true", JsonHelper.toJson(true)); assertEquals("1", JsonHelper.toJson(1)); assertEquals("1", JsonHelper.toJson(1L)); assertEquals("/"2018-02-20 00:00:00/"", JsonHelper.toJson((Date) MappingValue.objectCast("2018-2-20", Date.class))); List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); assertEquals("[1, 2, 3]", JsonHelper.toJson(list)); assertEquals("[1, 2, 3]", JsonHelper.toJson(new Integer[] { 1, 2, 3 })); assertEquals("[1, 2, 3]", JsonHelper.toJson(new int[] { 1, 2, 3 })); List<String> list2 = new ArrayList<>(); list2.add("1"); list2.add("2"); list2.add("3"); assertEquals("[/"1/", /"2/", /"3/"]", JsonHelper.toJson(list2)); assertEquals("[/"1/", /"2/", /"3/"]", JsonHelper.toJson(new String[] { "1", "2", "3" })); Map<String, Object> map = new HashMap<>(); assertEquals("{}", JsonHelper.toJson(map)); map.put("foo", "bar"); assertEquals("{/"foo/":/"bar/"}", JsonHelper.toJson(map)); map.put("bar", 1); assertEquals("{/"bar/":1,/"foo/":/"bar/"}", JsonHelper.toJson(map)); List<Map<String, Object>> list3 = new ArrayList<>(); assertEquals("[]", JsonHelper.toJson(list3)); list3.add(map); list3.add(map); assertEquals("[{/"bar/":1,/"foo/":/"bar/"}, {/"bar/":1,/"foo/":/"bar/"}]", JsonHelper.toJson(list3));
普通 Java Object 也可以表达 Key、Value 的结构,如下列,
@Test public void testStringifySimpleObject() { Object obj = new Object() { @SuppressWarnings("unused") public Object NULL = null; @SuppressWarnings("unused") public String str = null; @SuppressWarnings("unused") public Boolean isOk = false; @SuppressWarnings("unused") public Integer n0 = 0; @SuppressWarnings("unused") public Number n1 = 111; @SuppressWarnings("unused") public int n2 = 222; // @SuppressWarnings("unused") // public Date date = new Date(); @SuppressWarnings("unused") public String msg = "Hello world"; @SuppressWarnings("unused") public Object[] arr = new Object[] { 1, "2", null }; }; String jsonStr = JsonHelper.toJson(obj); // 输出 {"foo":"11","bar":"2222"} assertNotNull(jsonStr); assertEquals("{/"NULL/":null,/"str/":null,/"isOk/":false,/"n0/":0,/"n1/":111,/"n2/":222,/"msg/":/"Hello world/",/"arr/":[1, /"2/", null]}", jsonStr); }
toJSON() 也是支持这种结构的。