2019-03-13 19:45:12 +08:00

750 lines
21 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ruoyi.common.json;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.StringUtils;
/**
* 通用消息对象基于Map实现的可嵌套数据结构。 支持JSON数据结构。
*
* @author ruoyi
*/
public class JSONObject extends LinkedHashMap<String, Object>
{
private static final long serialVersionUID = 1L;
private static final Pattern arrayNamePattern = Pattern.compile("(\\w+)((\\[\\d+\\])+)");
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 数组结构。
*/
public static class JSONArray extends ArrayList<Object>
{
private static final long serialVersionUID = 1L;
public JSONArray()
{
super();
}
public JSONArray(int size)
{
super(size);
}
@Override
public String toString()
{
try
{
return JSON.marshal(this);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
@Override
public Object set(int index, Object element)
{
return super.set(index, transfer(element));
}
@Override
public boolean add(Object element)
{
return super.add(transfer(element));
}
@Override
public void add(int index, Object element)
{
super.add(index, transfer(element));
}
}
public JSONObject()
{
super();
}
public JSONObject(final JSONObject other)
{
super(other);
}
@Override
public String toString()
{
try
{
return JSON.marshal(this);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* 转换为紧凑格式的字符串。
*
* @return 返回本对象紧凑格式字符串。
*/
public String toCompactString()
{
try
{
return objectMapper.writeValueAsString(this);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* 获取指定字段的整数值。如果字段不存在或者无法转换为整数返回null。
*
* @param name 字段名,支持多级。
* @return 返回指定的整数值或者null。
*/
public Integer intValue(final String name)
{
return valueAsInt(value(name));
}
/**
* 获取指定字段的整数值。如果字段不存在或者无法转换为整数返回defaultValue。
*
* @param name 字段名,支持多级。
* @param defaultValue 查询失败时,返回的值。
* @return 返回指定的整数值或者defaultValue。
*/
public Integer intValue(final String name, final Integer defaultValue)
{
return StringUtils.nvl(intValue(name), defaultValue);
}
/**
* 获取指定字段的长整数值。如果字段不存在或者无法转换为长整数返回null。
*
* @param name 字段名,支持多级。
* @return 返回指定的长整数值或者null。
*/
public Long longValue(final String name)
{
return valueAsLong(value(name));
}
/**
* 获取指定字段的长整数值。如果字段不存在或者无法转换为长整数返回defaultValue。
*
* @param name 字段名,支持多级。
* @param defaultValue 查询失败时,返回的值。
* @return 返回指定的长整数值或者defaultValue。
*/
public Long longValue(final String name, final Long defaultValue)
{
return StringUtils.nvl(longValue(name), defaultValue);
}
/**
* 获取指定字段的布尔值。如果字段不存在或者无法转换为布尔型返回null。
*
* @param name 字段名,支持多级。
* @return 返回指定的布尔值或者null。
*/
public Boolean boolValue(final String name)
{
return valueAsBool(value(name));
}
/**
* 获取指定字段的布尔值。如果字段不存在或者无法转换为布尔型返回defaultValue。
*
* @param name 字段名,支持多级。
* @param defaultValue 查询失败时,返回的值。
* @return 返回指定的布尔值或者defaultValue。
*/
public Boolean boolValue(final String name, final Boolean defaultValue)
{
return StringUtils.nvl(boolValue(name), defaultValue);
}
/**
* 获取指定字段的字符串值。如果字段不存在返回null。
*
* @param name 字段名,支持多级。
* @return 返回指定的字符串值或者null。
*/
public String strValue(final String name)
{
return valueAsStr(value(name));
}
/**
* 获取指定字段的字符串值。如果字段不存在返回defaultValue。
*
* @param name 字段名,支持多级。
* @param defaultValue 查询失败时,返回的值。
* @return 返回指定的字符串值或者defaultValue。
*/
public String strValue(final String name, final String defaultValue)
{
return StringUtils.nvl(strValue(name), defaultValue);
}
/**
* 获取指定字段的值。
*
* @param name 字段名,支持多级,支持数组下标。
* @return 返回指定字段的值。
*/
public Object value(final String name)
{
final int indexDot = name.indexOf('.');
if (indexDot >= 0)
{
return obj(name.substring(0, indexDot)).value(name.substring(indexDot + 1));
}
else
{
final Matcher matcher = arrayNamePattern.matcher(name);
if (matcher.find())
{
return endArray(matcher.group(1), matcher.group(2), new EndArrayCallback<Object>()
{
@Override
public Object callback(JSONArray arr, int index)
{
return elementAt(arr, index);
}
});
}
else
{
return get(name);
}
}
}
/**
* 设置指定字段的值。
*
* @param name 字段名,支持多级,支持数组下标。
* @param value 字段值。
* @return 返回本对象。
*/
public JSONObject value(final String name, final Object value)
{
final int indexDot = name.indexOf('.');
if (indexDot >= 0)
{
obj(name.substring(0, indexDot)).value(name.substring(indexDot + 1), value);
}
else
{
final Matcher matcher = arrayNamePattern.matcher(name);
if (matcher.find())
{
endArray(matcher.group(1), matcher.group(2), new EndArrayCallback<Void>()
{
@Override
public Void callback(JSONArray arr, int index)
{
elementAt(arr, index, value);
return null;
}
});
}
else
{
set(name, value);
}
}
return this;
}
/**
* 获取对象非标量类型字段。返回的数据是一个结构体。当不存在指定对象时则为指定的名字创建一个空的MessageObject对象。
*
* @param name 字段名。不支持多级名字,支持数组下标。
* @return 返回指定的对象。如果对象不存在则为指定的名字创建一个空的MessageObject对象。
*/
public JSONObject obj(final String name)
{
final Matcher matcher = arrayNamePattern.matcher(name);
if (matcher.find())
{
return endArray(matcher.group(1), matcher.group(2), new EndArrayCallback<JSONObject>()
{
@Override
public JSONObject callback(JSONArray arr, int index)
{
return objAt(arr, index);
}
});
}
else
{
JSONObject obj = getObj(name);
if (obj == null)
{
obj = new JSONObject();
put(name, obj);
}
return obj;
}
}
/**
* 获取数组字段。将名字对应的对象以数组对象返回,当指定的字段不存在时,创建一个空的数组。
*
* @param name 字段名。不支持多级名字,不支持下标。
* @return 返回一个数组List
*/
public JSONArray arr(final String name)
{
JSONArray arr = getArr(name);
if (arr == null)
{
arr = new JSONArray();
put(name, arr);
}
return arr;
}
/**
* 获取对象(非标量类型)字段。返回的数据是一个结构体。
*
* @param name 字段名。
* @return 返回指定的对象字段。
*/
public JSONObject getObj(final String name)
{
return (JSONObject) get(name);
}
/**
* 获取数组类型字段。
*
* @param name 字段名。
* @return 返回数组类型字段。
*/
public JSONArray getArr(final String name)
{
return (JSONArray) get(name);
}
/**
* 返回字段整数值。如果不存在返回null。
*
* @param name 字段名。
* @return 返回指定字段整数值。
*/
public Integer getInt(final String name)
{
return valueAsInt(get(name));
}
/**
* 返回字段整数值。如果不存在返回defaultValue。
*
* @param name 字段名。
* @param defaultValue 字段不存在时,返回的值。
* @return 返回指定字段整数值。
*/
public Integer getInt(final String name, Integer defaultValue)
{
return StringUtils.nvl(getInt(name), defaultValue);
}
/**
* 返回字段长整数值。如果不存在返回null。
*
* @param name 字段名。
* @return 返回指定字段长整数值。
*/
public Long getLong(final String name)
{
return valueAsLong(get(name));
}
/**
* 返回字段长整数值。如果不存在返回defaultValue。
*
* @param name 字段名。
* @param defaultValue 字段不存在时,返回的值。
* @return 返回指定字段长整数值。
*/
public Long getLong(final String name, Long defaultValue)
{
return StringUtils.nvl(getLong(name), defaultValue);
}
/**
* 返回字段字符串值。如果不存在返回null。
*
* @param name 字段名。
* @return 返回指定字段字符串值。
*/
public String getStr(final String name)
{
return valueAsStr(get(name));
}
/**
* 返回字段字符串值。如果不存在返回defaultValue。
*
* @param name 字段名。
* @param defaultValue 字段不存在时,返回的值。
* @return 返回指定字段字符串值。
*/
public String getStr(final String name, final String defaultValue)
{
return StringUtils.nvl(getStr(name), defaultValue);
}
/**
* 字段值按照布尔类型返回。如果不存在返回null。
*
* @param name 字段名。
* @return 字段值。
*/
public Boolean getBool(final String name)
{
return valueAsBool(get(name));
}
/**
* 字段值按照布尔类型返回。如果不存在返回defaultValue。
*
* @param name 字段名。
* @param defaultValue 字段不存在时,返回的值。
* @return 字段值。
*/
public Boolean getBool(final String name, final Boolean defaultValue)
{
return StringUtils.nvl(getBool(name), defaultValue);
}
/**
* 设置字段值
*
* @param name 字段名
* @param value 字段值标量数字、字符串、布尔型结构体MessageObject。 如果是Map类型同时非MessageObject类型则自动转换为MessageObject类型再存入
* 此时再修改Map中的数据将不会体现到本对象中
* @return 返回本对象
*/
public JSONObject set(final String name, final Object value)
{
put(name, value);
return this;
}
/**
* 将本对象转换为Java Bean。
*
* @param beanClass Java Bean的类对象。
* @return 返回转换后的Java Bean。
*/
public <T> T asBean(Class<T> beanClass)
{
try
{
return JSON.unmarshal(JSON.marshal(this), beanClass);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* 重载基类的方法。如果 value 是 Map 类型,但不是 MessageObject 类型,则创建一个包含内容等同于原 Map 的 MessageObject 作为 value注意此后再更改 Map 的内容,将不会反映到
* MessageObject 中)。 重载此方法的目的是为了使JSON能够正确地解析为MessageObject对象。不建议直接调用此方法请使用 set(name, value)方法设置字段值。
*/
@Override
public Object put(String key, Object value)
{
return super.put(key, transfer(value));
}
public static Integer valueAsInt(Object value)
{
if (value instanceof Integer)
{
return (Integer) value;
}
else if (value instanceof Number)
{
return ((Number) value).intValue();
}
else if (value instanceof String)
{
return Integer.valueOf((String) value);
}
else if (value instanceof Boolean)
{
return ((Boolean) value) ? 1 : 0;
}
else
{
return null;
}
}
public static Long valueAsLong(Object value)
{
if (value instanceof Long)
{
return (Long) value;
}
else if (value instanceof Number)
{
return ((Number) value).longValue();
}
else if (value instanceof String)
{
return Long.valueOf((String) value);
}
else if (value instanceof Boolean)
{
return ((Boolean) value) ? 1L : 0L;
}
else
{
return null;
}
}
public static String valueAsStr(Object value)
{
if (value instanceof String)
{
return (String) value;
}
else if (value != null)
{
return value.toString();
}
else
{
return null;
}
}
public static Boolean valueAsBool(Object value)
{
if (value instanceof Boolean)
{
return (Boolean) value;
}
else if (value instanceof Number)
{
return ((Number) value).doubleValue() != 0.0;
}
else if (value instanceof String)
{
return Boolean.valueOf((String) value);
}
else
{
return null;
}
}
/**
* 将所有层次中凡是Map类型同时又不是MessageObject的类型转换为MessageObject类型。
*
* @param value 值。
* @return 返回转换后的值。
*/
@SuppressWarnings("unchecked")
private static Object transfer(final Object value)
{
if (!(value instanceof JSONObject) && value instanceof Map)
{
return toObj((Map<String, Object>) value);
}
else if (!(value instanceof JSONArray) && value instanceof Collection)
{
return toArr((Collection<Object>) value);
}
else
{
return value;
}
}
private static JSONArray toArr(final Collection<Object> list)
{
final JSONArray arr = new JSONArray(list.size());
for (final Object element : list)
{
arr.add(element);
}
return arr;
}
private static JSONObject toObj(final Map<String, Object> map)
{
final JSONObject obj = new JSONObject();
for (final Map.Entry<String, Object> ent : map.entrySet())
{
obj.put(ent.getKey(), transfer(ent.getValue()));
}
return obj;
}
/**
* 将指定下标元素作为数组返回,如果不存在,则在该位置创建一个空的数组。
*
* @param arr 当前数组。
* @param index 下标。
* @return 返回当前数组指定下标的元素,该元素应该是一个数组。
*/
private static JSONArray arrayAt(JSONArray arr, int index)
{
expand(arr, index);
if (arr.get(index) == null)
{
arr.set(index, new JSONArray());
}
return (JSONArray) arr.get(index);
}
/**
* 将指定下标元素作为结构体返回,如果不存在,则在该位置创建一个空的结构体。
*
* @param arr 当前数组。
* @param index 下标。
* @return 返回当前数组指定下标元素,该元素是一个结构体。
*/
private static JSONObject objAt(final JSONArray arr, int index)
{
expand(arr, index);
if (arr.get(index) == null)
{
arr.set(index, new JSONObject());
}
return (JSONObject) arr.get(index);
}
/**
* 设置数组指定下标位置的值。
*
* @param arr 数组。
* @param index 下标。
* @param value 值。
*/
private static void elementAt(final JSONArray arr, final int index, final Object value)
{
expand(arr, index).set(index, value);
}
/**
* 获取数组指定下标元素的值。
*
* @param arr 数组。
* @param index 下标。
* @return 值。
*/
private static Object elementAt(final JSONArray arr, final int index)
{
return expand(arr, index).get(index);
}
/**
* 扩展数组到指定下标,以防止访问时下标越界。
*
* @param arr 数组
* @param index 下标
* @return 返回传入的数组
*/
private static JSONArray expand(final JSONArray arr, final int index)
{
while (arr.size() <= index)
{
arr.add(null);
}
return arr;
}
/**
* 最后数组回调。
*
* @author Mike
*
* @param <T> 回调返回数据类型。
*/
private interface EndArrayCallback<T>
{
/**
* 当定位到最后一级数组,将调用本方法。
*
* @param arr 最后一级数组对象。
* @param index 最后一级索引。
* @return 返回回调的返回值。
*/
T callback(JSONArray arr, int index);
}
/**
* 处理多维数组的工具函数包括一维数组。多维数组的名字如arrary[1][2][3] 则name=arrayindexStr=[1][2][3]在callback中endArr将是
* array[1][2]指定的对象indexe=3。
*
* @param name 不带下标的名字,不支持多级名字。
* @param indexesStr 索引部分的字符串,如:[1][2][3]
* @param callback 回调函数。
* @return 返回回调函数的返回值。
*/
private <T> T endArray(final String name, final String indexesStr, final EndArrayCallback<T> callback)
{
JSONArray endArr = arr(name);
final int[] indexes = parseIndexes(indexesStr);
int i = 0;
while (i < indexes.length - 1)
{
endArr = arrayAt(endArr, indexes[i++]);
}
return callback.callback(endArr, indexes[i]);
}
private static int[] parseIndexes(final String s)
{
int[] indexes = null;
List<Integer> list = new ArrayList<Integer>();
final StringTokenizer st = new StringTokenizer(s, "[]");
while (st.hasMoreTokens())
{
final int index = Integer.valueOf(st.nextToken());
if (index < 0)
{
throw new RuntimeException(String.format("Illegal index %1$d in \"%2$s\"", index, s));
}
list.add(index);
}
indexes = new int[list.size()];
int i = 0;
for (Integer tmp : list.toArray(new Integer[list.size()]))
{
indexes[i++] = tmp;
}
return indexes;
}
}