add ObjectMapper

This commit is contained in:
Looly 2022-04-18 21:31:02 +08:00
parent 1c273c7d4c
commit 571d76f578
4 changed files with 247 additions and 203 deletions

View File

@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
# 5.8.0.M4 (2022-04-17)
# 5.8.0.M4 (2022-04-18)
### ❌不兼容特性
* 【json 】 【可能兼容问题】JSONArray删除部分构造
@ -14,6 +14,7 @@
* 【json 】 JSON新增在解析时的过滤方法issue#I52O85@Gitee
* 【core 】 添加ArrayUtil.distinct、CollUtil.distinct重载issue#2256@Github
* 【core 】 添加TransMap、FuncMap、ReferenceConcurrentMap、WeakConcurrentMap
* 【json 】 添加ObjectMapper
### 🐞Bug修复
* 【core 】 修复StrUtil.firstNonX非static问题issue#2257@Github

View File

@ -1,19 +1,13 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.collection.ArrayIter;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.lang.mutable.MutablePair;
import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ArrayUtil;
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;
import cn.hutool.json.serialize.JSONWriter;
import java.io.StringWriter;
@ -171,7 +165,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
*/
public JSONArray(Object object, JSONConfig jsonConfig, Filter<Mutable<Object>> filter) throws JSONException {
this(DEFAULT_CAPACITY, jsonConfig);
init(object, filter);
ObjectMapper.of(object).map(this, filter);
}
// endregion
@ -588,7 +582,6 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
clone.rawList = ObjectUtil.clone(this.rawList);
return clone;
}
// ------------------------------------------------------------------------------------------------- Private method start
/**
* 原始添加添加的对象不做任何处理
@ -612,71 +605,4 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
}
return this.rawList.add(obj);
}
/**
* 初始化
*
* @param source 数组或集合或JSON数组字符串
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤
* @throws JSONException 非数组或集合
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private void init(Object source, Filter<Mutable<Object>> filter) 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字符串
initFromStr((CharSequence) source, filter);
} else if (source instanceof JSONTokener) {
initFromTokener((JSONTokener) source, filter);
} else {
Iterator<?> iter;
if (ArrayUtil.isArray(source)) {// 数组
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.");
}
Object next;
while (iter.hasNext()) {
next = iter.next();
// 检查循环引用
if (next != source) {
this.addRaw(JSONUtil.wrap(next, this.config), filter);
}
}
}
}
/**
* 初始化
*
* @param source JSON字符串
*/
private void initFromStr(CharSequence source, Filter<Mutable<Object>> filter) {
if (null != source) {
initFromTokener(new JSONTokener(StrUtil.trim(source), this.config), filter);
}
}
/**
* 初始化
*
* @param x {@link JSONTokener}
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤
*/
private void initFromTokener(JSONTokener x, Filter<Mutable<Object>> filter) {
JSONParser.of(x).parseTo(this, filter);
}
// ------------------------------------------------------------------------------------------------- Private method end
}

View File

@ -1,9 +1,7 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.mutable.MutablePair;
import cn.hutool.core.map.CaseInsensitiveMap;
@ -12,10 +10,6 @@ import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.util.ArrayUtil;
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;
import cn.hutool.json.serialize.JSONWriter;
import java.io.StringWriter;
@ -24,9 +18,7 @@ import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
import java.util.ResourceBundle;
/**
* JSON对象<br>
@ -216,7 +208,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
*/
public JSONObject(Object source, JSONConfig config, Filter<MutablePair<String, Object>> filter) {
this(DEFAULT_CAPACITY, config);
init(source, filter);
ObjectMapper.of(source).map(this, filter);
}
/**
@ -230,26 +222,26 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* KEY或VALUE任意一个为null则不加入字段不存在也不加入<br>
* 若names列表为空则字段全部加入
*
* @param obj 包含需要字段的Bean对象或者Map对象
* @param names 需要构建JSONObject的字段名列表
* @param source 包含需要字段的Bean对象或者Map对象
* @param names 需要构建JSONObject的字段名列表
*/
public JSONObject(Object obj, String... names) {
public JSONObject(Object source, String... names) {
this();
if (ArrayUtil.isEmpty(names)) {
init(obj, null);
ObjectMapper.of(source).map(this, null);
return;
}
if (obj instanceof Map) {
if (source instanceof Map) {
Object value;
for (String name : names) {
value = ((Map<?, ?>) obj).get(name);
value = ((Map<?, ?>) source).get(name);
this.putOnce(name, value);
}
} else {
for (String name : names) {
try {
this.putOpt(name, ReflectUtil.getFieldValue(obj, name));
this.putOpt(name, ReflectUtil.getFieldValue(source, name));
} catch (Exception ignore) {
// ignore
}
@ -598,115 +590,4 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
clone.config = this.config;
return clone;
}
// ------------------------------------------------------------------------------------------------- Private method start
/**
* Bean对象转Map
*
* @param bean Bean对象
*/
private void populateMap(Object bean) {
BeanUtil.beanToMap(bean, this, InternalJSONUtil.toCopyOptions(config));
}
/**
* 初始化
* <ol>
* <li>value为Map将键值对加入JSON对象</li>
* <li>value为JSON字符串CharSequence使用JSONTokener解析</li>
* <li>value为JSONTokener直接解析</li>
* <li>value为普通JavaBean如果为普通的JavaBean调用其getters方法getXXX或者isXXX获得值加入到JSON对象例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* </ol>
*
* @param source JavaBean或者Map对象或者String
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private void init(Object source, Filter<MutablePair<String, Object>> filter) {
if (null == source) {
return;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (serializer instanceof JSONObjectSerializer) {
serializer.serialize(this, source);
return;
}
if (ArrayUtil.isArray(source) || source instanceof JSONArray) {
// 不支持集合类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
if (source instanceof Map) {
// Map
for (final Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
this.set(Convert.toStr(e.getKey()), e.getValue(), filter, false);
}
} else if (source instanceof Map.Entry) {
final Map.Entry entry = (Map.Entry) source;
this.set(Convert.toStr(entry.getKey()), entry.getValue(), filter, false);
} else if (source instanceof CharSequence) {
// 可能为JSON字符串
initFromStr((CharSequence) source, filter);
} else if (source instanceof JSONTokener) {
// JSONTokener
initFromTokener((JSONTokener) source, filter);
} else if (source instanceof ResourceBundle) {
// JSONTokener
initFromResourceBundle((ResourceBundle) source, filter);
} else if (BeanUtil.isReadableBean(source.getClass())) {
// 普通Bean过滤器无效
this.populateMap(source);
} else {
// 不支持对象类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
}
/**
* 初始化
*
* @param bundle ResourceBundle
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
* @since 5.3.1
*/
private void initFromResourceBundle(ResourceBundle bundle, Filter<MutablePair<String, Object>> filter) {
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
if (key != null) {
InternalJSONUtil.propertyPut(this, key, bundle.getString(key), filter);
}
}
}
/**
* 初始化可以判断字符串为JSON或者XML
*
* @param source JSON字符串
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
*/
private void initFromStr(CharSequence source, Filter<MutablePair<String, Object>> filter) {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
XML.toJSONObject(this, jsonStr, false);
return;
}
initFromTokener(new JSONTokener(StrUtil.trim(source), this.config), filter);
}
/**
* 初始化
*
* @param x JSONTokener
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作
*/
private void initFromTokener(JSONTokener x, Filter<MutablePair<String, Object>> filter) {
JSONParser.of(x).parseTo(this, filter);
}
// ------------------------------------------------------------------------------------------------- Private method end
}

View File

@ -0,0 +1,236 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ArrayIter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutablePair;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONObjectSerializer;
import cn.hutool.json.serialize.JSONSerializer;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
/**
* 对象和JSON映射器用于转换对象为JSON支持
* <ul>
* <li>Map JSONObject将键值对加入JSON对象</li>
* <li>Map.Entry JSONObject</li>
* <li>CharSequence JSONObject使用JSONTokener解析</li>
* <li>JSONTokener JSONObject直接解析</li>
* <li>ResourceBundle JSONObject</li>
* <li>Bean JSONObject调用其getters方法getXXX或者isXXX获得值加入到JSON对象例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* </ul>
*
* @author looly
* @since 5.8.0
*/
public class ObjectMapper {
/**
* 创建ObjectMapper
*
* @param source 来源对象
* @return ObjectMapper
*/
public static ObjectMapper of(Object source) {
return new ObjectMapper(source);
}
private final Object source;
/**
* 构造
*
* @param source 来源对象
*/
public ObjectMapper(Object source) {
this.source = source;
}
/**
* 将给定对象转换为{@link JSONObject}
*
* @param jsonObject 目标{@link JSONObject}
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void map(JSONObject jsonObject, Filter<MutablePair<String, Object>> filter) {
final Object source = this.source;
if (null == source) {
return;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (serializer instanceof JSONObjectSerializer) {
serializer.serialize(jsonObject, source);
return;
}
if (ArrayUtil.isArray(source) || source instanceof JSONArray) {
// 不支持集合类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
if (source instanceof Map) {
// Map
for (final Map.Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
jsonObject.set(Convert.toStr(e.getKey()), e.getValue(), filter, false);
}
} else if (source instanceof Map.Entry) {
final Map.Entry entry = (Map.Entry) source;
jsonObject.set(Convert.toStr(entry.getKey()), entry.getValue(), filter, false);
} else if (source instanceof CharSequence) {
// 可能为JSON字符串
mapFromStr((CharSequence) source, jsonObject, filter);
} else if (source instanceof JSONTokener) {
// JSONTokener
mapFromTokener((JSONTokener) source, jsonObject, filter);
} else if (source instanceof ResourceBundle) {
// JSONTokener
mapFromResourceBundle((ResourceBundle) source, jsonObject, filter);
} else if (BeanUtil.isReadableBean(source.getClass())) {
// 普通Bean
// TODO 过滤器对Bean无效需补充
mapFromBean(source, jsonObject);
} else {
// 不支持对象类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
}
/**
* 初始化
*
* @param jsonArray 目标{@link JSONArray}
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤
* @throws JSONException 非数组或集合
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void map(JSONArray jsonArray, Filter<Mutable<Object>> filter) throws JSONException {
final Object source = this.source;
if (null == source) {
return;
}
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (null != serializer && JSONArray.class.equals(TypeUtil.getTypeArgument(serializer.getClass()))) {
// 自定义序列化
serializer.serialize(jsonArray, source);
} else if (source instanceof CharSequence) {
// JSON字符串
mapFromStr((CharSequence) source, jsonArray, filter);
} else if (source instanceof JSONTokener) {
mapFromTokener((JSONTokener) source, jsonArray, filter);
} else {
Iterator<?> iter;
if (ArrayUtil.isArray(source)) {// 数组
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.");
}
final JSONConfig config = jsonArray.getConfig();
Object next;
while (iter.hasNext()) {
next = iter.next();
// 检查循环引用
if (next != source) {
jsonArray.addRaw(JSONUtil.wrap(next, config), filter);
}
}
}
}
/**
* {@link ResourceBundle}转换
*
* @param bundle ResourceBundle
* @param jsonObject {@link JSONObject}
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
* @since 5.3.1
*/
private static void mapFromResourceBundle(ResourceBundle bundle, JSONObject jsonObject, Filter<MutablePair<String, Object>> filter) {
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
if (key != null) {
InternalJSONUtil.propertyPut(jsonObject, key, bundle.getString(key), filter);
}
}
}
/**
* 从字符串转换
*
* @param source JSON字符串
* @param jsonObject {@link JSONObject}
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
*/
private static void mapFromStr(CharSequence source, JSONObject jsonObject, Filter<MutablePair<String, Object>> filter) {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
XML.toJSONObject(jsonObject, jsonStr, false);
return;
}
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonObject.getConfig()), jsonObject, filter);
}
/**
* 初始化
*
* @param source JSON字符串
* @param jsonArray {@link JSONArray}
* @param filter 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤
*/
private void mapFromStr(CharSequence source, JSONArray jsonArray, Filter<Mutable<Object>> filter) {
if (null != source) {
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonArray.getConfig()), jsonArray, filter);
}
}
/**
* {@link JSONTokener}转换
*
* @param x JSONTokener
* @param jsonObject {@link JSONObject}
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作
*/
private static void mapFromTokener(JSONTokener x, JSONObject jsonObject, Filter<MutablePair<String, Object>> filter) {
JSONParser.of(x).parseTo(jsonObject, filter);
}
/**
* 初始化
*
* @param x {@link JSONTokener}
* @param jsonArray {@link JSONArray}
* @param filter 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤
*/
private static void mapFromTokener(JSONTokener x, JSONArray jsonArray, Filter<Mutable<Object>> filter) {
JSONParser.of(x).parseTo(jsonArray, filter);
}
/**
* 从Bean转换
*
* @param bean Bean对象
* @param jsonObject {@link JSONObject}
*/
private static void mapFromBean(Object bean, JSONObject jsonObject) {
BeanUtil.beanToMap(bean, jsonObject, InternalJSONUtil.toCopyOptions(jsonObject.getConfig()));
}
}