一、前言
关于开源jfinal-3.0包中对于自定义com.jfinal.json.Json,并分别实现com.jfinal.json.JFinalJson、com.jfinal.json.FastJson、com.jfinal.json.Jackson、com.jfinal.json.MixedJson及通过各自工厂类JFinalJsonFactory、FastJsonFactory、JacksonFactory及MixedJsonFactory,最后通过JsonManager进行统一管理,如下图所示
二、源码说明
1.Json类
package com.jfinal.json;@b@@b@import com.jfinal.kit.StrKit;@b@@b@/**@b@ * json string 与 object 互转抽象@b@ */@b@public abstract class Json {@b@ @b@ private static IJsonFactory defaultJsonFactory = new JFinalJsonFactory();@b@ @b@ private static String defaultDatePattern = null;@b@ @b@ protected String datePattern = null;@b@ @b@ static void setDefaultJsonFactory(IJsonFactory defaultJsonFactory) {@b@ if (defaultJsonFactory == null) {@b@ throw new IllegalArgumentException("defaultJsonFactory can not be null.");@b@ }@b@ Json.defaultJsonFactory = defaultJsonFactory;@b@ }@b@ @b@ static void setDefaultDatePattern(String defaultDatePattern) {@b@ if (StrKit.isBlank(defaultDatePattern)) {@b@ throw new IllegalArgumentException("defaultDatePattern can not be blank.");@b@ }@b@ Json.defaultDatePattern = defaultDatePattern;@b@ }@b@ @b@ public Json setDatePattern(String datePattern) {@b@ if (StrKit.isBlank(datePattern)) {@b@ throw new IllegalArgumentException("datePattern can not be blank.");@b@ }@b@ this.datePattern = datePattern;@b@ return this;@b@ }@b@ @b@ public String getDatePattern() {@b@ return datePattern;@b@ }@b@ @b@ public String getDefaultDatePattern() {@b@ return defaultDatePattern;@b@ }@b@ @b@ public static Json getJson() {@b@ return defaultJsonFactory.getJson();@b@ }@b@ @b@ public abstract String toJson(Object object);@b@ @b@ public abstract <T> T parse(String jsonString, Class<T> type);@b@}
2.FastJson.java、Jackson.java、JFinalJson.java、MixedJsonFactory.java
package com.jfinal.json;@b@@b@import com.alibaba.fastjson.JSON;@b@import com.alibaba.fastjson.serializer.SerializerFeature;@b@@b@/**@b@ * Json 转换 fastjson 实现.@b@ */@b@public class FastJson extends Json {@b@ @b@ public static FastJson getJson() {@b@ return new FastJson();@b@ }@b@ @b@ public String toJson(Object object) {@b@ // 优先使用对象级的属性 datePattern, 然后才是全局性的 defaultDatePattern@b@ String dp = datePattern != null ? datePattern : getDefaultDatePattern();@b@ if (dp == null) {@b@ return JSON.toJSONString(object);@b@ } else {@b@ return JSON.toJSONStringWithDateFormat(object, dp, SerializerFeature.WriteDateUseDateFormat); // return JSON.toJSONString(object, SerializerFeature.WriteDateUseDateFormat);@b@ }@b@ }@b@ @b@ public <T> T parse(String jsonString, Class<T> type) {@b@ return JSON.parseObject(jsonString, type);@b@ }@b@}
import java.text.SimpleDateFormat;@b@import com.fasterxml.jackson.annotation.JsonInclude.Include;@b@import com.fasterxml.jackson.databind.ObjectMapper;@b@@b@/**@b@ * Json 转换 jackson 实现.@b@ * @b@ * json 到 java 类型转换规则: http://wiki.fasterxml.com/JacksonInFiveMinutes@b@ * JSON TYPE JAVA TYPE@b@ * object LinkedHashMap<String,Object>@b@ * array ArrayList<Object>@b@ * string String@b@ * number (no fraction) Integer, Long or BigInteger (smallest applicable)@b@ * number (fraction) Double (configurable to use BigDecimal)@b@ * true|false Boolean@b@ * null null@b@ */@b@public class Jackson extends Json {@b@ @b@ // Jackson 生成 json 的默认行为是生成 null value,可设置此值全局改变默认行为@b@ private static boolean defaultGenerateNullValue = true;@b@ @b@ // generateNullValue 通过设置此值,可临时改变默认生成 null value 的行为@b@ protected Boolean generateNullValue = null;@b@ @b@ protected ObjectMapper objectMapper = new ObjectMapper();@b@ @b@ public static void setDefaultGenerateNullValue(boolean defaultGenerateNullValue) {@b@ Jackson.defaultGenerateNullValue = defaultGenerateNullValue;@b@ }@b@ @b@ public Jackson setGenerateNullValue(boolean generateNullValue) {@b@ this.generateNullValue = generateNullValue;@b@ return this;@b@ }@b@ @b@ /**@b@ * 通过获取 ObjectMapper 进行更个性化设置,满足少数特殊情况@b@ */@b@ public ObjectMapper getObjectMapper() {@b@ return objectMapper;@b@ }@b@ @b@ public static Jackson getJson() {@b@ return new Jackson();@b@ }@b@ @b@ public String toJson(Object object) {@b@ try {@b@ // 优先使用对象级的属性 datePattern, 然后才是全局性的 defaultDatePattern@b@ String dp = datePattern != null ? datePattern : getDefaultDatePattern();@b@ if (dp != null) {@b@ objectMapper.setDateFormat(new SimpleDateFormat(dp));@b@ }@b@ @b@ // 优先使用对象属性 generateNullValue,决定转换 json时是否生成 null value@b@ Boolean pnv = generateNullValue != null ? generateNullValue : defaultGenerateNullValue;@b@ if (pnv == false) {@b@ objectMapper.setSerializationInclusion(Include.NON_NULL);@b@ }@b@ @b@ return objectMapper.writeValueAsString(object);@b@ } catch (Exception e) {@b@ throw e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException(e);@b@ }@b@ }@b@ @b@ public <T> T parse(String jsonString, Class<T> type) {@b@ try {@b@ return objectMapper.readValue(jsonString, type);@b@ } catch (Exception e) {@b@ throw e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException(e);@b@ }@b@ }@b@}
package com.jfinal.json;@b@@b@import java.lang.reflect.Array;@b@import java.lang.reflect.Method;@b@import java.text.SimpleDateFormat;@b@import java.util.ArrayList;@b@import java.util.Collection;@b@import java.util.Collections;@b@import java.util.Enumeration;@b@import java.util.HashMap;@b@import java.util.Iterator;@b@import java.util.List;@b@import java.util.Map;@b@import com.jfinal.kit.StrKit;@b@import com.jfinal.plugin.activerecord.Model;@b@import com.jfinal.plugin.activerecord.Record;@b@@b@/**@b@ * Json 转换 JFinal 实现.@b@ * @b@ * json 到 java 类型转换规则:@b@ * string java.lang.String@b@ * number java.lang.Number@b@ * true|false java.lang.Boolean@b@ * null null@b@ * array java.util.List@b@ * object java.util.Map@b@ */@b@@SuppressWarnings({"rawtypes", "unchecked"})@b@public class JFinalJson extends Json {@b@ @b@ private static int defaultConvertDepth = 15;@b@ @b@ protected int convertDepth = defaultConvertDepth;@b@ protected String timestampPattern = "yyyy-MM-dd HH:mm:ss";@b@ protected String datePattern = "yyyy-MM-dd";@b@ @b@ /**@b@ * 设置全局性默认转换深度@b@ */@b@ public static void setDefaultConvertDepth(int defaultConvertDepth) {@b@ if (defaultConvertDepth < 2) {@b@ throw new IllegalArgumentException("defaultConvertDepth depth can not less than 2.");@b@ }@b@ JFinalJson.defaultConvertDepth = defaultConvertDepth;@b@ }@b@ @b@ public JFinalJson setConvertDepth(int convertDepth) {@b@ if (convertDepth < 2) {@b@ throw new IllegalArgumentException("convert depth can not less than 2.");@b@ }@b@ this.convertDepth = convertDepth;@b@ return this;@b@ }@b@ @b@ public JFinalJson setTimestampPattern(String timestampPattern) {@b@ if (StrKit.isBlank(timestampPattern)) {@b@ throw new IllegalArgumentException("timestampPattern can not be blank.");@b@ }@b@ this.timestampPattern = timestampPattern;@b@ return this;@b@ }@b@ @b@ public Json setDatePattern(String datePattern) {@b@ if (StrKit.isBlank(datePattern)) {@b@ throw new IllegalArgumentException("datePattern can not be blank.");@b@ }@b@ this.datePattern = datePattern;@b@ return this;@b@ }@b@ @b@ public static JFinalJson getJson() {@b@ return new JFinalJson();@b@ }@b@ @b@ protected String mapToJson(Map map, int depth) {@b@ if(map == null) {@b@ return "null";@b@ }@b@ StringBuilder sb = new StringBuilder();@b@ boolean first = true;@b@ Iterator iter = map.entrySet().iterator();@b@ @b@ sb.append('{');@b@ while(iter.hasNext()){@b@ if(first)@b@ first = false;@b@ else@b@ sb.append(',');@b@ @b@ Map.Entry entry = (Map.Entry)iter.next();@b@ toKeyValue(String.valueOf(entry.getKey()),entry.getValue(), sb, depth);@b@ }@b@ sb.append('}');@b@ return sb.toString();@b@ }@b@ @b@ protected String toKeyValue(String key, Object value, StringBuilder sb, int depth){@b@ sb.append('\"');@b@ if(key == null)@b@ sb.append("null");@b@ else@b@ escape(key, sb);@b@ sb.append('\"').append(':');@b@ @b@ sb.append(toJson(value, depth));@b@ @b@ return sb.toString();@b@ }@b@ @b@ protected String iteratorToJson(Iterator iter, int depth) {@b@ boolean first = true;@b@ StringBuilder sb = new StringBuilder();@b@ @b@ sb.append('[');@b@ while(iter.hasNext()){@b@ if(first)@b@ first = false;@b@ else@b@ sb.append(',');@b@ @b@ Object value = iter.next();@b@ if(value == null){@b@ sb.append("null");@b@ continue;@b@ }@b@ sb.append(toJson(value, depth));@b@ }@b@ sb.append(']');@b@ return sb.toString();@b@ }@b@ @b@ /**@b@ * Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).@b@ */@b@ protected String escape(String s) {@b@ if(s == null)@b@ return null;@b@ StringBuilder sb = new StringBuilder();@b@ escape(s, sb);@b@ return sb.toString();@b@ }@b@ @b@ protected void escape(String s, StringBuilder sb) {@b@ for(int i=0; i<s.length(); i++){@b@ char ch = s.charAt(i);@b@ switch(ch){@b@ case '"':@b@ sb.append("\\\"");@b@ break;@b@ case '\\':@b@ sb.append("\\\\");@b@ break;@b@ case '\b':@b@ sb.append("\\b");@b@ break;@b@ case '\f':@b@ sb.append("\\f");@b@ break;@b@ case '\n':@b@ sb.append("\\n");@b@ break;@b@ case '\r':@b@ sb.append("\\r");@b@ break;@b@ case '\t':@b@ sb.append("\\t");@b@ break;@b@ //case '/':@b@ // sb.append("\\/");@b@ // break;@b@ default:@b@ if((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) {@b@ String str = Integer.toHexString(ch);@b@ sb.append("\\u");@b@ for(int k=0; k<4-str.length(); k++) {@b@ sb.append('0');@b@ }@b@ sb.append(str.toUpperCase());@b@ }@b@ else{@b@ sb.append(ch);@b@ }@b@ }@b@ }@b@ }@b@ @b@ public String toJson(Object object) {@b@ return toJson(object, convertDepth);@b@ }@b@ @b@ protected String toJson(Object value, int depth) {@b@ if(value == null || (depth--) < 0)@b@ return "null";@b@ @b@ if(value instanceof String)@b@ return "\"" + escape((String)value) + "\"";@b@ @b@ if(value instanceof Double){@b@ if(((Double)value).isInfinite() || ((Double)value).isNaN())@b@ return "null";@b@ else@b@ return value.toString();@b@ }@b@ @b@ if(value instanceof Float){@b@ if(((Float)value).isInfinite() || ((Float)value).isNaN())@b@ return "null";@b@ else@b@ return value.toString();@b@ }@b@ @b@ if(value instanceof Number)@b@ return value.toString();@b@ @b@ if(value instanceof Boolean)@b@ return value.toString();@b@ @b@ if (value instanceof java.util.Date) {@b@ if (value instanceof java.sql.Timestamp) {@b@ return "\"" + new SimpleDateFormat(timestampPattern).format(value) + "\"";@b@ }@b@ if (value instanceof java.sql.Time) {@b@ return "\"" + value.toString() + "\"";@b@ }@b@ // 优先使用对象级的属性 datePattern, 然后才是全局性的 defaultDatePattern@b@ String dp = datePattern != null ? datePattern : getDefaultDatePattern();@b@ if (dp != null) {@b@ return "\"" + new SimpleDateFormat(dp).format(value) + "\"";@b@ } else {@b@ return "" + ((java.util.Date)value).getTime();@b@ }@b@ }@b@ @b@ if(value instanceof Collection) {@b@ return iteratorToJson(((Collection)value).iterator(), depth);@b@ }@b@ @b@ if(value instanceof Map) {@b@ return mapToJson((Map)value, depth);@b@ }@b@ @b@ String result = otherToJson(value, depth);@b@ if (result != null)@b@ return result;@b@ @b@ // 类型无法处理时当作字符串处理,否则ajax调用返回时js无法解析@b@ // return value.toString();@b@ return "\"" + escape(value.toString()) + "\"";@b@ }@b@ @b@ protected String otherToJson(Object value, int depth) {@b@ if (value instanceof Character) {@b@ return "\"" + escape(value.toString()) + "\"";@b@ }@b@ @b@ if (value instanceof Model) {@b@ Map map = com.jfinal.plugin.activerecord.CPI.getAttrs((Model)value);@b@ return mapToJson(map, depth);@b@ }@b@ if (value instanceof Record) {@b@ Map map = ((Record)value).getColumns();@b@ return mapToJson(map, depth);@b@ }@b@ if (value.getClass().isArray()) {@b@ int len = Array.getLength(value);@b@ List<Object> list = new ArrayList<Object>(len);@b@ for (int i=0; i<len; i++) {@b@ list.add(Array.get(value, i));@b@ }@b@ return iteratorToJson(list.iterator(), depth);@b@ }@b@ if (value instanceof Iterator) {@b@ return iteratorToJson((Iterator)value, depth);@b@ }@b@ if (value instanceof Enumeration) {@b@ ArrayList<?> list = Collections.list((Enumeration<?>)value);@b@ return iteratorToJson(list.iterator(), depth);@b@ }@b@ if (value instanceof Enum) {@b@ return "\"" + ((Enum)value).toString() + "\"";@b@ }@b@ @b@ return beanToJson(value, depth);@b@ }@b@ @b@ protected String beanToJson(Object model, int depth) {@b@ Map map = new HashMap();@b@ Method[] methods = model.getClass().getMethods();@b@ for (Method m : methods) {@b@ String methodName = m.getName();@b@ int indexOfGet = methodName.indexOf("get");@b@ if (indexOfGet == 0 && methodName.length() > 3) { // Only getter@b@ String attrName = methodName.substring(3);@b@ if (!attrName.equals("Class")) { // Ignore Object.getClass()@b@ Class<?>[] types = m.getParameterTypes();@b@ if (types.length == 0) {@b@ try {@b@ Object value = m.invoke(model);@b@ map.put(StrKit.firstCharToLowerCase(attrName), value);@b@ } catch (Exception e) {@b@ throw new RuntimeException(e.getMessage(), e);@b@ }@b@ }@b@ }@b@ }@b@ else {@b@ int indexOfIs = methodName.indexOf("is");@b@ if (indexOfIs == 0 && methodName.length() > 2) {@b@ String attrName = methodName.substring(2);@b@ Class<?>[] types = m.getParameterTypes();@b@ if (types.length == 0) {@b@ try {@b@ Object value = m.invoke(model);@b@ map.put(StrKit.firstCharToLowerCase(attrName), value);@b@ } catch (Exception e) {@b@ throw new RuntimeException(e.getMessage(), e);@b@ }@b@ }@b@ }@b@ }@b@ }@b@ return mapToJson(map, depth);@b@ }@b@ @b@ public <T> T parse(String jsonString, Class<T> type) {@b@ throw new RuntimeException("jfinal " + com.jfinal.core.Const.JFINAL_VERSION + @b@ "默认 json 实现暂不支持 json 到 object 的转换,建议使用 active recrord 的 Generator 生成 base model," +@b@ "再通过 me.setJsonFactory(new JacksonFactory()) 来支持");@b@ }@b@}
class MixedJson extends Json {@b@@b@ private static JFinalJson jFinalJson = JFinalJson.getJson();@b@ private static FastJson fastJson = FastJson.getJson();@b@@b@ public String toJson(Object object) {@b@ return jFinalJson.toJson(object);@b@ }@b@@b@ public <T> T parse(String jsonString, Class<T> type) {@b@ return fastJson.parse(jsonString, type);@b@ }@b@ }
2.工厂接口及实现工厂类
package com.jfinal.json;@b@@b@public interface IJsonFactory {@b@ Json getJson();@b@}
package com.jfinal.json;@b@ @b@public class FastJsonFactory implements IJsonFactory {@b@ @b@ private static final FastJsonFactory me = new FastJsonFactory();@b@ @b@ public static FastJsonFactory me() {@b@ return me;@b@ }@b@ @b@ public Json getJson() {@b@ return new FastJson();@b@ }@b@}
package com.jfinal.json;@b@@b@public class JacksonFactory implements IJsonFactory {@b@ @b@ private static final JacksonFactory me = new JacksonFactory();@b@ @b@ public static JacksonFactory me() {@b@ return me;@b@ }@b@ @b@ public Json getJson() {@b@ return new Jackson();@b@ }@b@}
package com.jfinal.json;@b@@b@public class JacksonFactory implements IJsonFactory {@b@ @b@ private static final JacksonFactory me = new JacksonFactory();@b@ @b@ public static JacksonFactory me() {@b@ return me;@b@ }@b@ @b@ public Json getJson() {@b@ return new Jackson();@b@ }@b@}
package com.jfinal.json;@b@@b@import com.jfinal.json.FastJson;@b@import com.jfinal.json.IJsonFactory;@b@import com.jfinal.json.JFinalJson;@b@import com.jfinal.json.Json;@b@ @b@public class MixedJsonFactory implements IJsonFactory {@b@ @b@ private static final MixedJsonFactory me = new MixedJsonFactory();@b@ @b@ public static MixedJsonFactory me() {@b@ return me;@b@ }@b@@b@ private static MixedJson mixedJson = new MixedJson();@b@@b@ public Json getJson() {@b@ return mixedJson;@b@ }@b@}
3.JsonManager类
package com.jfinal.json;@b@ @b@public class JsonManager {@b@ @b@ private static final JsonManager me = new JsonManager();@b@ @b@ private JsonManager() {}@b@ @b@ public static JsonManager me() {@b@ return me;@b@ }@b@ @b@ public void setDefaultJsonFactory(IJsonFactory defaultJsonFactory) {@b@ Json.setDefaultJsonFactory(defaultJsonFactory);@b@ }@b@ @b@ public void setDefaultDatePattern(String defaultDatePattern) {@b@ Json.setDefaultDatePattern(defaultDatePattern);@b@ }@b@}