Browse Source

add custom serialize support

Looly 6 years ago
parent
commit
caa8d6dea7

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@
 * 【core】        ArrayUtil增加distinct方法
 * 【http】         去除log模块依赖,Cookie中去除日志提示,body方法传入JSON对象废弃,未来移除json模块依赖
 * 【extra】        添加MyNLP支持(issue#519@Github)
+* 【json】         添加自定义序列化反序列化支持(issue#I1052A@Gitee)
 
 ### Bug修复
 

+ 28 - 3
hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java

@@ -44,7 +44,7 @@ public class ClassUtil {
 	public static <T> Class<T> getClass(T obj) {
 		return ((null == obj) ? null : (Class<T>) obj.getClass());
 	}
-	
+
 	/**
 	 * 获得外围类<br>
 	 * 返回定义此类或匿名类所在的类,如果类本身是在包中定义的,返回{@code null}
@@ -56,15 +56,16 @@ public class ClassUtil {
 	public static Class<?> getEnclosingClass(Class<?> clazz) {
 		return null == clazz ? null : clazz.getEnclosingClass();
 	}
-	
+
 	/**
 	 * 是否为顶层类,既定义在包中的类,而非定义在类中的内部类
+	 * 
 	 * @param clazz 类
 	 * @return 是否为顶层类
 	 * @since 4.5.7
 	 */
 	public static boolean isTopLevelClass(Class<?> clazz) {
-		if(null == clazz) {
+		if (null == clazz) {
 			return false;
 		}
 		return null == getEnclosingClass(clazz);
@@ -1018,4 +1019,28 @@ public class ClassUtil {
 		}
 		return values;
 	}
+
+	/**
+	 * 是否为JDK中定义的类或接口,判断依据:
+	 * 
+	 * <pre>
+	 * 1、以java.、javax.开头的包名
+	 * 2、ClassLoader为null
+	 * </pre>
+	 * 
+	 * @param clazz 被检查的类
+	 * @return 是否为JDK中定义的类或接口
+	 * @since 4.6.5
+	 */
+	public static boolean isJdkClass(Class<?> clazz) {
+		final Package objectPackage = clazz.getPackage();
+		if(null == objectPackage) {
+			return false;
+		}
+		final String objectPackageName = objectPackage.getName();
+		if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || clazz.getClassLoader() == null) {
+			return true;
+		}
+		return false;
+	}
 }

+ 68 - 26
hutool-json/src/main/java/cn/hutool/json/JSONArray.java

@@ -16,6 +16,9 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.CharUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.TypeUtil;
+import cn.hutool.json.serialize.GlobalSerializeMapping;
+import cn.hutool.json.serialize.JSONSerializer;
 
 /**
  * JSON数组<br>
@@ -32,7 +35,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 	private static final long serialVersionUID = 2664900568717612292L;
 
 	/** 默认初始大小 */
-	private static final int DEFAULT_CAPACITY = 10;
+	public static final int DEFAULT_CAPACITY = 10;
 
 	/** 持有原始数据的List */
 	private final List<Object> rawList;
@@ -63,6 +66,17 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 	 * 构造<br>
 	 * 默认使用{@link ArrayList} 实现
 	 * 
+	 * @param config JSON配置项
+	 * @since 4.6.5
+	 */
+	public JSONArray(JSONConfig config) {
+		this(DEFAULT_CAPACITY, config);
+	}
+
+	/**
+	 * 构造<br>
+	 * 默认使用{@link ArrayList} 实现
+	 * 
 	 * @param initialCapacity 初始大小
 	 * @param config JSON配置项
 	 * @since 4.1.19
@@ -152,11 +166,30 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 	 * @throws JSONException 非数组或集合
 	 */
 	public JSONArray(Object object, boolean ignoreNullValue) throws JSONException {
-		this(DEFAULT_CAPACITY, JSONConfig.create().setIgnoreNullValue(ignoreNullValue));
+		this(object, JSONConfig.create().setIgnoreNullValue(ignoreNullValue));
+	}
+
+	/**
+	 * 从对象构造<br>
+	 * 支持以下类型的参数:
+	 * 
+	 * <pre>
+	 * 1. 数组
+	 * 2. {@link Iterable}对象
+	 * 3. JSON数组字符串
+	 * </pre>
+	 *
+	 * @param object 数组或集合或JSON数组字符串
+	 * @param jsonConfig JSON选项
+	 * @throws JSONException 非数组或集合
+	 * @since 4.6.5
+	 */
+	public JSONArray(Object object, JSONConfig jsonConfig) throws JSONException {
+		this(DEFAULT_CAPACITY, jsonConfig);
 		init(object);
 	}
 	// -------------------------------------------------------------------------------------------------------------------- Constructor start
-	
+
 	/**
 	 * 设置转为字符串时的日期格式,默认为时间戳(null值)
 	 * 
@@ -330,7 +363,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 
 	@Override
 	public boolean add(Object e) {
-		return this.rawList.add(JSONUtil.wrap(e, this.config.isIgnoreNullValue()));
+		return this.rawList.add(JSONUtil.wrap(e, this.config));
 	}
 
 	@Override
@@ -366,7 +399,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		}
 		final ArrayList<Object> list = new ArrayList<>(c.size());
 		for (Object object : c) {
-			list.add(JSONUtil.wrap(object, this.config.isIgnoreNullValue()));
+			list.add(JSONUtil.wrap(object, this.config));
 		}
 		return rawList.addAll(index, list);
 	}
@@ -389,17 +422,17 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 
 	@Override
 	public Object set(int index, Object element) {
-		return this.rawList.set(index, JSONUtil.wrap(element, this.config.isIgnoreNullValue()));
+		return this.rawList.set(index, JSONUtil.wrap(element, this.config));
 	}
 
 	@Override
 	public void add(int index, Object element) {
 		if (index < 0) {
-			throw new JSONException("JSONArray[" + index + "] not found.");
+			throw new JSONException("JSONArray[{}] not found.", index);
 		}
 		if (index < this.size()) {
 			InternalJSONUtil.testValidity(element);
-			this.rawList.add(index, JSONUtil.wrap(element, this.config.isIgnoreNullValue()));
+			this.rawList.add(index, JSONUtil.wrap(element, this.config));
 		} else {
 			while (index != this.size()) {
 				this.add(JSONNull.NULL);
@@ -455,7 +488,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 	public <T> List<T> toList(Class<T> elementType) {
 		return JSONConverter.toList(this, elementType);
 	}
-	
+
 	/**
 	 * 转为JSON字符串,无缩进
 	 *
@@ -512,7 +545,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 	}
 
 	// ------------------------------------------------------------------------------------------------- Private method start
-	
+
 	/**
 	 * 将JSON内容写入Writer
 	 * 
@@ -528,22 +561,22 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		final boolean isIgnoreNullValue = this.config.isIgnoreNullValue();
 		boolean isFirst = true;
 		for (Object obj : this.rawList) {
-			if(ObjectUtil.isNull(obj) && isIgnoreNullValue) {
+			if (ObjectUtil.isNull(obj) && isIgnoreNullValue) {
 				continue;
 			}
 			if (isFirst) {
 				isFirst = false;
-			}else {
+			} else {
 				writer.write(CharUtil.COMMA);
 			}
-			
+
 			if (indentFactor > 0) {
 				writer.write(CharUtil.LF);
 			}
 			InternalJSONUtil.indent(writer, newindent);
 			InternalJSONUtil.writeValue(writer, obj, indentFactor, newindent, this.config);
 		}
-		
+
 		if (indentFactor > 0) {
 			writer.write(CharUtil.LF);
 		}
@@ -551,25 +584,34 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 		writer.write(CharUtil.BRACKET_END);
 		return writer;
 	}
-	
+
 	/**
 	 * 初始化
 	 * 
-	 * @param object 数组或集合或JSON数组字符串
+	 * @param source 数组或集合或JSON数组字符串
 	 * @throws JSONException 非数组或集合
 	 */
-	private void init(Object object) throws JSONException{
-		if (object instanceof CharSequence) {
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	private void init(Object source) throws JSONException {
+		if (null == source) {
+			return;
+		}
+
+		final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
+		if (null != serializer && JSONArray.class.equals(TypeUtil.getTypeArgument(serializer.getClass()))) {
+			// 自定义序列化
+			serializer.serialize(this, source);
+		} else if (source instanceof CharSequence) {
 			// JSON字符串
-			init((CharSequence) object);
+			init((CharSequence) source);
 		} else {
 			Iterator<?> iter;
-			if (object.getClass().isArray()) {// 数组
-				iter = new ArrayIter<>(object);
-			} else if (object instanceof Iterator<?>) {// Iterator
-				iter = ((Iterator<?>) object);
-			} else if (object instanceof Iterable<?>) {// Iterable
-				iter = ((Iterable<?>) object).iterator();
+			if (source.getClass().isArray()) {// 数组
+				iter = new ArrayIter<>(source);
+			} else if (source instanceof Iterator<?>) {// Iterator
+				iter = ((Iterator<?>) source);
+			} else if (source instanceof Iterable<?>) {// Iterable
+				iter = ((Iterable<?>) source).iterator();
 			} else {
 				throw new JSONException("JSONArray initial value should be a string or collection or array.");
 			}
@@ -578,7 +620,7 @@ public class JSONArray extends JSONGetter<Integer> implements JSON, List<Object>
 			}
 		}
 	}
-	
+
 	/**
 	 * 初始化
 	 * 

+ 9 - 0
hutool-json/src/main/java/cn/hutool/json/JSONConverter.java

@@ -11,6 +11,8 @@ import cn.hutool.core.convert.impl.ArrayConverter;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.TypeUtil;
+import cn.hutool.json.serialize.GlobalSerializeMapping;
+import cn.hutool.json.serialize.JSONDeserializer;
 
 /**
  * JSON转换器
@@ -68,6 +70,13 @@ public class JSONConverter implements Converter<JSON> {
 			return null;
 		}
 		
+		if(value instanceof JSON) {
+			JSONDeserializer<?> deserializer = GlobalSerializeMapping.getDeserializer(targetType);
+			if(null != deserializer) {
+				return (T) deserializer.deserialize((JSON)value);
+			}
+		}
+		
 		Object targetValue = null;
 		try {
 			targetValue = Convert.convert(targetType, value);

+ 26 - 10
hutool-json/src/main/java/cn/hutool/json/JSONObject.java

@@ -26,6 +26,9 @@ import cn.hutool.core.util.CharUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ReflectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.serialize.GlobalSerializeMapping;
+import cn.hutool.json.serialize.JSONObjectSerializer;
+import cn.hutool.json.serialize.JSONSerializer;
 
 /**
  * JSON对象<br>
@@ -41,7 +44,7 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 	private static final long serialVersionUID = -330220388580734346L;
 
 	/** 默认初始大小 */
-	private static final int DEFAULT_CAPACITY = 16;
+	public static final int DEFAULT_CAPACITY = 16;
 
 	/** JSON的KV持有Map */
 	private final Map<String, Object> rawHashMap;
@@ -88,6 +91,16 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 	public JSONObject(int capacity, boolean isIgnoreCase, boolean isOrder) {
 		this(capacity, JSONConfig.create().setIgnoreCase(isIgnoreCase).setOrder(isOrder));
 	}
+	
+	/**
+	 * 构造
+	 * 
+	 * @param config JSON配置项
+	 * @since 4.6.5
+	 */
+	public JSONObject(JSONConfig config) {
+		this(DEFAULT_CAPACITY, config);
+	}
 
 	/**
 	 * 构造
@@ -389,7 +402,7 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 			this.remove(key);
 		} else {
 			InternalJSONUtil.testValidity(value);
-			this.rawHashMap.put(key, JSONUtil.wrap(value, ignoreNullValue));
+			this.rawHashMap.put(key, JSONUtil.wrap(value, this.config));
 		}
 		return this;
 	}
@@ -699,7 +712,7 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 
 			if (value != bean) {
 				// 防止循环引用
-				this.rawHashMap.put(prop.getFieldName(), JSONUtil.wrap(value, this.config.isIgnoreNullValue()));
+				this.put(prop.getFieldName(), value);
 			}
 		}
 	}
@@ -715,23 +728,26 @@ public class JSONObject extends JSONGetter<String> implements JSON, Map<String,
 	 * 
 	 * @param source JavaBean或者Map对象或者String
 	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
 	private void init(Object source) {
 		if (null == source) {
 			return;
 		}
-
-		if (source instanceof Map) {
-			boolean ignoreNullValue = this.config.isIgnoreNullValue();
+		
+		final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
+		if(null != serializer && serializer instanceof JSONObjectSerializer) {
+			// 自定义序列化
+			serializer.serialize(this, source);
+		} else if (source instanceof Map) {
+			// Map
 			for (final Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
-				final Object value = e.getValue();
-				if (false == ignoreNullValue || null != value) {
-					this.rawHashMap.put(Convert.toStr(e.getKey()), JSONUtil.wrap(value, ignoreNullValue));
-				}
+				this.put(Convert.toStr(e.getKey()), e.getValue());
 			}
 		} else if (source instanceof CharSequence) {
 			// 可能为JSON字符串
 			init((CharSequence) source);
 		} else if (source instanceof JSONTokener) {
+			// JSONTokener
 			init((JSONTokener) source);
 		} else if (source instanceof Number) {
 			// ignore Number

+ 64 - 10
hutool-json/src/main/java/cn/hutool/json/JSONUtil.java

@@ -18,9 +18,16 @@ import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.file.FileReader;
 import cn.hutool.core.lang.TypeReference;
 import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ClassUtil;
 import cn.hutool.core.util.HexUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.TypeUtil;
+import cn.hutool.json.serialize.GlobalSerializeMapping;
+import cn.hutool.json.serialize.JSONArraySerializer;
+import cn.hutool.json.serialize.JSONDeserializer;
+import cn.hutool.json.serialize.JSONObjectSerializer;
+import cn.hutool.json.serialize.JSONSerializer;
 
 /**
  * JSON工具类
@@ -596,12 +603,13 @@ public final class JSONUtil {
 	 * </ul>
 	 * 
 	 * @param object 被包装的对象
-	 * @param ignoreNullValue 是否忽略{@code null} 值
+	 * @param jsonConfig JSON选项
 	 * @return 包装后的值,null表示此值需被忽略
 	 */
-	public static Object wrap(Object object, boolean ignoreNullValue) {
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public static Object wrap(Object object, JSONConfig jsonConfig) {
 		if (object == null) {
-			return ignoreNullValue ? null : JSONNull.NULL;
+			return jsonConfig.isIgnoreNullValue() ? null : JSONNull.NULL;
 		}
 		if (object instanceof JSON //
 				|| JSONNull.NULL.equals(object) //
@@ -612,15 +620,28 @@ public final class JSONUtil {
 		) {
 			return object;
 		}
+		
+		// 自定义序列化
+		final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(object.getClass());
+		if(null != serializer) {
+			final Type jsonType = TypeUtil.getTypeArgument(serializer.getClass());
+			if(null != jsonType) {
+				if(serializer instanceof JSONObjectSerializer) {
+					serializer.serialize(new JSONObject(jsonConfig), object);
+				} else if(serializer instanceof JSONArraySerializer) {
+					serializer.serialize(new JSONArray(jsonConfig), object);
+				}
+			}
+		}
 
 		try {
 			// JSONArray
 			if (object instanceof Iterable || ArrayUtil.isArray(object)) {
-				return new JSONArray(object, ignoreNullValue);
+				return new JSONArray(object, jsonConfig);
 			}
 			// JSONObject
 			if (object instanceof Map) {
-				return new JSONObject(object, ignoreNullValue);
+				return new JSONObject(object, jsonConfig);
 			}
 
 			// 日期类型原样保存,便于格式化
@@ -636,15 +657,12 @@ public final class JSONUtil {
 			}
 
 			// Java内部类不做转换
-			final Class<?> objectClass = object.getClass();
-			final Package objectPackage = objectClass.getPackage();
-			final String objectPackageName = objectPackage != null ? objectPackage.getName() : "";
-			if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || objectClass.getClassLoader() == null) {
+			if(ClassUtil.isJdkClass(object.getClass())) {
 				return object.toString();
 			}
 
 			// 默认按照JSONObject对待
-			return new JSONObject(object, ignoreNullValue);
+			return new JSONObject(object, jsonConfig);
 		} catch (Exception exception) {
 			return null;
 		}
@@ -727,6 +745,42 @@ public final class JSONUtil {
 	public static JSONObject xmlToJson(String xml) {
 		return XML.toJSONObject(xml);
 	}
+	
+	/**
+	 * 加入自定义的序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 序列化器实现
+	 * @see GlobalSerializeMapping#put(Type, JSONArraySerializer)
+	 * @since 4.6.5
+	 */
+	public static void putSerializer(Type type, JSONArraySerializer<?> serializer) {
+		GlobalSerializeMapping.put(type, serializer);
+	}
+	
+	/**
+	 * 加入自定义的序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 序列化器实现
+	 * @see GlobalSerializeMapping#put(Type, JSONObjectSerializer)
+	 * @since 4.6.5
+	 */
+	public static void putSerializer(Type type, JSONObjectSerializer<?> serializer) {
+		GlobalSerializeMapping.put(type, serializer);
+	}
+	
+	/**
+	 * 加入自定义的反序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 反序列化器实现
+	 * @see GlobalSerializeMapping#put(Type, JSONDeserializer)
+	 * @since 4.6.5
+	 */
+	public static void putDeserializer(Type type, JSONDeserializer<?> deserializer) {
+		GlobalSerializeMapping.put(type, deserializer);
+	}
 
 	// --------------------------------------------------------------------------------------------- Private method start
 	/**

+ 90 - 0
hutool-json/src/main/java/cn/hutool/json/serialize/GlobalSerializeMapping.java

@@ -0,0 +1,90 @@
+package cn.hutool.json.serialize;
+
+import java.lang.reflect.Type;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import cn.hutool.json.JSON;
+
+/**
+ * 全局的序列化和反序列化器映射<br>
+ * 在JSON和Java对象转换过程中,优先使用注册于此处的自定义转换
+ * 
+ * @author Looly
+ *
+ */
+public class GlobalSerializeMapping {
+	
+	private static Map<Type, JSONSerializer<? extends JSON, ?>> serializerMap;
+	private static Map<Type, JSONDeserializer<?>> deserializerMap;
+	
+	/**
+	 * 加入自定义的序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 序列化器实现
+	 */
+	public static void put(Type type, JSONArraySerializer<?> serializer) {
+		putInternal(type, serializer);
+	}
+	
+	/**
+	 * 加入自定义的序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 序列化器实现
+	 */
+	public static void put(Type type, JSONObjectSerializer<?> serializer) {
+		putInternal(type, serializer);
+	}
+
+	/**
+	 * 加入自定义的序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 序列化器实现
+	 */
+	synchronized private static void putInternal(Type type, JSONSerializer<? extends JSON, ?> serializer) {
+		if(null == serializerMap) {
+			serializerMap = new ConcurrentHashMap<>();
+		}
+		serializerMap.put(type, serializer);
+	}
+	
+	/**
+	 * 加入自定义的反序列化器
+	 * 
+	 * @param type 对象类型
+	 * @param serializer 反序列化器实现
+	 */
+	synchronized public static void put(Type type, JSONDeserializer<?> deserializer) {
+		if(null == deserializerMap) {
+			deserializerMap = new ConcurrentHashMap<>();
+		}
+		deserializerMap.put(type, deserializer);
+	}
+	
+	/**
+	 * 获取自定义的序列化器,如果未定义返回{@code null}
+	 * @param type 类型
+	 * @return 自定义的序列化器或者{@code null}
+	 */
+	public static JSONSerializer<? extends JSON, ?> getSerializer(Type type){
+		if(null == serializerMap) {
+			return null;
+		}
+		return serializerMap.get(type);
+	}
+	
+	/**
+	 * 获取自定义的反序列化器,如果未定义返回{@code null}
+	 * @param type 类型
+	 * @return 自定义的反序列化器或者{@code null}
+	 */
+	public static JSONDeserializer<?> getDeserializer(Type type){
+		if(null == deserializerMap) {
+			return null;
+		}
+		return deserializerMap.get(type);
+	}
+}

+ 12 - 0
hutool-json/src/main/java/cn/hutool/json/serialize/JSONArraySerializer.java

@@ -0,0 +1,12 @@
+package cn.hutool.json.serialize;
+
+import cn.hutool.json.JSONArray;
+
+/**
+ * JSON列表的序列化接口,用于将特定对象序列化为{@link JSONArray}
+ * 
+ * @param <V> 对象类型
+ * 
+ * @author Looly
+ */
+public interface JSONArraySerializer<V> extends JSONSerializer<JSONArray, V>{}

+ 21 - 0
hutool-json/src/main/java/cn/hutool/json/serialize/JSONDeserializer.java

@@ -0,0 +1,21 @@
+package cn.hutool.json.serialize;
+
+import cn.hutool.json.JSON;
+
+/**
+ * JSON反序列话自定义实现类
+ * 
+ * @author Looly
+ *
+ * @param <T> 反序列化后的类型
+ */
+public interface JSONDeserializer<T> {
+	
+	/**
+	 * 反序列化,通过实现此方法,自定义实现JSON转换为指定类型的逻辑
+	 * 
+	 * @param json {@link JSON}
+	 * @return 目标对象
+	 */
+	T deserialize(JSON json);
+}

+ 11 - 0
hutool-json/src/main/java/cn/hutool/json/serialize/JSONObjectSerializer.java

@@ -0,0 +1,11 @@
+package cn.hutool.json.serialize;
+
+import cn.hutool.json.JSONObject;
+
+/**
+ * 对象的序列化接口,用于将特定对象序列化为{@link JSONObject}
+ * @param <V> 对象类型
+ * 
+ * @author Looly
+ */
+public interface JSONObjectSerializer<V> extends JSONSerializer<JSONObject, V>{}

+ 22 - 0
hutool-json/src/main/java/cn/hutool/json/serialize/JSONSerializer.java

@@ -0,0 +1,22 @@
+package cn.hutool.json.serialize;
+
+import cn.hutool.json.JSON;
+
+/**
+ * 序列化接口,通过实现此接口,实现自定义的对象转换为JSON的操作
+ * 
+ * @param <T> JSON类型,可以是JSONObject或者JSONArray
+ * @param <V> 对象类型
+ * @author Looly
+ */
+public interface JSONSerializer<T extends JSON, V> {
+
+	/**
+	 * 序列化实现,通过实现此方法,将指定类型的对象转换为{@link JSON}对象<br>
+	 * 转换后的对象可以为JSONObject也可以为JSONArray,首先new一个空的JSON,然后将需要的数据字段put到JSON对象中去即可。
+	 * 
+	 * @param json JSON,可以为JSONObject或者JSONArray
+	 * @param bean 指定类型对象
+	 */
+	void serialize(T json, V bean);
+}

+ 7 - 0
hutool-json/src/main/java/cn/hutool/json/serialize/package-info.java

@@ -0,0 +1,7 @@
+/**
+ * JSON自定义序列化和反序列化接口和默认实现
+ * 
+ * @author Looly
+ *
+ */
+package cn.hutool.json.serialize;

+ 55 - 0
hutool-json/src/test/java/cn/hutool/json/CustomSerializeTest.java

@@ -0,0 +1,55 @@
+package cn.hutool.json;
+
+import java.util.Date;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import cn.hutool.json.serialize.JSONDeserializer;
+import cn.hutool.json.serialize.JSONObjectSerializer;
+import lombok.ToString;
+
+public class CustomSerializeTest {
+
+	@Test
+	public void serializeTest() {
+		JSONUtil.putSerializer(CustomBean.class, new JSONObjectSerializer<CustomBean>() {
+
+			@Override
+			public void serialize(JSONObject json, CustomBean bean) {
+				json.put("customName", bean.name);
+			}
+		});
+		
+		CustomBean customBean = new CustomBean();
+		customBean.name = "testName";
+		
+		JSONObject obj = JSONUtil.parseObj(customBean);
+		Assert.assertEquals("testName", obj.getStr("customName"));
+	}
+	
+	@Test
+	public void deserializeTest() {
+		JSONUtil.putDeserializer(CustomBean.class, new JSONDeserializer<CustomBean>() {
+
+			@Override
+			public CustomBean deserialize(JSON json) {
+				CustomBean customBean = new CustomBean();
+				customBean.name = ((JSONObject)json).getStr("customName");
+				return customBean;
+			}
+
+		});
+		
+		String jsonStr = "{\"customName\":\"testName\"}";
+		CustomBean bean = JSONUtil.parseObj(jsonStr).toBean(CustomBean.class);
+		Assert.assertEquals("testName", bean.name);
+	}
+
+	@ToString
+	public static class CustomBean {
+		public String name;
+		public String b;
+		public Date date;
+	}
+}

+ 1 - 1
hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java

@@ -351,7 +351,7 @@ public class JSONObjectTest {
 		Assert.assertEquals("yyb\\nbbb", jsonObject.getStrEscaped("name"));
 		
 		String bbb = jsonObject.getStr("bbb", "defaultBBB");
-		Console.log(bbb);
+		Assert.assertEquals("defaultBBB", bbb);
 	}
 
 	public static enum TestEnum {