This commit is contained in:
Looly 2020-04-17 15:54:43 +08:00
parent 94c824e03d
commit 7e8096a75c
6 changed files with 242 additions and 144 deletions

View File

@ -13,6 +13,7 @@
* 【core 】 增加XmlUtil.setNamespaceAwaregetByPath支持UniversalNamespaceCache
* 【core 】 增加XmlUtil.setNamespaceAwaregetByPath支持UniversalNamespaceCache
* 【aop 】 增加Spring-cglib支持改为SPI实现
* 【json 】 增加JSONUtil.parseXXX增加JSONConfig参数
### Bug修复
* 【json 】 修复解析JSON字符串时配置无法传递问题

View File

@ -188,8 +188,7 @@ final class InternalJSONUtil {
* @return JSONObject
*/
protected static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value) {
String keyStr = Convert.toStr(key);
String[] path = StrUtil.split(keyStr, StrUtil.DOT);
final String[] path = StrUtil.split(Convert.toStr(key), StrUtil.DOT);
int last = path.length - 1;
JSONObject target = jsonObject;
for (int i = 0; i < last; i += 1) {

View File

@ -1,13 +1,13 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.lang.TypeReference;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.lang.TypeReference;
/**
* JSON接口
*

View File

@ -23,8 +23,10 @@ import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
/**
@ -40,15 +42,22 @@ import java.util.Set;
public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object> {
private static final long serialVersionUID = -330220388580734346L;
/** 默认初始大小 */
public static final int DEFAULT_CAPACITY = 16;
/**
* 默认初始大小
*/
public static final int DEFAULT_CAPACITY = MapUtil.DEFAULT_INITIAL_CAPACITY;
/** JSON的KV持有Map */
/**
* JSON的KV持有Map
*/
private final Map<String, Object> rawHashMap;
/** 配置项 */
/**
* 配置项
*/
private final JSONConfig config;
// -------------------------------------------------------------------------------------------------------------------- Constructor start
/**
* 构造初始容量为 {@link #DEFAULT_CAPACITY}KEY无序
*/
@ -107,7 +116,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
* @since 4.1.19
*/
public JSONObject(int capacity, JSONConfig config) {
if(null == config){
if (null == config) {
config = JSONConfig.create();
}
if (config.isIgnoreCase()) {
@ -179,7 +188,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
* <li>value为JSONTokener直接解析</li>
* <li>value为普通JavaBean如果为普通的JavaBean调用其getters方法getXXX或者isXXX获得值加入到JSON对象例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* </ol>
*
* <p>
* 如果给定值为Map将键值对加入JSON对象;<br>
* 如果为普通的JavaBean调用其getters方法getXXX或者isXXX获得值加入到JSON对象<br>
* 例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"
@ -200,7 +209,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
* 1. 若obj为Map则获取name列表对应键值对
* 2. 若obj为普通Bean使用反射方式获取字段名和字段值
* </pre>
*
* <p>
* KEY或VALUE任意一个为null则不加入字段不存在也不加入<br>
* 若names列表为空则字段全部加入
*
@ -236,7 +245,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
*
* @param source 以大括号 {} 包围的字符串其中KEY和VALUE使用 : 分隔每个键值对使用逗号分隔
* @param isOrder 是否有序
* @exception JSONException JSON字符串语法错误
* @throws JSONException JSON字符串语法错误
* @since 4.2.2
*/
public JSONObject(CharSequence source, boolean isOrder) throws JSONException {
@ -559,6 +568,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
}
// ------------------------------------------------------------------------------------------------- Private method start
/**
* 将JSON内容写入Writer
*
@ -664,7 +674,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
}
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if(serializer instanceof JSONObjectSerializer) {
if (serializer instanceof JSONObjectSerializer) {
// 自定义序列化
serializer.serialize(this, source);
} else if (source instanceof Map) {
@ -678,7 +688,10 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
} else if (source instanceof JSONTokener) {
// JSONTokener
init((JSONTokener) source);
} else if(BeanUtil.isReadableBean(source.getClass())){
} else if (source instanceof ResourceBundle) {
// JSONTokener
init((ResourceBundle) source);
} else if (BeanUtil.isReadableBean(source.getClass())) {
// 普通Bean
this.populateMap(source);
}
@ -687,9 +700,30 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
/**
* 初始化
*
* @param bundle ResourceBundle
* @since 5.3.1
*/
private void init(ResourceBundle bundle) {
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
if (key != null) {
InternalJSONUtil.propertyPut(this, key, bundle.getString(key));
}
}
}
/**
* 初始化可以判断字符串为JSON或者XML
*
* @param source JSON字符串
*/
private void init(CharSequence source) {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
XML.toJSONObject(this, jsonStr, false);
}
init(new JSONTokener(StrUtil.trim(source), this.config));
}

View File

@ -23,9 +23,8 @@ import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@ -100,6 +99,19 @@ public final class JSONUtil {
return new JSONObject(obj);
}
/**
* JSON字符串转JSONObject对象<br>
* 此方法会忽略空值但是对JSON字符串不影响
*
* @param obj Bean对象或者Map
* @param config JSON配置
* @return JSONObject
* @since 5.3.1
*/
public static JSONObject parseObj(Object obj, JSONConfig config) {
return new JSONObject(obj, config);
}
/**
* JSON字符串转JSONObject对象
*
@ -146,6 +158,18 @@ public final class JSONUtil {
return new JSONArray(arrayOrCollection);
}
/**
* JSON字符串转JSONArray
*
* @param arrayOrCollection 数组或集合对象
* @param config JSON配置
* @return JSONArray
* @since 5.3.1
*/
public static JSONArray parseArray(Object arrayOrCollection, JSONConfig config) {
return new JSONArray(arrayOrCollection, config);
}
/**
* JSON字符串转JSONArray
*
@ -169,6 +193,22 @@ public final class JSONUtil {
* @return JSON
*/
public static JSON parse(Object obj) {
return parse(obj, JSONConfig.create());
}
/**
* 转换对象为JSON<br>
* 支持的对象<br>
* String: 转换为相应的对象<br>
* ArrayIterableIterator转换为JSONArray<br>
* Bean对象转为JSONObject
*
* @param obj 对象
* @param config JSON配置
* @return JSON
* @since 5.3.1
*/
public static JSON parse(Object obj, JSONConfig config) {
if (null == obj) {
return null;
}
@ -176,17 +216,13 @@ public final class JSONUtil {
JSON json;
if (obj instanceof JSON) {
json = (JSON) obj;
} else if (obj instanceof String) {
String jsonStr = ((String) obj).trim();
if (jsonStr.startsWith("[")) {
json = parseArray(jsonStr);
} else {
json = parseObj(jsonStr);
}
} else if (obj instanceof Collection || obj.getClass().isArray()) {// 列表
json = new JSONArray(obj);
} else if (obj instanceof CharSequence) {
final String jsonStr = StrUtil.trim((CharSequence) obj);
json = StrUtil.startWith(jsonStr, '[') ? parseArray(jsonStr) : parseObj(jsonStr);
} else if (obj instanceof Iterable || obj instanceof Iterator || ArrayUtil.isArray(obj)) {// 列表
json = new JSONArray(obj, config);
} else {// 对象
json = new JSONObject(obj);
json = new JSONObject(obj, config);
}
return json;
@ -206,8 +242,10 @@ public final class JSONUtil {
* Map转化为JSONObject
*
* @param map {@link Map}
* @return JSONObject
* @return JSONObjec
* @deprecated 请直接使用 {@link #parseObj(Object)}
*/
@Deprecated
public static JSONObject parseFromMap(Map<?, ?> map) {
return new JSONObject(map);
}
@ -217,17 +255,11 @@ public final class JSONUtil {
*
* @param bundle ResourceBundle文件
* @return JSONObject
* @deprecated 请直接使用 {@link #parseObj(Object)}
*/
@Deprecated
public static JSONObject parseFromResourceBundle(ResourceBundle bundle) {
JSONObject jsonObject = new JSONObject();
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
if (key != null) {
InternalJSONUtil.propertyPut(jsonObject, key, bundle.getString(key));
}
}
return jsonObject;
return new JSONObject(bundle);
}
// -------------------------------------------------------------------- Pause end

View File

@ -14,33 +14,98 @@ import java.util.Iterator;
*/
public class XML {
/** The Character '&amp;'. */
/**
* The Character '&amp;'.
*/
public static final Character AMP = CharUtil.AMP;
/** The Character '''. */
/**
* The Character '''.
*/
public static final Character APOS = CharUtil.SINGLE_QUOTE;
/** The Character '!'. */
/**
* The Character '!'.
*/
public static final Character BANG = '!';
/** The Character '='. */
/**
* The Character '='.
*/
public static final Character EQ = '=';
/** The Character '&gt;'. */
/**
* The Character '&gt;'.
*/
public static final Character GT = '>';
/** The Character '&lt;'. */
/**
* The Character '&lt;'.
*/
public static final Character LT = '<';
/** The Character '?'. */
/**
* The Character '?'.
*/
public static final Character QUEST = '?';
/** The Character '"'. */
/**
* The Character '"'.
*/
public static final Character QUOT = CharUtil.DOUBLE_QUOTES;
/** The Character '/'. */
/**
* The Character '/'.
*/
public static final Character SLASH = CharUtil.SLASH;
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</code> are ignored.
*
* @param string The source string.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string) throws JSONException {
return toJSONObject(string, false);
}
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</code> are ignored.
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to numbers but will instead be the exact value as seen in the XML document.
*
* @param string The source string.
* @param keepStrings If true, then values will not be coerced into boolean or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
return toJSONObject(new JSONObject(), string, keepStrings);
}
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
*
* @param jo JSONObject
* @param string XML字符串
* @param keepStrings If true, then values will not be coerced into boolean or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
* @since 5.3.1
*/
public static JSONObject toJSONObject(JSONObject jo, String string, boolean keepStrings) throws JSONException {
XMLTokener x = new XMLTokener(string, jo.getConfig());
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, keepStrings);
}
return jo;
}
/**
* Scan the content following the named tag, attaching it to the context.
*
@ -135,7 +200,7 @@ public class XML {
tagName = (String) token;
token = null;
jsonobject = new JSONObject();
for (;;) {
for (; ; ) {
if (token == null) {
token = x.nextToken();
}
@ -169,7 +234,7 @@ public class XML {
} else if (token == GT) {
// Content, between <...> and </...>
for (;;) {
for (; ; ) {
token = x.nextContent();
if (token == null) {
if (tagName != null) {
@ -203,39 +268,6 @@ public class XML {
}
}
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</code> are ignored.
*
* @param string The source string.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string) throws JSONException {
return toJSONObject(string, false);
}
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]&gt;</code> are ignored.
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to numbers but will instead be the exact value as seen in the XML document.
*
* @param string The source string.
* @param keepStrings If true, then values will not be coerced into boolean or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(string, jo.getConfig());
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, keepStrings);
}
return jo;
}
/**
* 转换JSONObject为XML
* Convert a JSONObject into a well-formed, element-normal XML string.
@ -258,7 +290,7 @@ public class XML {
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toXml(Object object, String tagName) throws JSONException {
if(null == object) {
if (null == object) {
return null;
}