修改关键字定位方式

jingwei
youhong.ai 2023-06-02 11:29:18 +08:00
parent 7e6fa007e0
commit 17ba40eee8
37 changed files with 6076 additions and 16 deletions

View File

@ -0,0 +1,214 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.copier.CopyOptions;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.lang.Filter;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutablePair;
import aiyh.utils.tool.cn.hutool.core.map.CaseInsensitiveLinkedMap;
import aiyh.utils.tool.cn.hutool.core.map.CaseInsensitiveTreeMap;
import aiyh.utils.tool.cn.hutool.core.util.*;
import java.math.BigDecimal;
import java.util.*;
/**
* JSONJSON使
*
* @author Looly
*/
public final class InternalJSONUtil {
private InternalJSONUtil() {
}
/**
* Number NaN or infinite
*
* @param obj
* @return
* @throws JSONException If o is a non-finite number.
*/
static Object testValidity(Object obj) throws JSONException {
if (!ObjectUtil.isValidIfNumber(obj)) {
throw new JSONException("JSON does not allow non-finite numbers.");
}
return obj;
}
/**
* StringJSON
* <ul>
* <li>{@link JSONString}{@link JSONString#toJSONString()}</li>
* <li>{@link JSONString}{@link JSONString#toJSONString()}</li>
* <li>Collection{@link JSONArray}</li>
* <li>Map{@link JSONObject}</li>
* <li>使{@link NumberUtil#toStr(Number)}</li>
* <li>toString使</li>
* </ul>
*
* @param value
* @return
* @throws JSONException If the value is or contains an invalid number.
*/
static String valueToString(Object value) throws JSONException {
if (value == null || value instanceof JSONNull) {
return JSONNull.NULL.toString();
}
if (value instanceof JSONString) {
try {
return ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
} else if (value instanceof Number) {
return NumberUtil.toStr((Number) value);
} else if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) {
return value.toString();
} else if (value instanceof Map) {
Map<?, ?> map = (Map<?, ?>) value;
return new JSONObject(map).toString();
} else if (value instanceof Collection) {
Collection<?> coll = (Collection<?>) value;
return new JSONArray(coll).toString();
} else if (ArrayUtil.isArray(value)) {
return new JSONArray(value).toString();
} else {
return JSONUtil.quote(value.toString());
}
}
/**
* number, boolean, or nullString
*
* @param string A String.
* @return A simple JSON value.
*/
public static Object stringToValue(String string) {
// null处理
if (StrUtil.isEmpty(string) || StrUtil.NULL.equalsIgnoreCase(string)) {
return JSONNull.NULL;
}
// boolean处理
if ("true".equalsIgnoreCase(string)) {
return Boolean.TRUE;
}
if ("false".equalsIgnoreCase(string)) {
return Boolean.FALSE;
}
// Number处理
char b = string.charAt(0);
if ((b >= '0' && b <= '9') || b == '-') {
try {
if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) {
// pr#192@GiteeDouble会出现小数精度丢失问题此处使用BigDecimal
return new BigDecimal(string);
} else {
final long myLong = Long.parseLong(string);
if (string.equals(Long.toString(myLong))) {
if (myLong == (int) myLong) {
return (int) myLong;
} else {
return myLong;
}
}
}
} catch (Exception ignore) {
}
}
// 其它情况返回原String值下
return string;
}
/**
* PropertyJSON<br>
* com.luxiaolei.package.hutool<br>
* JSONObject
*
* @param jsonObject JSONObject
* @param key
* @param value
* @return JSONObject
*/
static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value, Filter<MutablePair<String, Object>> filter) {
final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT);
final int last = path.length - 1;
JSONObject target = jsonObject;
for (int i = 0; i < last; i += 1) {
final String segment = path[i];
JSONObject nextTarget = target.getJSONObject(segment);
if (nextTarget == null) {
nextTarget = new JSONObject(target.getConfig());
target.set(segment, nextTarget, filter, target.getConfig().isCheckDuplicate());
}
target = nextTarget;
}
target.set(path[last], value, filter, target.getConfig().isCheckDuplicate());
return jsonObject;
}
/**
* nullnull
*
* <pre>
* 1. CharSequence
* 2. JSONTokener
* 3. Map
* </pre>
*
* @param obj
* @return null
* @since 4.3.1
*/
static boolean defaultIgnoreNullValue(Object obj) {
return (!(obj instanceof CharSequence))//
&& (!(obj instanceof JSONTokener))//
&& (!(obj instanceof Map));
}
/**
* {@link JSONConfig}Bean{@link CopyOptions}
*
* @param config {@link JSONConfig}
* @return {@link CopyOptions}
* @since 5.8.0
*/
static CopyOptions toCopyOptions(JSONConfig config) {
return CopyOptions.create()
.setIgnoreCase(config.isIgnoreCase())
.setIgnoreError(config.isIgnoreError())
.setIgnoreNullValue(config.isIgnoreNullValue())
.setTransientSupport(config.isTransientSupport());
}
/**
* Map
*
* @param capacity
* @param config JSON{@code null}使
* @return Map
*/
static Map<String, Object> createRawMap(int capacity, JSONConfig config) {
final Map<String, Object> rawHashMap;
if (null == config) {
config = JSONConfig.create();
}
final Comparator<String> keyComparator = config.getKeyComparator();
if (config.isIgnoreCase()) {
if (null != keyComparator) {
rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
} else {
rawHashMap = new CaseInsensitiveLinkedMap<>(capacity);
}
} else {
if (null != keyComparator) {
rawHashMap = new TreeMap<>(keyComparator);
} else {
rawHashMap = new LinkedHashMap<>(capacity);
}
}
return rawHashMap;
}
}

View File

@ -0,0 +1,195 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.BeanPath;
import aiyh.utils.tool.cn.hutool.core.lang.TypeReference;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
/**
* JSON
*
* @author Looly
*/
public interface JSON extends Cloneable, Serializable {
/**
* JSON
*
* @return {@link JSONConfig}
* @since 5.8.6
*/
JSONConfig getConfig();
/**
* JSON<br>
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param expression
* @return
* @see BeanPath#get(Object)
* @since 4.0.6
*/
Object getByPath(String expression);
/**
* filed<br>
* JSONArrayJSONObjectputkey<br>
* JSONArray<br>
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param expression
* @param value
*/
void putByPath(String expression, Object value);
/**
* JSON<br>
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
* <p>
*
*
* @param <T>
* @param expression
* @param resultType
* @return
* @see BeanPath#get(Object)
* @since 4.0.6
*/
<T> T getByPath(String expression, Class<T> resultType);
/**
* JSON4
*
* @return JSON
* @throws JSONException
* @since 3.0.9
*/
default String toStringPretty() throws JSONException {
return this.toJSONString(4);
}
/**
* JSON
*
* @param indentFactor
* @return JSON
* @throws JSONException
*/
default String toJSONString(int indentFactor) throws JSONException {
final StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
return this.write(sw, indentFactor, 0).toString();
}
}
/**
* JSONWriter<br>
* Warning: This method assumes that the data structure is acyclical.
*
* @param writer Writer
* @return Writer
* @throws JSONException JSON
*/
default Writer write(Writer writer) throws JSONException {
return this.write(writer, 0, 0);
}
/**
* JSONWriter<br>
* Warning: This method assumes that the data structure is acyclical.
*
* @param writer writer
* @param indentFactor
* @param indent
* @return Writer
* @throws JSONException JSON
*/
Writer write(Writer writer, int indentFactor, int indent) throws JSONException;
/**
*
*
* @param <T> Bean
* @param clazz
* @return
*/
default <T> T toBean(Class<T> clazz) {
return toBean((Type) clazz);
}
/**
*
*
* @param <T> Bean
* @param reference {@link TypeReference}Type
* @return
* @since 4.2.2
*/
default <T> T toBean(TypeReference<T> reference) {
return toBean(reference.getType());
}
/**
*
*
* @param <T> Bean
* @param type {@link Type}
* @return
* @since 3.0.8
*/
default <T> T toBean(Type type) {
return toBean(type, getConfig().isIgnoreError());
}
/**
*
*
* @param <T> Bean
* @param type {@link Type}
* @param ignoreError
* @return
* @since 4.3.2
*/
default <T> T toBean(Type type, boolean ignoreError) {
return JSONConverter.jsonConvert(type, this, ignoreError);
}
}

View File

@ -0,0 +1,591 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.BeanPath;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.lang.Filter;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.Mutable;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutableObj;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutablePair;
import aiyh.utils.tool.cn.hutool.core.text.StrJoiner;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.*;
/**
* JSON<br>
* JSON<br>
* JSON:
*
* <pre>
* ["a", "b", "c", 12]
* </pre>
*
* @author looly
*/
public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, RandomAccess {
private static final long serialVersionUID = 2664900568717612292L;
/**
*
*/
public static final int DEFAULT_CAPACITY = 10;
/**
* List
*/
private List<Object> rawList;
/**
*
*/
private final JSONConfig config;
// region Constructors
/**
* <br>
* 使{@link ArrayList}
*/
public JSONArray() {
this(DEFAULT_CAPACITY);
}
/**
* <br>
* 使{@link ArrayList}
*
* @param initialCapacity
* @since 3.2.2
*/
public JSONArray(int initialCapacity) {
this(initialCapacity, JSONConfig.create());
}
/**
* <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
*/
public JSONArray(int initialCapacity, JSONConfig config) {
this.rawList = new ArrayList<>(initialCapacity);
this.config = ObjectUtil.defaultIfNull(config, JSONConfig::create);
}
/**
* {@code null}<br>
*
*
* <pre>
* 1.
* 2. {@link Iterable}
* 3. JSON
* </pre>
*
* @param object JSON
* @throws JSONException
*/
public JSONArray(Object object) throws JSONException {
this(object, true);
}
/**
* <br>
*
*
* <pre>
* 1.
* 2. {@link Iterable}
* 3. JSON
* </pre>
*
* @param object JSON
* @param ignoreNullValue
* @throws JSONException
*/
public JSONArray(Object object, boolean ignoreNullValue) throws JSONException {
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(object, jsonConfig, null);
}
/**
* <br>
*
*
* <pre>
* 1.
* 2. {@link Iterable}
* 3. JSON
* </pre>
*
* @param object JSON
* @param jsonConfig JSON
* @param filter {@code null}
* @throws JSONException
* @since 5.8.0
*/
public JSONArray(Object object, JSONConfig jsonConfig, Filter<Mutable<Object>> filter) throws JSONException {
this(DEFAULT_CAPACITY, jsonConfig);
ObjectMapper.of(object).map(this, filter);
}
// endregion
@Override
public JSONConfig getConfig() {
return this.config;
}
/**
* null
*
* @param format null使
* @return this
* @since 4.1.19
*/
public JSONArray setDateFormat(String format) {
this.config.setDateFormat(format);
return this;
}
/**
* JSONArray{@code separator}
*
* @param separator
* @return a string.
* @throws JSONException If the array contains an invalid number.
*/
public String join(String separator) throws JSONException {
return StrJoiner.of(separator)
.append(this, InternalJSONUtil::valueToString).toString();
}
@Override
public Object get(int index) {
return this.rawList.get(index);
}
@Override
public Object getObj(Integer index, Object defaultValue) {
return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index);
}
@Override
public Object getByPath(String expression) {
return BeanPath.create(expression).get(this);
}
@Override
public <T> T getByPath(String expression, Class<T> resultType) {
return JSONConverter.jsonConvert(resultType, getByPath(expression), true);
}
@Override
public void putByPath(String expression, Object value) {
BeanPath.create(expression).set(this, value);
}
/**
* Append an object value. This increases the array's length by one. <br>
* +1 {@link JSONArray#add(Object)}
*
* @param value Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONNull.NULL
* @return this.
* @see #set(Object)
*/
public JSONArray put(Object value) {
return set(value);
}
/**
* Append an object value. This increases the array's length by one. <br>
* +1 {@link JSONArray#add(Object)}
*
* @param value Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONNull.NULL
* @return this.
* @since 5.2.5
*/
public JSONArray set(Object value) {
this.add(value);
return this;
}
/**
* JSONArrayIndexindexJSONArrayindexJSONNull.Null
*
* @param index
* @param value . : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return this.
* @throws JSONException index &lt; 0
* @see #set(int, Object)
*/
public JSONArray put(int index, Object value) throws JSONException {
this.set(index, value);
return this;
}
/**
* JSONObject
*
* @param names JSONArray
* @return A JSONObjectnull
* @throws JSONException null
*/
public JSONObject toJSONObject(JSONArray names) throws JSONException {
if (names == null || names.size() == 0 || this.size() == 0) {
return null;
}
final JSONObject jo = new JSONObject(this.config);
for (int i = 0; i < names.size(); i += 1) {
jo.set(names.getStr(i), this.getObj(i));
}
return jo;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((rawList == null) ? 0 : rawList.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final JSONArray other = (JSONArray) obj;
if (rawList == null) {
return other.rawList == null;
} else {
return rawList.equals(other.rawList);
}
}
@Override
public Iterator<Object> iterator() {
return rawList.iterator();
}
/**
* JSONJSONObjectIterable便使foreach
*
* @return Iterable
* @since 4.0.12
*/
public Iterable<JSONObject> jsonIter() {
return new JSONObjectIter(iterator());
}
@Override
public int size() {
return rawList.size();
}
@Override
public boolean isEmpty() {
return rawList.isEmpty();
}
@Override
public boolean contains(Object o) {
return rawList.contains(o);
}
@Override
public Object[] toArray() {
return rawList.toArray();
}
@Override
@SuppressWarnings({"unchecked"})
public <T> T[] toArray(T[] a) {
return (T[]) JSONConverter.toArray(this, a.getClass().getComponentType());
}
@Override
public boolean add(Object e) {
return addRaw(JSONUtil.wrap(e, this.config), null);
}
@Override
public Object remove(int index) {
return index >= 0 && index < this.size() ? this.rawList.remove(index) : null;
}
@Override
public boolean remove(Object o) {
return rawList.remove(o);
}
@SuppressWarnings("NullableProblems")
@Override
public boolean containsAll(Collection<?> c) {
return rawList.containsAll(c);
}
@SuppressWarnings("NullableProblems")
@Override
public boolean addAll(Collection<?> c) {
if (CollUtil.isEmpty(c)) {
return false;
}
for (Object obj : c) {
this.add(obj);
}
return true;
}
@SuppressWarnings("NullableProblems")
@Override
public boolean addAll(int index, Collection<?> c) {
if (CollUtil.isEmpty(c)) {
return false;
}
final ArrayList<Object> list = new ArrayList<>(c.size());
for (Object object : c) {
list.add(JSONUtil.wrap(object, this.config));
}
return rawList.addAll(index, list);
}
@SuppressWarnings("NullableProblems")
@Override
public boolean removeAll(Collection<?> c) {
return this.rawList.removeAll(c);
}
@SuppressWarnings("NullableProblems")
@Override
public boolean retainAll(Collection<?> c) {
return this.rawList.retainAll(c);
}
@Override
public void clear() {
this.rawList.clear();
}
/**
* JSONArrayIndexindexJSONArrayindexJSONNull.Null
*
* @param index
* @param element . : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return
*/
@Override
public Object set(int index, Object element) {
return set(index, element, null);
}
/**
* JSONArrayIndexindexJSONArrayindexJSONNull.Null
*
* @param index
* @param element . : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @param filter keyindex
* @return
* @since 5.8.0
*/
public Object set(int index, Object element, Filter<MutablePair<Integer, Object>> filter) {
// 添加前置过滤通过MutablePair实现过滤、修改键值对等
if (null != filter) {
final MutablePair<Integer, Object> pair = new MutablePair<>(index, element);
if (filter.accept(pair)) {
// 使用修改后的值
element = pair.getValue();
}
}
if (index >= size()) {
add(index, element);
}
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[{}] not found.", index);
}
if (index < this.size()) {
InternalJSONUtil.testValidity(element);
this.rawList.add(index, JSONUtil.wrap(element, this.config));
} else {
while (index != this.size()) {
this.add(JSONNull.NULL);
}
this.set(element);
}
}
@Override
public int indexOf(Object o) {
return this.rawList.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return this.rawList.lastIndexOf(o);
}
@Override
public ListIterator<Object> listIterator() {
return this.rawList.listIterator();
}
@Override
public ListIterator<Object> listIterator(int index) {
return this.rawList.listIterator(index);
}
@Override
public List<Object> subList(int fromIndex, int toIndex) {
return this.rawList.subList(fromIndex, toIndex);
}
/**
* Bean
*
* @param arrayClass
* @return
*/
public Object toArray(Class<?> arrayClass) {
return JSONConverter.toArray(this, arrayClass);
}
/**
* {@link ArrayList}
*
* @param <T>
* @param elementType
* @return {@link ArrayList}
* @since 3.0.8
*/
public <T> List<T> toList(Class<T> elementType) {
return JSONConverter.toList(this, elementType);
}
/**
* JSON
*
* @return JSONArray
*/
@Override
public String toString() {
return this.toJSONString(0);
}
/**
* JSON<br>
*
*
* @param indentFactor
* @param filter keyindex
* @return JSON
* @since 5.7.15
*/
public String toJSONString(int indentFactor, Filter<MutablePair<Object, Object>> filter) {
final StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
return this.write(sw, indentFactor, 0, filter).toString();
}
}
@Override
public Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
return write(writer, indentFactor, indent, null);
}
/**
* JSONWriter<br>
*
*
* @param writer writer
* @param indentFactor
* @param indent
* @param filter keyindex
* @return Writer
* @throws JSONException JSON
* @since 5.7.15
*/
public Writer write(Writer writer, int indentFactor, int indent, Filter<MutablePair<Object, Object>> filter) throws JSONException {
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config).beginArray();
CollUtil.forEach(this, (value, index) -> jsonWriter.writeField(new MutablePair<>(index, value), filter));
jsonWriter.end();
// 此处不关闭Writer考虑writer后续还需要填内容
return writer;
}
@Override
public Object clone() throws CloneNotSupportedException {
final JSONArray clone = (JSONArray) super.clone();
clone.rawList = ObjectUtil.clone(this.rawList);
return clone;
}
/**
*
*
* @param obj
* @param filter {@code null}
* @return
* @since 5.8.0
*/
protected boolean addRaw(Object obj, Filter<Mutable<Object>> filter) {
// 添加前置过滤通过MutablePair实现过滤、修改键值对等
if (null != filter) {
final Mutable<Object> mutable = new MutableObj<>(obj);
if (filter.accept(mutable)) {
// 使用修改后的值
obj = mutable.get();
} else {
// 键值对被过滤
return false;
}
}
return this.rawList.add(obj);
}
}

View File

@ -0,0 +1,18 @@
package aiyh.utils.tool.cn.hutool.json;
/**
* {@code parse(value)}JSON
*
* @author Looly
* @since 5.7.8
*/
public interface JSONBeanParser<T> {
/**
* valueBean<br>
* JSONJSON
*
* @param value JSONStringNumber
*/
void parse(T value);
}

View File

@ -0,0 +1,265 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.comparator.CompareUtil;
import java.io.Serializable;
import java.util.Comparator;
/**
* JSON
*
* @author looly
* @since 4.1.19
*/
public class JSONConfig implements Serializable {
private static final long serialVersionUID = 119730355204738278L;
/**
* {@code null}
*/
private Comparator<String> keyComparator;
/**
*
*/
private boolean ignoreError;
/**
*
*/
private boolean ignoreCase;
/**
* null
*/
private String dateFormat;
/**
* null
*/
private boolean ignoreNullValue = true;
/**
* transient@Transient
*/
private boolean transientSupport = true;
/**
* 0true,5.05
*/
private boolean stripTrailingZeros = true;
/**
* key
*/
private boolean checkDuplicate;
/**
*
*
* @return JSONConfig
*/
public static JSONConfig create() {
return new JSONConfig();
}
/**
* JSONObject
*
* @return
* @deprecated {@code true}
*/
@Deprecated
public boolean isOrder() {
return true;
}
/**
* JSONObject
*
* @param order
* @return this
* @deprecated
*/
@SuppressWarnings("unused")
@Deprecated
public JSONConfig setOrder(boolean order) {
return this;
}
/**
* <br>
* {@code null}
*
* @return
* @since 5.7.21
*/
public Comparator<String> getKeyComparator() {
return this.keyComparator;
}
/**
*
*
* @return this
* @since 5.7.21
*/
public JSONConfig setNatureKeyComparator() {
return setKeyComparator(CompareUtil.naturalComparator());
}
/**
* <br>
* {@code null}
*
* @param keyComparator
* @return this
* @since 5.7.21
*/
public JSONConfig setKeyComparator(Comparator<String> keyComparator) {
this.keyComparator = keyComparator;
return this;
}
/**
*
*
* @return
*/
public boolean isIgnoreError() {
return ignoreError;
}
/**
*
*
* @param ignoreError
* @return this
*/
public JSONConfig setIgnoreError(boolean ignoreError) {
this.ignoreError = ignoreError;
return this;
}
/**
*
*
* @return
*/
public boolean isIgnoreCase() {
return ignoreCase;
}
/**
*
*
* @param ignoreCase
* @return this
*/
public JSONConfig setIgnoreCase(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
return this;
}
/**
* null
*
* @return null
*/
public String getDateFormat() {
return dateFormat;
}
/**
* null<br>
* JSONJSONbean
*
* @param dateFormat null
* @return this
*/
public JSONConfig setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
return this;
}
/**
* null
*
* @return null
*/
public boolean isIgnoreNullValue() {
return this.ignoreNullValue;
}
/**
* null
*
* @param ignoreNullValue null
* @return this
*/
public JSONConfig setIgnoreNullValue(boolean ignoreNullValue) {
this.ignoreNullValue = ignoreNullValue;
return this;
}
/**
* transient@Transient
*
* @return
* @since 5.4.2
*/
public boolean isTransientSupport() {
return this.transientSupport;
}
/**
* transient@Transient
*
* @param transientSupport
* @return this
* @since 5.4.2
*/
public JSONConfig setTransientSupport(boolean transientSupport) {
this.transientSupport = transientSupport;
return this;
}
/**
* 0true,5.05
*
* @return 0true,5.05
* @since 5.6.2
*/
public boolean isStripTrailingZeros() {
return stripTrailingZeros;
}
/**
* 0true,5.05
*
* @param stripTrailingZeros 0true,5.05
* @return this
* @since 5.6.2
*/
public JSONConfig setStripTrailingZeros(boolean stripTrailingZeros) {
this.stripTrailingZeros = stripTrailingZeros;
return this;
}
/**
* key
*
* @return key
* @since 5.8.5
*/
public boolean isCheckDuplicate() {
return checkDuplicate;
}
/**
* key
*
* @param checkDuplicate key
* @return this
* @since 5.8.5
*/
public JSONConfig setCheckDuplicate(boolean checkDuplicate) {
this.checkDuplicate = checkDuplicate;
return this;
}
}

View File

@ -0,0 +1,151 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.BeanUtil;
import aiyh.utils.tool.cn.hutool.core.codec.Base64;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.convert.ConvertException;
import aiyh.utils.tool.cn.hutool.core.convert.Converter;
import aiyh.utils.tool.cn.hutool.core.convert.ConverterRegistry;
import aiyh.utils.tool.cn.hutool.core.convert.impl.ArrayConverter;
import aiyh.utils.tool.cn.hutool.core.convert.impl.BeanConverter;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import aiyh.utils.tool.cn.hutool.core.util.TypeUtil;
import aiyh.utils.tool.cn.hutool.json.serialize.GlobalSerializeMapping;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONDeserializer;
import java.lang.reflect.Type;
import java.util.List;
/**
* JSON
*
* @author looly
* @since 4.2.2
*/
public class JSONConverter implements Converter<JSON> {
static {
// 注册到转换中心
final ConverterRegistry registry = ConverterRegistry.getInstance();
registry.putCustom(JSON.class, JSONConverter.class);
registry.putCustom(JSONObject.class, JSONConverter.class);
registry.putCustom(JSONArray.class, JSONConverter.class);
}
/**
* JSONArray
*
* @param jsonArray JSONArray
* @param arrayClass
* @return
*/
protected static Object toArray(JSONArray jsonArray, Class<?> arrayClass) {
return new ArrayConverter(arrayClass).convert(jsonArray, null);
}
/**
* JSONArray
*
* @param <T>
* @param jsonArray JSONArray
* @param elementType
* @return
*/
protected static <T> List<T> toList(JSONArray jsonArray, Class<T> elementType) {
return Convert.toList(elementType, jsonArray);
}
/**
* JSON<br>
* JDKJSONBean<br>
* {@link JSONBeanParser}{@link JSONBeanParser#parse(Object)}
*
* @param <T>
* @param targetType
* @param value
* @param ignoreError
* @return
* @throws ConvertException
*/
@SuppressWarnings("unchecked")
protected static <T> T jsonConvert(Type targetType, Object value, boolean ignoreError) throws ConvertException {
if (JSONUtil.isNull(value)) {
return null;
}
// since 5.7.8增加自定义Bean反序列化接口
if (targetType instanceof Class) {
final Class<?> clazz = (Class<?>) targetType;
if (JSONBeanParser.class.isAssignableFrom(clazz)) {
@SuppressWarnings("rawtypes") final JSONBeanParser target = (JSONBeanParser) ReflectUtil.newInstanceIfPossible(clazz);
if (null == target) {
throw new ConvertException("Can not instance [{}]", targetType);
}
target.parse(value);
return (T) target;
} else if (targetType == byte[].class && value instanceof CharSequence) {
// issue#I59LW4
return (T) Base64.decode((CharSequence) value);
}
}
return jsonToBean(targetType, value, ignoreError);
}
/**
* JSON<br>
* JDKJSONBean
*
* @param <T>
* @param targetType
* @param value JSON
* @param ignoreError
* @return
* @throws ConvertException
* @since 5.7.10
*/
protected static <T> T jsonToBean(Type targetType, Object value, boolean ignoreError) throws ConvertException {
if (JSONUtil.isNull(value)) {
return null;
}
if (value instanceof JSON) {
final JSONDeserializer<?> deserializer = GlobalSerializeMapping.getDeserializer(targetType);
if (null != deserializer) {
// noinspection unchecked
return (T) deserializer.deserialize((JSON) value);
}
// issue#2212@Github
// 在JSONObject转Bean时读取JSONObject本身的配置文件
if (value instanceof JSONGetter
&& targetType instanceof Class && BeanUtil.hasSetter((Class<?>) targetType)) {
final JSONConfig config = ((JSONGetter<?>) value).getConfig();
final Converter<T> converter = new BeanConverter<>(targetType,
InternalJSONUtil.toCopyOptions(config).setIgnoreError(ignoreError));
return converter.convertWithCheck(value, null, ignoreError);
}
}
final T targetValue = Convert.convertWithCheck(targetType, value, null, ignoreError);
if (null == targetValue && !ignoreError) {
if (StrUtil.isBlankIfStr(value)) {
// 对于传入空字符串的情况如果转换的目标对象是非字符串或非原始类型转换器会返回false。
// 此处特殊处理认为返回null属于正常情况
return null;
}
throw new ConvertException("Can not convert {} to type {}", value, ObjectUtil.defaultIfNull(TypeUtil.getClass(targetType), targetType));
}
return targetValue;
}
@Override
public JSON convert(Object value, JSON defaultValue) throws IllegalArgumentException {
return JSONUtil.parse(value);
}
}

View File

@ -0,0 +1,38 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.exceptions.ExceptionUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
/**
* JSON
*
* @author looly
* @since 3.0.2
*/
public class JSONException extends RuntimeException {
private static final long serialVersionUID = 0;
public JSONException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public JSONException(String message) {
super(message);
}
public JSONException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public JSONException(String message, Throwable cause) {
super(message, cause);
}
public JSONException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
super(message, throwable, enableSuppression, writableStackTrace);
}
public JSONException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}

View File

@ -0,0 +1,237 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.convert.ConvertException;
import aiyh.utils.tool.cn.hutool.core.date.DateUtil;
import aiyh.utils.tool.cn.hutool.core.date.LocalDateTimeUtil;
import aiyh.utils.tool.cn.hutool.core.getter.OptNullBasicTypeFromObjectGetter;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* JSONGetterGetter
*
* @param <K> Key
* @author Looly
*/
public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
/**
* JSON
*
* @return {@link JSONConfig}
* @since 5.3.0
*/
JSONConfig getConfig();
/**
* key{@code null}key
*
* @param key
* @return true key{@code null}{@link JSONNull#NULL}{@code false}{@code true}
*/
default boolean isNull(K key) {
return JSONUtil.isNull(this.getObj(key));
}
/**
* '\n'"\n"
*
* @param key
* @return
* @since 4.2.2
*/
default String getStrEscaped(K key) {
return getStrEscaped(key, null);
}
/**
* '\n'"\n"
*
* @param key
* @param defaultValue
* @return
* @since 4.2.2
*/
default String getStrEscaped(K key, String defaultValue) {
return JSONUtil.escape(getStr(key, defaultValue));
}
/**
* JSONArray<br>
* {@link JSONArray}
*
* @param key KEY
* @return JSONArray{@code null}{@code null}JSONArray
*/
default JSONArray getJSONArray(K key) {
final Object object = this.getObj(key);
if (JSONUtil.isNull(object)) {
return null;
}
if (object instanceof JSON) {
return (JSONArray) object;
}
return new JSONArray(object, getConfig());
}
/**
* JSONObject<br>
* {@link JSONObject}
*
* @param key KEY
* @return JSONObject{@code null}{@code null}JSONObject
*/
default JSONObject getJSONObject(K key) {
final Object object = this.getObj(key);
if (JSONUtil.isNull(object)) {
return null;
}
if (object instanceof JSON) {
return (JSONObject) object;
}
return new JSONObject(object, getConfig());
}
/**
* JSONBean<br>
* JSONObjectBean
*
* @param <T> Bean
* @param key KEY
* @param beanType Bean
* @return BeannullJSONObjectnull
* @since 3.1.1
*/
default <T> T getBean(K key, Class<T> beanType) {
final JSONObject obj = getJSONObject(key);
return (null == obj) ? null : obj.toBean(beanType);
}
/**
* JSONBeanList<br>
* JSONArrayBeanList
*
* @param <T> Bean
* @param key KEY
* @param beanType Bean
* @return BeanListnullJSONObjectnull
* @since 5.7.20
*/
default <T> List<T> getBeanList(K key, Class<T> beanType) {
final JSONArray jsonArray = getJSONArray(key);
return (null == jsonArray) ? null : jsonArray.toList(beanType);
}
@Override
default Date getDate(K key, Date defaultValue) {
// 默认转换
final Object obj = getObj(key);
if (JSONUtil.isNull(obj)) {
return defaultValue;
}
if (obj instanceof Date) {
return (Date) obj;
}
final Optional<String> formatOps = Optional.ofNullable(getConfig()).map(JSONConfig::getDateFormat);
if (formatOps.isPresent()) {
final String format = formatOps.get();
if (StrUtil.isNotBlank(format)) {
// 用户指定了日期格式,获取日期属性时使用对应格式
final String str = Convert.toStr(obj);
if (null == str) {
return defaultValue;
}
return DateUtil.parse(str, format);
}
}
return Convert.toDate(obj, defaultValue);
}
/**
* {@link LocalDateTime}
*
* @param key
* @param defaultValue
* @return {@link LocalDateTime}
* @since 5.7.7
*/
default LocalDateTime getLocalDateTime(K key, LocalDateTime defaultValue) {
// 默认转换
final Object obj = getObj(key);
if (JSONUtil.isNull(obj)) {
return defaultValue;
}
if (obj instanceof LocalDateTime) {
return (LocalDateTime) obj;
}
final Optional<String> formatOps = Optional.ofNullable(getConfig()).map(JSONConfig::getDateFormat);
if (formatOps.isPresent()) {
final String format = formatOps.get();
if (StrUtil.isNotBlank(format)) {
// 用户指定了日期格式,获取日期属性时使用对应格式
final String str = Convert.toStr(obj);
if (null == str) {
return defaultValue;
}
return LocalDateTimeUtil.parse(str, format);
}
}
return Convert.toLocalDateTime(obj, defaultValue);
}
/**
* byte[]
*
* @param key
* @return
* @since 5.8.2
*/
default byte[] getBytes(K key) {
return get(key, byte[].class);
}
/**
* <br>
*
*
* @param <T>
* @param key
* @param type
* @return
* @throws ConvertException
* @since 3.0.8
*/
default <T> T get(K key, Class<T> type) throws ConvertException {
return get(key, type, false);
}
/**
*
*
* @param <T>
* @param key
* @param type
* @param ignoreError
* @return
* @throws ConvertException
* @since 3.0.8
*/
default <T> T get(K key, Class<T> type, boolean ignoreError) throws ConvertException {
final Object value = this.getObj(key);
if (JSONUtil.isNull(value)) {
return null;
}
return JSONConverter.jsonConvert(type, value, ignoreError);
}
}

View File

@ -0,0 +1,46 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.io.Serializable;
/**
* {@code null}Javascriptnull<br>
* Java{@code null}jsundefined
*
* @author Looly
*/
public class JSONNull implements Serializable {
private static final long serialVersionUID = 2633815155870764938L;
/**
* {@code NULL} Java {@code null} <br>
* {@code NULL.equals(null)} {@code true}. <br>
* {@code NULL.toString()} {@code "null"}.
*/
public static final JSONNull NULL = new JSONNull();
/**
* A Null object is equal to the null value and to itself.
* {@code null}
*
* @param object An object to test for nullness.
* @return true if the object parameter is the JSONObject.NULL object or null.
*/
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@Override
public boolean equals(Object object) {
return object == null || (object == this);
}
/**
* Get the "null" string value.
* null
*
* @return The string "null".
*/
@Override
public String toString() {
return StrUtil.NULL;
}
}

View File

@ -0,0 +1,577 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.BeanPath;
import aiyh.utils.tool.cn.hutool.core.collection.CollectionUtil;
import aiyh.utils.tool.cn.hutool.core.lang.Filter;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutablePair;
import aiyh.utils.tool.cn.hutool.core.map.CaseInsensitiveMap;
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
import aiyh.utils.tool.cn.hutool.core.map.MapWrapper;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Map;
/**
* JSON<br>
* <br>
*
* <pre>
* json = new JSONObject().put(&quot;JSON&quot;, &quot;Hello, World!&quot;).toString();
* </pre>
*
* @author looly
*/
public class JSONObject extends MapWrapper<String, Object> implements JSON, JSONGetter<String> {
private static final long serialVersionUID = -330220388580734346L;
/**
*
*/
public static final int DEFAULT_CAPACITY = MapUtil.DEFAULT_INITIAL_CAPACITY;
/**
*
*/
private JSONConfig config;
// -------------------------------------------------------------------------------------------------------------------- Constructor start
/**
* {@link #DEFAULT_CAPACITY}KEY
*/
public JSONObject() {
this(DEFAULT_CAPACITY, false);
}
/**
* {@link #DEFAULT_CAPACITY}
*
* @param isOrder
* @since 3.0.9
*/
public JSONObject(boolean isOrder) {
this(DEFAULT_CAPACITY, isOrder);
}
/**
*
*
* @param capacity
* @param isOrder
* @since 3.0.9
*/
public JSONObject(int capacity, boolean isOrder) {
this(capacity, false, isOrder);
}
/**
*
*
* @param capacity
* @param isIgnoreCase KEY
* @param isOrder
* @since 3.3.1
* @deprecated isOrder
*/
@SuppressWarnings("unused")
@Deprecated
public JSONObject(int capacity, boolean isIgnoreCase, boolean isOrder) {
this(capacity, JSONConfig.create().setIgnoreCase(isIgnoreCase));
}
/**
*
*
* @param config JSON
* @since 4.6.5
*/
public JSONObject(JSONConfig config) {
this(DEFAULT_CAPACITY, config);
}
/**
*
*
* @param capacity
* @param config JSON{@code null}使
* @since 4.1.19
*/
public JSONObject(int capacity, JSONConfig config) {
super(InternalJSONUtil.createRawMap(capacity, ObjectUtil.defaultIfNull(config, JSONConfig.create())));
this.config = ObjectUtil.defaultIfNull(config, JSONConfig.create());
}
/**
* JSONObjectJavaBeannull
* <ol>
* <li>valueMapJSON</li>
* <li>valueJSONCharSequence使JSONTokener</li>
* <li>valueJSONTokener</li>
* <li>valueJavaBeanJavaBeangettersgetXXXisXXXJSON
* JavaBeangetName()"张三"name: "张三"</li>
* </ol>
*
* @param source JavaBeanMapString
*/
public JSONObject(Object source) {
this(source, InternalJSONUtil.defaultIgnoreNullValue(source));
}
/**
* JSONObject
* <ol>
* <li>valueMapJSON</li>
* <li>valueJSONCharSequence使JSONTokener</li>
* <li>valueJSONTokener</li>
* <li>valueJavaBeanJavaBeangettersgetXXXisXXXJSONJavaBeangetName()"张三"name: "张三"</li>
* </ol>
*
* @param source JavaBeanMapString
* @param ignoreNullValue
* @since 3.0.9
*/
public JSONObject(Object source, boolean ignoreNullValue) {
this(source, JSONConfig.create().setIgnoreNullValue(ignoreNullValue));
}
/**
* JSONObject
* <ol>
* <li>valueMapJSON</li>
* <li>valueJSONCharSequence使JSONTokener</li>
* <li>valueJSONTokener</li>
* <li>valueJavaBeanJavaBeangettersgetXXXisXXXJSONJavaBeangetName()"张三"name: "张三"</li>
* </ol>
*
* @param source JavaBeanMapString
* @param ignoreNullValue sourceJSON
* @param isOrder
* @since 4.2.2
* @deprecated isOrderJSONObject
*/
@SuppressWarnings("unused")
@Deprecated
public JSONObject(Object source, boolean ignoreNullValue, boolean isOrder) {
this(source, JSONConfig.create()//
.setIgnoreCase((source instanceof CaseInsensitiveMap))//
.setIgnoreNullValue(ignoreNullValue)
);
}
/**
* JSONObject
* <ol>
* <li>valueMapJSON</li>
* <li>valueJSONCharSequence使JSONTokener</li>
* <li>valueJSONTokener</li>
* <li>valueJavaBeanJavaBeangettersgetXXXisXXXJSONJavaBeangetName()"张三"name: "张三"</li>
* </ol>
* <p>
* MapJSON;<br>
* JavaBeangettersgetXXXisXXXJSON<br>
* JavaBeangetName()"张三"name: "张三"
*
* @param source JavaBeanMapString
* @param config JSON{@code null}使
* @since 4.2.2
*/
public JSONObject(Object source, JSONConfig config) {
this(source, config, null);
}
/**
* JSONObject
* <ol>
* <li>valueMapJSON</li>
* <li>valueJSONCharSequence使JSONTokener</li>
* <li>valueJSONTokener</li>
* <li>valueJavaBeanJavaBeangettersgetXXXisXXXJSONJavaBeangetName()"张三"name: "张三"</li>
* </ol>
* <p>
* MapJSON;<br>
* JavaBeangettersgetXXXisXXXJSON<br>
* JavaBeangetName()"张三"name: "张三"
*
* @param source JavaBeanMapString
* @param config JSON{@code null}使
* @param filter {@code null}
* @since 5.8.0
*/
public JSONObject(Object source, JSONConfig config, Filter<MutablePair<String, Object>> filter) {
this(DEFAULT_CAPACITY, config);
ObjectMapper.of(source).map(this, filter);
}
/**
* nameJSONObject
*
* <pre>
* 1. objMapname
* 2. objBean使
* </pre>
* <p>
* KEYVALUEnull<br>
* names
*
* @param source BeanMap
* @param names JSONObject
*/
public JSONObject(Object source, String... names) {
this();
if (ArrayUtil.isEmpty(names)) {
ObjectMapper.of(source).map(this, null);
return;
}
if (source instanceof Map) {
Object value;
for (String name : names) {
value = ((Map<?, ?>) source).get(name);
this.set(name, value, null, getConfig().isCheckDuplicate());
}
} else {
for (String name : names) {
try {
this.putOpt(name, ReflectUtil.getFieldValue(source, name));
} catch (Exception ignore) {
// ignore
}
}
}
}
/**
* JSONJSON
*
* @param source {} KEYVALUE使 : 使
* @param isOrder
* @throws JSONException JSON
* @since 4.2.2
* @deprecated isOrder
*/
@SuppressWarnings("unused")
@Deprecated
public JSONObject(CharSequence source, boolean isOrder) throws JSONException {
this(source, JSONConfig.create());
}
// -------------------------------------------------------------------------------------------------------------------- Constructor end
@Override
public JSONConfig getConfig() {
return this.config;
}
/**
* null<br>
* JSONJSONbean
*
* @param format null使
* @return this
* @since 4.1.19
*/
public JSONObject setDateFormat(String format) {
this.config.setDateFormat(format);
return this;
}
/**
* KEYJSONArray
*
* @param names KEY
* @return A JSONArray of values.
* @throws JSONException If any of the values are non-finite numbers.
*/
public JSONArray toJSONArray(Collection<String> names) throws JSONException {
if (CollectionUtil.isEmpty(names)) {
return null;
}
final JSONArray ja = new JSONArray(this.config);
Object value;
for (String name : names) {
value = this.get(name);
if (null != value) {
ja.set(value);
}
}
return ja;
}
@Override
public Object getObj(String key, Object defaultValue) {
return this.getOrDefault(key, defaultValue);
}
@Override
public Object getByPath(String expression) {
return BeanPath.create(expression).get(this);
}
@Override
public <T> T getByPath(String expression, Class<T> resultType) {
return JSONConverter.jsonConvert(resultType, getByPath(expression), true);
}
@Override
public void putByPath(String expression, Object value) {
BeanPath.create(expression).set(this, value);
}
/**
* PUT JSONObjectnull{@code null}
*
* @param key
* @param value . : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return this.
* @throws JSONException
* @deprecated Mapthis使{@link #set(String, Object)}
*/
@Override
@Deprecated
public JSONObject put(String key, Object value) throws JSONException {
return set(key, value);
}
/**
* JSONObjectnull{@code null}
*
* @param key
* @param value . : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return this.
* @throws JSONException
*/
public JSONObject set(String key, Object value) throws JSONException {
return set(key, value, null, false);
}
/**
* JSONObjectnull{@code null}
*
* @param key
* @param value . : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @param filter {@code null}
* @param checkDuplicate {@code true}{@link JSONException}
* @return this.
* @throws JSONException
* @since 5.8.0
*/
public JSONObject set(String key, Object value, Filter<MutablePair<String, Object>> filter, boolean checkDuplicate) throws JSONException {
if (null == key) {
return this;
}
// 添加前置过滤通过MutablePair实现过滤、修改键值对等
if (null != filter) {
final MutablePair<String, Object> pair = new MutablePair<>(key, value);
if (filter.accept(pair)) {
// 使用修改后的键值对
key = pair.getKey();
value = pair.getValue();
} else {
// 键值对被过滤
return this;
}
}
final boolean ignoreNullValue = this.config.isIgnoreNullValue();
if (ObjectUtil.isNull(value) && ignoreNullValue) {
// 忽略值模式下如果值为空清除key
this.remove(key);
} else {
if (checkDuplicate && containsKey(key)) {
throw new JSONException("Duplicate key \"{}\"", key);
}
super.put(key, JSONUtil.wrap(InternalJSONUtil.testValidity(value), this.config));
}
return this;
}
/**
* Put keynull
*
* @param key
* @param value : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return this.
* @throws JSONException
*/
public JSONObject putOnce(String key, Object value) throws JSONException {
return setOnce(key, value, null);
}
/**
* Put keynull
*
* @param key
* @param value : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @param filter {@code null}
* @return this
* @throws JSONException
* @since 5.8.0
*/
public JSONObject setOnce(String key, Object value, Filter<MutablePair<String, Object>> filter) throws JSONException {
return set(key, value, filter, true);
}
/**
* putJSONObject
*
* @param key
* @param value : Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return this.
* @throws JSONException
*/
public JSONObject putOpt(String key, Object value) throws JSONException {
if (key != null && value != null) {
this.set(key, value);
}
return this;
}
@Override
public void putAll(Map<? extends String, ?> m) {
for (Entry<? extends String, ?> entry : m.entrySet()) {
this.set(entry.getKey(), entry.getValue());
}
}
/**
* setkeyvaluevalueJSONArray. <br>
* valueJSONArray
*
* @param key
* @param value
* @return this.
* @throws JSONException {@code null}JSONArray
*/
public JSONObject accumulate(String key, Object value) throws JSONException {
InternalJSONUtil.testValidity(value);
Object object = this.getObj(key);
if (object == null) {
this.set(key, value);
} else if (object instanceof JSONArray) {
((JSONArray) object).set(value);
} else {
this.set(key, JSONUtil.createArray(this.config).set(object).set(value));
}
return this;
}
/**
* keyJSONArrayvalueJSONArrayJSONArray
*
* @param key
* @param value
* @return this.
* @throws JSONException {@code null}JSONArray
*/
public JSONObject append(String key, Object value) throws JSONException {
InternalJSONUtil.testValidity(value);
Object object = this.getObj(key);
if (object == null) {
this.set(key, new JSONArray(this.config).set(value));
} else if (object instanceof JSONArray) {
this.set(key, ((JSONArray) object).set(value));
} else {
throw new JSONException("JSONObject [" + key + "] is not a JSONArray.");
}
return this;
}
/**
* 1
*
* @param key A key string.
* @return this.
* @throws JSONException Integer, Long, Double, Float.
*/
public JSONObject increment(String key) throws JSONException {
Object value = this.getObj(key);
if (value == null) {
this.set(key, 1);
} else if (value instanceof BigInteger) {
this.set(key, ((BigInteger) value).add(BigInteger.ONE));
} else if (value instanceof BigDecimal) {
this.set(key, ((BigDecimal) value).add(BigDecimal.ONE));
} else if (value instanceof Integer) {
this.set(key, (Integer) value + 1);
} else if (value instanceof Long) {
this.set(key, (Long) value + 1);
} else if (value instanceof Double) {
this.set(key, (Double) value + 1);
} else if (value instanceof Float) {
this.set(key, (Float) value + 1);
} else {
throw new JSONException("Unable to increment [" + JSONUtil.quote(key) + "].");
}
return this;
}
/**
* JSON<br>
* {@code null}
*
* @return JSON
*/
@Override
public String toString() {
return this.toJSONString(0);
}
/**
* JSON<br>
*
*
* @param indentFactor
* @param filter
* @return JSON
* @since 5.7.15
*/
public String toJSONString(int indentFactor, Filter<MutablePair<Object, Object>> filter) {
final StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
return this.write(sw, indentFactor, 0, filter).toString();
}
}
@Override
public Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
return write(writer, indentFactor, indent, null);
}
/**
* JSONWriter<br>
*
*
* @param writer writer
* @param indentFactor
* @param indent
* @param filter
* @return Writer
* @throws JSONException JSON
* @since 5.7.15
*/
public Writer write(Writer writer, int indentFactor, int indent, Filter<MutablePair<Object, Object>> filter) throws JSONException {
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config)
.beginObj();
this.forEach((key, value) -> jsonWriter.writeField(new MutablePair<>(key, value), filter));
jsonWriter.end();
// 此处不关闭Writer考虑writer后续还需要填内容
return writer;
}
@Override
public JSONObject clone() throws CloneNotSupportedException {
final JSONObject clone = (JSONObject) super.clone();
clone.config = this.config;
return clone;
}
}

View File

@ -0,0 +1,41 @@
package aiyh.utils.tool.cn.hutool.json;
import java.util.Iterator;
/**
* JSONAray便JSONObjectIterableforeach
*
* @author looly
* @since 4.0.12
*/
public class JSONObjectIter implements Iterable<JSONObject> {
Iterator<Object> iterator;
public JSONObjectIter(Iterator<Object> iterator) {
this.iterator = iterator;
}
@Override
public Iterator<JSONObject> iterator() {
return new Iterator<JSONObject>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public JSONObject next() {
return (JSONObject) iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
};
}
}

View File

@ -0,0 +1,139 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.lang.Filter;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.Mutable;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutablePair;
/**
* JSON
*
* @author looly
* @since 5.8.0
*/
public class JSONParser {
/**
* JSONParser
*
* @param tokener {@link JSONTokener}
* @return JSONParser
*/
public static JSONParser of(JSONTokener tokener) {
return new JSONParser(tokener);
}
private final JSONTokener tokener;
/**
*
*
* @param tokener {@link JSONTokener}
*/
public JSONParser(JSONTokener tokener) {
this.tokener = tokener;
}
// region parseTo
/**
* {@link JSONTokener}{@link JSONObject}
*
* @param jsonObject {@link JSONObject}
* @param filter {@code null}
*/
public void parseTo(JSONObject jsonObject, Filter<MutablePair<String, Object>> filter) {
final JSONTokener tokener = this.tokener;
if (tokener.nextClean() != '{') {
throw tokener.syntaxError("A JSONObject text must begin with '{'");
}
char prev;
char c;
String key;
while (true) {
prev = tokener.getPrevious();
c = tokener.nextClean();
switch (c) {
case 0:
throw tokener.syntaxError("A JSONObject text must end with '}'");
case '}':
return;
case '{':
case '[':
if (prev == '{') {
throw tokener.syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray.");
}
default:
tokener.back();
key = tokener.nextValue().toString();
}
// The key is followed by ':'.
c = tokener.nextClean();
if (c != ':') {
throw tokener.syntaxError("Expected a ':' after a key");
}
jsonObject.set(key, tokener.nextValue(), filter, jsonObject.getConfig().isCheckDuplicate());
// Pairs are separated by ','.
switch (tokener.nextClean()) {
case ';':
case ',':
if (tokener.nextClean() == '}') {
// issue#2380
// 尾后逗号Trailing CommasJSON中虽然不支持但是ECMAScript 2017支持此处做兼容。
return;
}
tokener.back();
break;
case '}':
return;
default:
throw tokener.syntaxError("Expected a ',' or '}'");
}
}
}
/**
* JSON{@link JSONArray}
*
* @param jsonArray {@link .JSONArray}
* @param filter {@code null}
*/
public void parseTo(JSONArray jsonArray, Filter<Mutable<Object>> filter) {
final JSONTokener x = this.tokener;
if (x.nextClean() != '[') {
throw x.syntaxError("A JSONArray text must start with '['");
}
if (x.nextClean() != ']') {
x.back();
for (; ; ) {
if (x.nextClean() == ',') {
x.back();
jsonArray.addRaw(JSONNull.NULL, filter);
} else {
x.back();
jsonArray.addRaw(x.nextValue(), filter);
}
switch (x.nextClean()) {
case ',':
if (x.nextClean() == ']') {
return;
}
x.back();
break;
case ']':
return;
default:
throw x.syntaxError("Expected a ',' or ']'");
}
}
}
}
// endregion
}

View File

@ -0,0 +1,140 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.util.CharUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
/**
* JSONJSON<br>
* from http://blog.csdn.net/lovelong8808/article/details/54580278
*
* @author looly
* @since 3.1.2
*/
public class JSONStrFormatter {
/**
*
*/
private static final String SPACE = " ";
/**
*
*/
private static final char NEW_LINE = StrUtil.C_LF;
/**
* JSON
*
* @param json JSON
* @return JSON
*/
public static String format(String json) {
final StringBuilder result = new StringBuilder();
Character wrapChar = null;
boolean isEscapeMode = false;
int length = json.length();
int number = 0;
char key;
for (int i = 0; i < length; i++) {
key = json.charAt(i);
if (CharUtil.DOUBLE_QUOTES == key || CharUtil.SINGLE_QUOTE == key) {
if (null == wrapChar) {
// 字符串模式开始
wrapChar = key;
} else if (isEscapeMode) {
// 在字符串模式下的转义
isEscapeMode = false;
} else if (wrapChar.equals(key)) {
// 字符串包装结束
wrapChar = null;
}
if ((i > 1) && (json.charAt(i - 1) == CharUtil.COLON)) {
result.append(CharUtil.SPACE);
}
result.append(key);
continue;
}
if (CharUtil.BACKSLASH == key) {
if (null != wrapChar) {
// 字符串模式下转义有效
isEscapeMode = !isEscapeMode;
result.append(key);
continue;
} else {
result.append(key);
}
}
if (null != wrapChar) {
// 字符串模式
result.append(key);
continue;
}
// 如果当前字符是前方括号、前花括号做如下处理:
if ((key == CharUtil.BRACKET_START) || (key == CharUtil.DELIM_START)) {
// 如果前面还有字符,并且字符为“:”,打印:换行和缩进字符字符串。
if ((i > 1) && (json.charAt(i - 1) == CharUtil.COLON)) {
result.append(NEW_LINE);
result.append(indent(number));
}
result.append(key);
// 前方括号、前花括号,的后面必须换行。打印:换行。
result.append(NEW_LINE);
// 每出现一次前方括号、前花括号;缩进次数增加一次。打印:新行缩进。
number++;
result.append(indent(number));
continue;
}
// 3、如果当前字符是后方括号、后花括号做如下处理
if ((key == CharUtil.BRACKET_END) || (key == CharUtil.DELIM_END)) {
// 1后方括号、后花括号的前面必须换行。打印换行。
result.append(NEW_LINE);
// 2每出现一次后方括号、后花括号缩进次数减少一次。打印缩进。
number--;
result.append(indent(number));
// 3打印当前字符。
result.append(key);
// 4如果当前字符后面还有字符并且字符不为“打印换行。
// if (((i + 1) < length) && (json.charAt(i + 1) != ',')) {
// result.append(NEW_LINE);
// }
// 5继续下一次循环。
continue;
}
// 4、如果当前字符是逗号。逗号后面换行并缩进不改变缩进次数。
if ((key == ',')) {
result.append(key);
result.append(NEW_LINE);
result.append(indent(number));
continue;
}
if ((i > 1) && (json.charAt(i - 1) == CharUtil.COLON)) {
result.append(CharUtil.SPACE);
}
// 5、打印当前字符。
result.append(key);
}
return result.toString();
}
/**
* 4SPACE
*
* @param number
* @return
*/
private static String indent(int number) {
return StrUtil.repeat(SPACE, number);
}
}

View File

@ -0,0 +1,17 @@
package aiyh.utils.tool.cn.hutool.json;
/**
* {@code JSONString}{@code toJSONString()}<br>
* {@code toJSONString()}JSON
*
* @author Looly
*/
public interface JSONString {
/**
* JSON
*
* @return JSON
*/
String toJSONString();
}

View File

@ -0,0 +1,58 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.BeanUtil;
/**
* JSON<br>
* JSON
*
* @author Looly
*/
public class JSONSupport implements JSONString, JSONBeanParser<JSON> {
/**
* JSON StringBean
*
* @param jsonString JSON String
*/
public void parse(String jsonString) {
parse(new JSONObject(jsonString));
}
/**
* JSONBean
*
* @param json JSON
*/
@Override
public void parse(JSON json) {
final JSONSupport support = JSONConverter.jsonToBean(getClass(), json, false);
BeanUtil.copyProperties(support, this);
}
/**
* @return JSON
*/
public JSONObject toJSON() {
return new JSONObject(this);
}
@Override
public String toJSONString() {
return toJSON().toString();
}
/**
* JSON使JSONdebug
*
* @return JSON
*/
public String toPrettyString() {
return toJSON().toStringPretty();
}
@Override
public String toString() {
return toJSONString();
}
}

View File

@ -0,0 +1,458 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.io.*;
/**
* JSONJSONJSONObjectJSONArray
*
* @author from JSON.org
*/
public class JSONTokener {
private long character;
/**
* End of stream
*/
private boolean eof;
/**
* Reader
*/
private long index;
/**
*
*/
private long line;
/**
*
*/
private char previous;
/**
* 使
*/
private boolean usePrevious;
/**
*
*/
private final Reader reader;
/**
* JSON
*/
private final JSONConfig config;
// ------------------------------------------------------------------------------------ Constructor start
/**
* Reader
*
* @param reader Reader
* @param config JSON
*/
public JSONTokener(Reader reader, JSONConfig config) {
this.reader = reader.markSupported() ? reader : new BufferedReader(reader);
this.eof = false;
this.usePrevious = false;
this.previous = 0;
this.index = 0;
this.character = 1;
this.line = 1;
this.config = config;
}
/**
* InputStream使UTF-8
*
* @param inputStream InputStream
* @param config JSON
*/
public JSONTokener(InputStream inputStream, JSONConfig config) throws JSONException {
this(IoUtil.getUtf8Reader(inputStream), config);
}
/**
*
*
* @param s JSON
* @param config JSON
*/
public JSONTokener(CharSequence s, JSONConfig config) {
this(new StringReader(StrUtil.str(s)), config);
}
// ------------------------------------------------------------------------------------ Constructor end
/**
* 退JSON
*/
public void back() throws JSONException {
if (this.usePrevious || this.index <= 0) {
throw new JSONException("Stepping back two steps is not supported");
}
this.index -= 1;
this.character -= 1;
this.usePrevious = true;
this.eof = false;
}
/**
* @return
*/
public boolean end() {
return this.eof && !this.usePrevious;
}
/**
*
*
* @return truefalse
*/
public boolean more() throws JSONException {
this.next();
if (this.end()) {
return false;
}
this.back();
return true;
}
/**
*
*
* @return , or 0 if past the end of the source string.
* @throws JSONException JSONIO
*/
public char next() throws JSONException {
int c;
if (this.usePrevious) {
this.usePrevious = false;
c = this.previous;
} else {
try {
c = this.reader.read();
} catch (IOException exception) {
throw new JSONException(exception);
}
if (c <= 0) { // End of stream
this.eof = true;
c = 0;
}
}
this.index += 1;
if (this.previous == '\r') {
this.line += 1;
this.character = c == '\n' ? 0 : 1;
} else if (c == '\n') {
this.line += 1;
this.character = 0;
} else {
this.character += 1;
}
this.previous = (char) c;
return this.previous;
}
/**
* Get the last character read from the input or '\0' if nothing has been read yet.
*
* @return the last character read from the input.
*/
protected char getPrevious() {
return this.previous;
}
/**
*
*
* @param c
* @return The character
* @throws JSONException
*/
public char next(char c) throws JSONException {
char n = this.next();
if (n != c) {
throw this.syntaxError("Expected '" + c + "' and instead saw '" + n + "'");
}
return n;
}
/**
* n
*
* @param n
* @return n
* @throws JSONException
*/
public String next(int n) throws JSONException {
if (n == 0) {
return "";
}
char[] chars = new char[n];
int pos = 0;
while (pos < n) {
chars[pos] = this.next();
if (this.end()) {
throw this.syntaxError("Substring bounds error");
}
pos += 1;
}
return new String(chars);
}
/**
*
*
* @return 0
* @throws JSONException
*/
public char nextClean() throws JSONException {
char c;
while (true) {
c = this.next();
if (c == 0 || c > ' ') {
return c;
}
}
}
/**
* <br>
* JSON使
*
* @param quote , {@code "} {@code '}
* @return
* @throws JSONException
*/
public String nextString(char quote) throws JSONException {
char c;
StringBuilder sb = new StringBuilder();
while (true) {
c = this.next();
switch (c) {
case 0:
case '\n':
case '\r':
throw this.syntaxError("Unterminated string");
case '\\':// 转义符
c = this.next();
switch (c) {
case 'b':
sb.append('\b');
break;
case 't':
sb.append('\t');
break;
case 'n':
sb.append('\n');
break;
case 'f':
sb.append('\f');
break;
case 'r':
sb.append('\r');
break;
case 'u':// Unicode符
sb.append((char) Integer.parseInt(this.next(4), 16));
break;
case '"':
case '\'':
case '\\':
case '/':
sb.append(c);
break;
default:
throw this.syntaxError("Illegal escape.");
}
break;
default:
if (c == quote) {
return sb.toString();
}
sb.append(c);
}
}
}
/**
* Get the text up but not including the specified character or the end of line, whichever comes first. <br>
*
*
* @param delimiter
* @return
*/
public String nextTo(char delimiter) throws JSONException {
StringBuilder sb = new StringBuilder();
for (; ; ) {
char c = this.next();
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
if (c != 0) {
this.back();
}
return sb.toString().trim();
}
sb.append(c);
}
}
/**
* Get the text up but not including one of the specified delimiter characters or the end of line, whichever comes first.
*
* @param delimiters A set of delimiter characters.
* @return A string, trimmed.
*/
public String nextTo(String delimiters) throws JSONException {
char c;
StringBuilder sb = new StringBuilder();
for (; ; ) {
c = this.next();
if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') {
if (c != 0) {
this.back();
}
return sb.toString().trim();
}
sb.append(c);
}
}
/**
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL
*
* @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL
* @throws JSONException
*/
public Object nextValue() throws JSONException {
char c = this.nextClean();
String string;
switch (c) {
case '"':
case '\'':
return this.nextString(c);
case '{':
this.back();
try {
return new JSONObject(this, this.config);
} catch (final StackOverflowError e) {
throw new JSONException("JSONObject depth too large to process.", e);
}
case '[':
this.back();
try {
return new JSONArray(this, this.config);
} catch (final StackOverflowError e) {
throw new JSONException("JSONArray depth too large to process.", e);
}
}
/*
* Handle unquoted text. This could be the values true, false, or null, or it can be a number.
* An implementation (such as this one) is allowed to also accept non-standard forms. Accumulate
* characters until we reach the end of the text or a formatting character.
*/
final StringBuilder sb = new StringBuilder();
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
sb.append(c);
c = this.next();
}
this.back();
string = sb.toString().trim();
if (0 == string.length()) {
throw this.syntaxError("Missing value");
}
return InternalJSONUtil.stringToValue(string);
}
/**
* Skip characters until the next character is the requested character. If the requested character is not found, no characters are skipped.
*
* @param to
* @return 0
*/
public char skipTo(char to) throws JSONException {
char c;
try {
long startIndex = this.index;
long startCharacter = this.character;
long startLine = this.line;
this.reader.mark(1000000);
do {
c = this.next();
if (c == 0) {
this.reader.reset();
this.index = startIndex;
this.character = startCharacter;
this.line = startLine;
return c;
}
} while (c != to);
} catch (IOException exception) {
throw new JSONException(exception);
}
this.back();
return c;
}
/**
* Make a JSONException to signal a syntax error. <br>
* JSONException
*
* @param message
* @return A JSONException object, suitable for throwing
*/
public JSONException syntaxError(String message) {
return new JSONException(message + this);
}
/**
* {@link JSONArray}
*
* @return {@link JSONArray}
*/
public JSONArray toJSONArray() {
JSONArray jsonArray = new JSONArray(this.config);
if (this.nextClean() != '[') {
throw this.syntaxError("A JSONArray text must start with '['");
}
if (this.nextClean() != ']') {
this.back();
while (true) {
if (this.nextClean() == ',') {
this.back();
jsonArray.add(JSONNull.NULL);
} else {
this.back();
jsonArray.add(this.nextValue());
}
switch (this.nextClean()) {
case ',':
if (this.nextClean() == ']') {
return jsonArray;
}
this.back();
break;
case ']':
return jsonArray;
default:
throw this.syntaxError("Expected a ',' or ']'");
}
}
}
return jsonArray;
}
/**
* Make a printable string of this JSONTokener.
*
* @return " at {index} [character {character} line {line}]"
*/
@Override
public String toString() {
return " at " + this.index + " [character " + this.character + " line " + this.line + "]";
}
}

View File

@ -0,0 +1,983 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
import aiyh.utils.tool.cn.hutool.core.io.file.FileReader;
import aiyh.utils.tool.cn.hutool.core.lang.TypeReference;
import aiyh.utils.tool.cn.hutool.core.map.MapWrapper;
import aiyh.utils.tool.cn.hutool.core.util.*;
import aiyh.utils.tool.cn.hutool.json.serialize.GlobalSerializeMapping;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONArraySerializer;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONDeserializer;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONObjectSerializer;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.time.temporal.TemporalAccessor;
import java.util.*;
/**
* JSON
*
* @author Looly
*/
public class JSONUtil {
// -------------------------------------------------------------------- Pause start
/**
* JSONObject
*
* @return JSONObject
*/
public static JSONObject createObj() {
return new JSONObject();
}
/**
* JSONObject
*
* @param config JSON
* @return JSONObject
* @since 5.2.5
*/
public static JSONObject createObj(JSONConfig config) {
return new JSONObject(config);
}
/**
* JSONArray
*
* @return JSONArray
*/
public static JSONArray createArray() {
return new JSONArray();
}
/**
* JSONArray
*
* @param config JSON
* @return JSONArray
* @since 5.2.5
*/
public static JSONArray createArray(JSONConfig config) {
return new JSONArray(config);
}
/**
* JSONJSONObject
*
* @param jsonStr JSON
* @return JSONObject
*/
public static JSONObject parseObj(String jsonStr) {
return new JSONObject(jsonStr);
}
/**
* JSONJSONObject<br>
* JSON
*
* @param obj BeanMap
* @return JSONObject
*/
public static JSONObject parseObj(Object obj) {
return parseObj(obj, null);
}
/**
* JSONJSONObject<br>
* JSON
*
* @param obj BeanMap
* @param config JSON
* @return JSONObject
* @since 5.3.1
*/
public static JSONObject parseObj(Object obj, JSONConfig config) {
return new JSONObject(obj, ObjectUtil.defaultIfNull(config, JSONConfig::create));
}
/**
* JSONJSONObject
*
* @param obj BeanMap
* @param ignoreNullValue sourceJSON
* @return JSONObject
* @since 3.0.9
*/
public static JSONObject parseObj(Object obj, boolean ignoreNullValue) {
return new JSONObject(obj, ignoreNullValue);
}
/**
* JSONJSONObject
*
* @param obj BeanMap
* @param ignoreNullValue sourceJSON
* @param isOrder
* @return JSONObject
* @since 4.2.2
* @deprecated isOrder
*/
@SuppressWarnings("unused")
@Deprecated
public static JSONObject parseObj(Object obj, boolean ignoreNullValue, boolean isOrder) {
return new JSONObject(obj, ignoreNullValue);
}
/**
* JSONJSONArray
*
* @param jsonStr JSON
* @return JSONArray
*/
public static JSONArray parseArray(String jsonStr) {
return new JSONArray(jsonStr);
}
/**
* JSONJSONArray
*
* @param arrayOrCollection
* @return JSONArray
* @since 3.0.8
*/
public static JSONArray parseArray(Object arrayOrCollection) {
return parseArray(arrayOrCollection, null);
}
/**
* JSONJSONArray
*
* @param arrayOrCollection
* @param config JSON
* @return JSONArray
* @since 5.3.1
*/
public static JSONArray parseArray(Object arrayOrCollection, JSONConfig config) {
return new JSONArray(arrayOrCollection, config);
}
/**
* JSONJSONArray
*
* @param arrayOrCollection
* @param ignoreNullValue
* @return JSONArray
* @since 3.2.3
*/
public static JSONArray parseArray(Object arrayOrCollection, boolean ignoreNullValue) {
return new JSONArray(arrayOrCollection, ignoreNullValue);
}
/**
* JSONJSONConfigJSON<br>
*
* <ul>
* <li>String: </li>
* <li>ArrayIterableIteratorJSONArray</li>
* <li>BeanJSONObject</li>
* </ul>
*
* @param obj
* @return JSON
*/
public static JSON parse(Object obj) {
return parse(obj, null);
}
/**
* JSONJSONConfigJSON<br>
*
* <ul>
* <li>String: </li>
* <li>ArrayIterableIteratorJSONArray</li>
* <li>BeanJSONObject</li>
* </ul>
*
* @param obj
* @param config JSON{@code null}使
* @return JSON
* @since 5.3.1
*/
public static JSON parse(Object obj, JSONConfig config) {
if (null == obj) {
return null;
}
JSON json;
if (obj instanceof JSON) {
json = (JSON) obj;
} else if (obj instanceof CharSequence) {
final String jsonStr = StrUtil.trim((CharSequence) obj);
json = isTypeJSONArray(jsonStr) ? parseArray(jsonStr, config) : parseObj(jsonStr, config);
} else if (obj instanceof MapWrapper) {
// MapWrapper实现了Iterable会被当作JSONArray此处做修正
json = parseObj(obj, config);
} else if (obj instanceof Iterable || obj instanceof Iterator || ArrayUtil.isArray(obj)) {// 列表
json = parseArray(obj, config);
} else {// 对象
json = parseObj(obj, config);
}
return json;
}
/**
* XMLJSONObject
*
* @param xmlStr XML
* @return JSONObject
*/
public static JSONObject parseFromXml(String xmlStr) {
return XML.toJSONObject(xmlStr);
}
// -------------------------------------------------------------------- Parse end
// -------------------------------------------------------------------- Read start
/**
* JSON
*
* @param file JSON
* @param charset
* @return JSONJSONObjectJSONArray
* @throws IORuntimeException IO
*/
public static JSON readJSON(File file, Charset charset) throws IORuntimeException {
return parse(FileReader.create(file, charset).readString());
}
/**
* JSONObject
*
* @param file JSON
* @param charset
* @return JSONObject
* @throws IORuntimeException IO
*/
public static JSONObject readJSONObject(File file, Charset charset) throws IORuntimeException {
return parseObj(FileReader.create(file, charset).readString());
}
/**
* JSONArray
*
* @param file JSON
* @param charset
* @return JSONArray
* @throws IORuntimeException IO
*/
public static JSONArray readJSONArray(File file, Charset charset) throws IORuntimeException {
return parseArray(FileReader.create(file, charset).readString());
}
// -------------------------------------------------------------------- Read end
// -------------------------------------------------------------------- toString start
/**
* JSON
*
* @param json JSON
* @param indentFactor
* @return JSON
*/
public static String toJsonStr(JSON json, int indentFactor) {
if (null == json) {
return null;
}
return json.toJSONString(indentFactor);
}
/**
* JSON
*
* @param json JSON
* @return JSON
*/
public static String toJsonStr(JSON json) {
if (null == json) {
return null;
}
return json.toJSONString(0);
}
/**
* JSONwrite
*
* @param json JSON
* @param writer Writer
* @since 5.3.3
*/
public static void toJsonStr(JSON json, Writer writer) {
if (null != json) {
json.write(writer);
}
}
/**
* JSON
*
* @param json JSON
* @return JSON
*/
public static String toJsonPrettyStr(JSON json) {
if (null == json) {
return null;
}
return json.toJSONString(4);
}
/**
* JSON
*
* @param obj JSON
* @return JSON
*/
public static String toJsonStr(Object obj) {
return toJsonStr(obj, (JSONConfig) null);
}
/**
* JSON
*
* @param obj JSON
* @param jsonConfig JSON
* @return JSON
* @since 5.7.12
*/
public static String toJsonStr(Object obj, JSONConfig jsonConfig) {
if (null == obj) {
return null;
}
if (obj instanceof CharSequence) {
return StrUtil.str((CharSequence) obj);
}
return toJsonStr(parse(obj, jsonConfig));
}
/**
* JSONwriter
*
* @param obj JSON
* @param writer Writer
* @since 5.3.3
*/
public static void toJsonStr(Object obj, Writer writer) {
if (null != obj) {
toJsonStr(parse(obj), writer);
}
}
/**
* JSON
*
* @param obj Bean
* @return JSON
*/
public static String toJsonPrettyStr(Object obj) {
return toJsonPrettyStr(parse(obj));
}
/**
* XML
*
* @param json JSON
* @return XML
*/
public static String toXmlStr(JSON json) {
return XML.toXml(json);
}
// -------------------------------------------------------------------- toString end
// -------------------------------------------------------------------- toBean start
/**
* JSON
*
* @param <T> Bean
* @param jsonString JSON
* @param beanClass
* @return
* @since 3.1.2
*/
public static <T> T toBean(String jsonString, Class<T> beanClass) {
return toBean(parseObj(jsonString), beanClass);
}
/**
* JSON<br>
* {@link JSONConfig}null
*
* @param <T> Bean
* @param jsonString JSON
* @param config JSON
* @param beanClass
* @return
* @since 5.8.0
*/
public static <T> T toBean(String jsonString, JSONConfig config, Class<T> beanClass) {
return toBean(parseObj(jsonString, config), beanClass);
}
/**
*
*
* @param <T> Bean
* @param json JSONObject
* @param beanClass
* @return
*/
public static <T> T toBean(JSONObject json, Class<T> beanClass) {
return null == json ? null : json.toBean(beanClass);
}
/**
* JSON
*
* @param <T> Bean
* @param jsonString JSON
* @param typeReference {@link TypeReference}Type
* @param ignoreError
* @return
* @since 4.3.2
*/
public static <T> T toBean(String jsonString, TypeReference<T> typeReference, boolean ignoreError) {
return toBean(jsonString, typeReference.getType(), ignoreError);
}
/**
* JSON
*
* @param <T> Bean
* @param jsonString JSON
* @param beanType
* @param ignoreError
* @return
* @since 4.3.2
*/
public static <T> T toBean(String jsonString, Type beanType, boolean ignoreError) {
return parse(jsonString, JSONConfig.create().setIgnoreError(ignoreError)).toBean(beanType);
}
/**
*
*
* @param <T> Bean
* @param json JSONObject
* @param typeReference {@link TypeReference}Type
* @param ignoreError
* @return
* @since 4.6.2
*/
public static <T> T toBean(JSON json, TypeReference<T> typeReference, boolean ignoreError) {
return toBean(json, typeReference.getType(), ignoreError);
}
/**
*
*
* @param <T> Bean
* @param json JSONObject
* @param beanType
* @param ignoreError
* @return
* @since 4.3.2
*/
public static <T> T toBean(JSON json, Type beanType, boolean ignoreError) {
if (null == json) {
return null;
}
return json.toBean(beanType, ignoreError);
}
// -------------------------------------------------------------------- toBean end
/**
* JSONArrayBeanListArrayList
*
* @param <T> Bean
* @param jsonArray JSONArray
* @param elementType List
* @return List
* @since 5.5.2
*/
public static <T> List<T> toList(String jsonArray, Class<T> elementType) {
return toList(parseArray(jsonArray), elementType);
}
/**
* JSONArrayBeanListArrayList
*
* @param <T> Bean
* @param jsonArray {@link JSONArray}
* @param elementType List
* @return List
* @since 4.0.7
*/
public static <T> List<T> toList(JSONArray jsonArray, Class<T> elementType) {
return null == jsonArray ? null : jsonArray.toList(elementType);
}
/**
* JSON<br>
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param json {@link JSON}
* @param expression
* @return
* @see JSON#getByPath(String)
*/
public static Object getByPath(JSON json, String expression) {
return getByPath(json, expression, null);
}
/**
* JSON<br>
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param <T>
* @param json {@link JSON}
* @param expression
* @param defaultValue
* @return
* @see JSON#getByPath(String)
* @since 5.6.0
*/
@SuppressWarnings("unchecked")
public static <T> T getByPath(JSON json, String expression, T defaultValue) {
if ((null == json || StrUtil.isBlank(expression))) {
return defaultValue;
}
if (null != defaultValue) {
final Class<T> type = (Class<T>) defaultValue.getClass();
return ObjectUtil.defaultIfNull(json.getByPath(expression, type), defaultValue);
}
return (T) json.getByPath(expression);
}
/**
* filed<br>
* JSONArrayJSONObjectputkey<br>
* JSONArrayJSONArray<br>
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param json JSONJSONObjectJSONArray
* @param expression
* @param value
*/
public static void putByPath(JSON json, String expression, Object value) {
json.putByPath(expression, value);
}
/**
* 使<br>
* HTML&lt;/&lt;\/<br>
* JSON
*
* @param string
* @return JSON
*/
public static String quote(String string) {
return quote(string, true);
}
/**
* 使<br>
* HTML&lt;/&lt;\/<br>
* JSON
*
* @param string
* @param isWrap 使
* @return JSON
* @since 3.3.1
*/
public static String quote(String string, boolean isWrap) {
StringWriter sw = new StringWriter();
try {
return quote(string, sw, isWrap).toString();
} catch (IOException ignored) {
// will never happen - we are writing to a string writer
return StrUtil.EMPTY;
}
}
/**
* 使<br>
* HTML&lt;/&lt;\/<br>
* JSON
*
* @param str
* @param writer Writer
* @return Writer
* @throws IOException IO
*/
public static Writer quote(String str, Writer writer) throws IOException {
return quote(str, writer, true);
}
/**
* 使<br>
* HTML&lt;/&lt;\/<br>
* JSON
*
* @param str
* @param writer Writer
* @param isWrap 使
* @return Writer
* @throws IOException IO
* @since 3.3.1
*/
public static Writer quote(String str, Writer writer, boolean isWrap) throws IOException {
if (StrUtil.isEmpty(str)) {
if (isWrap) {
writer.write("\"\"");
}
return writer;
}
char c; // 当前字符
int len = str.length();
if (isWrap) {
writer.write('"');
}
for (int i = 0; i < len; i++) {
c = str.charAt(i);
switch (c) {
case '\\':
case '"':
writer.write("\\");
writer.write(c);
break;
default:
writer.write(escape(c));
}
}
if (isWrap) {
writer.write('"');
}
return writer;
}
/**
*
*
* @param str
* @return
*/
public static String escape(String str) {
if (StrUtil.isEmpty(str)) {
return str;
}
final int len = str.length();
final StringBuilder builder = new StringBuilder(len);
char c;
for (int i = 0; i < len; i++) {
c = str.charAt(i);
builder.append(escape(c));
}
return builder.toString();
}
/**
* <br>
*
* <ul>
* <li>{@code null} = {@code JSONNull.NULL}</li>
* <li>array or collection = JSONArray</li>
* <li>map = JSONObject</li>
* <li>standard property (Double, String, et al) = </li>
* <li>java = </li>
* <li> = JSONObject{@code null}</li>
* </ul>
*
* @param object
* @param jsonConfig JSON
* @return null
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static Object wrap(Object object, JSONConfig jsonConfig) {
if (object == null) {
return jsonConfig.isIgnoreNullValue() ? null : JSONNull.NULL;
}
if (object instanceof JSON //
|| ObjectUtil.isNull(object) //
|| object instanceof JSONString //
|| object instanceof CharSequence //
|| object instanceof Number //
|| ObjectUtil.isBasicType(object) //
) {
return object;
}
try {
// fix issue#1399@Github
if (object instanceof SQLException) {
return object.toString();
}
// JSONArray
if (object instanceof Iterable || ArrayUtil.isArray(object)) {
return new JSONArray(object, jsonConfig);
}
// JSONObject
if (object instanceof Map || object instanceof Map.Entry) {
return new JSONObject(object, jsonConfig);
}
// 日期类型原样保存,便于格式化
if (object instanceof Date
|| object instanceof Calendar
|| object instanceof TemporalAccessor
) {
return object;
}
// 枚举类保存其字符串形式4.0.2新增)
if (object instanceof Enum) {
return object.toString();
}
// Java内部类不做转换
if (ClassUtil.isJdkClass(object.getClass())) {
return object.toString();
}
// 默认按照JSONObject对待
return new JSONObject(object, jsonConfig);
} catch (final Exception exception) {
return null;
}
}
/**
* JSONJSON
*
* @param jsonStr JSON
* @return
* @since 3.1.2
*/
public static String formatJsonStr(String jsonStr) {
return JSONStrFormatter.format(jsonStr);
}
/**
* JSONJSON
*
* @param str
* @return JSON
* @since 3.3.0
* @deprecated 使 {@link #isTypeJSON(String)}
*/
@Deprecated
public static boolean isJson(String str) {
return isTypeJSON(str);
}
/**
* JSONJSON
*
* @param str
* @return JSON
* @since 5.7.22
*/
public static boolean isTypeJSON(String str) {
return isTypeJSONObject(str) || isTypeJSONArray(str);
}
/**
* JSONObjectJSONObject
*
* @param str
* @return JSON
* @since 3.3.0
* @deprecated 使 {@link #isTypeJSONObject(String)}
*/
@Deprecated
public static boolean isJsonObj(String str) {
return isTypeJSONObject(str);
}
/**
* JSONObjectJSONObject
*
* @param str
* @return JSON
* @since 5.7.22
*/
public static boolean isTypeJSONObject(String str) {
if (StrUtil.isBlank(str)) {
return false;
}
return StrUtil.isWrap(StrUtil.trim(str), '{', '}');
}
/**
* JSONArrayJSONArray
*
* @param str
* @return JSON
* @since 3.3.0
* @deprecated 使 {@link #isTypeJSONArray(String)}
*/
@Deprecated
public static boolean isJsonArray(String str) {
return isTypeJSONArray(str);
}
/**
* JSONArrayJSONArray
*
* @param str
* @return JSONArray
* @since 5.7.22
*/
public static boolean isTypeJSONArray(String str) {
if (StrUtil.isBlank(str)) {
return false;
}
return StrUtil.isWrap(StrUtil.trim(str), '[', ']');
}
/**
* nullnull
*
* <pre>
* 1. {@code null}
* 2. {@link JSONNull}
* </pre>
*
* @param obj
* @return null
* @since 4.5.7
*/
public static boolean isNull(Object obj) {
return null == obj || obj instanceof JSONNull;
}
/**
* XMLJSONObject<br>
* JSONJSONArray
*
* @param xml XML
* @return JSONObject
* @since 4.0.8
*/
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 deserializer
* @see GlobalSerializeMapping#put(Type, JSONDeserializer)
* @since 4.6.5
*/
public static void putDeserializer(Type type, JSONDeserializer<?> deserializer) {
GlobalSerializeMapping.put(type, deserializer);
}
// --------------------------------------------------------------------------------------------- Private method start
/**
* <br>
* <a href="https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF">https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF</a>
*
* @param c
* @return
*/
private static String escape(char c) {
switch (c) {
case '\b':
return "\\b";
case '\t':
return "\\t";
case '\n':
return "\\n";
case '\f':
return "\\f";
case '\r':
return "\\r";
default:
if (c < StrUtil.C_SPACE || //
(c >= '\u0080' && c <= '\u00a0') || //
(c >= '\u2000' && c <= '\u2010') || //
(c >= '\u2028' && c <= '\u202F') || //
(c >= '\u2066' && c <= '\u206F')//
) {
return HexUtil.toUnicodeHex(c);
} else {
return Character.toString(c);
}
}
}
// --------------------------------------------------------------------------------------------- Private method end
}

View File

@ -0,0 +1,263 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.bean.BeanUtil;
import aiyh.utils.tool.cn.hutool.core.collection.ArrayIter;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.io.IoUtil;
import aiyh.utils.tool.cn.hutool.core.lang.Filter;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.Mutable;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutablePair;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import aiyh.utils.tool.cn.hutool.core.util.TypeUtil;
import aiyh.utils.tool.cn.hutool.json.serialize.GlobalSerializeMapping;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONObjectSerializer;
import aiyh.utils.tool.cn.hutool.json.serialize.JSONSerializer;
import java.io.InputStream;
import java.io.Reader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
/**
* JSONJSON
* <ul>
* <li>Map JSONObjectJSON</li>
* <li>Map.Entry JSONObject</li>
* <li>CharSequence JSONObject使JSONTokener</li>
* <li>{@link Reader} JSONObject使JSONTokener</li>
* <li>{@link InputStream} JSONObject使JSONTokener</li>
* <li>JSONTokener JSONObject</li>
* <li>ResourceBundle JSONObject</li>
* <li>Bean JSONObjectgettersgetXXXisXXXJSONJavaBeangetName()"张三"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 (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, jsonObject.getConfig().isCheckDuplicate());
}
} else if (source instanceof Map.Entry) {
final Map.Entry entry = (Map.Entry) source;
jsonObject.set(Convert.toStr(entry.getKey()), entry.getValue(), filter, jsonObject.getConfig().isCheckDuplicate());
} else if (source instanceof CharSequence) {
// 可能为JSON字符串
mapFromStr((CharSequence) source, jsonObject, filter);
} else if (source instanceof Reader) {
mapFromTokener(new JSONTokener((Reader) source, jsonObject.getConfig()), jsonObject, filter);
} else if (source instanceof InputStream) {
mapFromTokener(new JSONTokener((InputStream) source, jsonObject.getConfig()), jsonObject, filter);
} else if (source instanceof byte[]) {
mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source), jsonObject.getConfig()), 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 Reader) {
mapFromTokener(new JSONTokener((Reader) source, jsonArray.getConfig()), jsonArray, filter);
} else if (source instanceof InputStream) {
mapFromTokener(new JSONTokener((InputStream) source, jsonArray.getConfig()), jsonArray, filter);
} else if (source instanceof byte[]) {
final byte[] bytesSource = (byte[]) source;
// 如果是普通的的byte[], 要避免下标越界
if (bytesSource.length > 1 && '[' == bytesSource[0] && ']' == bytesSource[bytesSource.length - 1]) {
mapFromTokener(new JSONTokener(IoUtil.toStream(bytesSource), jsonArray.getConfig()), jsonArray, filter);
} else {
// https://github.com/dromara/hutool/issues/2369
// 非标准的二进制流,则按照普通数组对待
for (final byte b : bytesSource) {
jsonArray.add(b);
}
}
} 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()));
}
}

View File

@ -0,0 +1,140 @@
package aiyh.utils.tool.cn.hutool.json;
import aiyh.utils.tool.cn.hutool.core.util.CharUtil;
import aiyh.utils.tool.cn.hutool.json.xml.JSONXMLParser;
import aiyh.utils.tool.cn.hutool.json.xml.JSONXMLSerializer;
/**
* XMLJSONObject
*
* @author JSON.org, looly
* @see JSONXMLParser
* @see JSONXMLSerializer
*/
public class XML {
/**
* The Character '&amp;'.
*/
public static final Character AMP = CharUtil.AMP;
/**
* The Character '''.
*/
public static final Character APOS = CharUtil.SINGLE_QUOTE;
/**
* The Character '!'.
*/
public static final Character BANG = '!';
/**
* The Character '='.
*/
public static final Character EQ = '=';
/**
* The Character '&gt;'.
*/
public static final Character GT = '>';
/**
* The Character '&lt;'.
*/
public static final Character LT = '<';
/**
* The Character '?'.
*/
public static final Character QUEST = '?';
/**
* The Character '"'.
*/
public static final Character QUOT = CharUtil.DOUBLE_QUOTES;
/**
* The Character '/'.
*/
public static final Character SLASH = CharUtil.SLASH;
/**
* XMLJSONObject
* JSONJSONArray
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and {@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);
}
/**
* XMLJSONObject
* JSONJSONArray
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and {@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);
}
/**
* XMLJSONObject
* JSONJSONArray
*
* @param jo JSONObject
* @param xmlStr XML
* @param keepStrings {@code true}Stringboolean
* @return A JSONObject JSONjo
* @throws JSONException
* @since 5.3.1
*/
public static JSONObject toJSONObject(JSONObject jo, String xmlStr, boolean keepStrings) throws JSONException {
JSONXMLParser.parseJSONObject(jo, xmlStr, keepStrings);
return jo;
}
/**
* JSONObjectXML
*
* @param object JSON
* @return XML
* @throws JSONException JSON
*/
public static String toXml(Object object) throws JSONException {
return toXml(object, null);
}
/**
* JSONObjectXML
*
* @param object JSON
* @param tagName
* @return A string.
* @throws JSONException JSON
*/
public static String toXml(Object object, String tagName) throws JSONException {
return toXml(object, tagName, "content");
}
/**
* JSONObjectXML
*
* @param object JSON
* @param tagName
* @param contentKeys key,key
* @return A string.
* @throws JSONException JSON
*/
public static String toXml(Object object, String tagName, String... contentKeys) throws JSONException {
return JSONXMLSerializer.toXml(object, tagName, contentKeys);
}
}

View File

@ -0,0 +1,362 @@
package aiyh.utils.tool.cn.hutool.json;
/**
* XMLJSONTokenerXML
*
* @author JSON.org
*/
public class XMLTokener extends JSONTokener {
/**
* The table of entity values.
* It initially contains Character values for amp, apos, gt, lt, quot.
*/
public static final java.util.HashMap<String, Character> entity;
static {
entity = new java.util.HashMap<>(8);
entity.put("amp", XML.AMP);
entity.put("apos", XML.APOS);
entity.put("gt", XML.GT);
entity.put("lt", XML.LT);
entity.put("quot", XML.QUOT);
}
/**
* Construct an XMLTokener from a string.
*
* @param s A source string.
* @param config JSON
*/
public XMLTokener(CharSequence s, JSONConfig config) {
super(s, config);
}
/**
* Get the text in the CDATA block.
*
* @return The string up to the {@code ]]>}.
* @throws JSONException If the {@code ]]>} is not found.
*/
public String nextCDATA() throws JSONException {
char c;
int i;
final StringBuilder sb = new StringBuilder();
for (; ; ) {
c = next();
if (end()) {
throw syntaxError("Unclosed CDATA");
}
sb.append(c);
i = sb.length() - 3;
if (i >= 0 && sb.charAt(i) == ']' && sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
sb.setLength(i);
return sb.toString();
}
}
}
/**
* Get the next XML outer token, trimming whitespace.
* There are two kinds of tokens: the '&gt;' character which begins a markup tag, and the content text between markup tags.
*
* @return A string, or a '&gt;' Character, or null if there is no more source text.
* @throws JSONException JSON
*/
public Object nextContent() throws JSONException {
char c;
final StringBuilder sb;
do {
c = next();
} while (Character.isWhitespace(c));
if (c == 0) {
return null;
}
if (c == '<') {
return XML.LT;
}
sb = new StringBuilder();
for (; ; ) {
if (c == '<' || c == 0) {
back();
return sb.toString().trim();
}
if (c == '&') {
sb.append(nextEntity(c));
} else {
sb.append(c);
}
c = next();
}
}
/**
* Return the next entity. These entities are translated to Characters: {@code & ' > < "}.
*
* @param ampersand An ampersand character.
* @return A Character or an entity String if the entity is not recognized.
* @throws JSONException If missing ';' in XML entity.
*/
public Object nextEntity(char ampersand) throws JSONException {
final StringBuilder sb = new StringBuilder();
char c;
for (; ; ) {
c = next();
if (Character.isLetterOrDigit(c) || c == '#') {
sb.append(Character.toLowerCase(c));
} else if (c == ';') {
break;
} else {
throw syntaxError("Missing ';' in XML entity: &" + sb);
}
}
return unescapeEntity(sb.toString());
}
/**
* Unescape an XML entity encoding;
*
* @param e entity (only the actual entity value, not the preceding & or ending ;
* @return Unescape str
*/
static String unescapeEntity(final String e) {
// validate
if (e == null || e.isEmpty()) {
return "";
}
// if our entity is an encoded unicode point, parse it.
if (e.charAt(0) == '#') {
final int cp;
if (e.charAt(1) == 'x' || e.charAt(1) == 'X') {
// hex encoded unicode
cp = Integer.parseInt(e.substring(2), 16);
} else {
// decimal encoded unicode
cp = Integer.parseInt(e.substring(1));
}
return new String(new int[]{cp}, 0, 1);
}
final Character knownEntity = entity.get(e);
if (knownEntity == null) {
// we don't know the entity so keep it encoded
return '&' + e + ';';
}
return knownEntity.toString();
}
/**
* Returns the next XML meta token. This is used for skipping over &lt;!...&gt; and &lt;?...?&gt; structures.
*
* @return Syntax characters ({@code < > / = ! ?}) are returned as Character, and strings and names are returned as Boolean. We don't care what the values actually are.
* @throws JSONException XMLIf a string is not properly closed or if the XML is badly structured.
*/
public Object nextMeta() throws JSONException {
char c;
char q;
do {
c = next();
} while (Character.isWhitespace(c));
switch (c) {
case 0:
throw syntaxError("Misshaped meta tag");
case '<':
return XML.LT;
case '>':
return XML.GT;
case '/':
return XML.SLASH;
case '=':
return XML.EQ;
case '!':
return XML.BANG;
case '?':
return XML.QUEST;
case '"':
case '\'':
q = c;
for (; ; ) {
c = next();
if (c == 0) {
throw syntaxError("Unterminated string");
}
if (c == q) {
return Boolean.TRUE;
}
}
default:
for (; ; ) {
c = next();
if (Character.isWhitespace(c)) {
return Boolean.TRUE;
}
switch (c) {
case 0:
case '<':
case '>':
case '/':
case '=':
case '!':
case '?':
case '"':
case '\'':
back();
return Boolean.TRUE;
}
}
}
}
/**
* Get the next XML Token. These tokens are found inside of angle brackets. <br>
* It may be one of these characters: {@code / > = ! ?} or it may be a string wrapped in single quotes or double
* quotes, or it may be a name.
*
* @return a String or a Character.
* @throws JSONException If the XML is not well formed.
*/
public Object nextToken() throws JSONException {
char c;
char q;
StringBuilder sb;
do {
c = next();
} while (Character.isWhitespace(c));
switch (c) {
case 0:
throw syntaxError("Misshaped element");
case '<':
throw syntaxError("Misplaced '<'");
case '>':
return XML.GT;
case '/':
return XML.SLASH;
case '=':
return XML.EQ;
case '!':
return XML.BANG;
case '?':
return XML.QUEST;
// Quoted string
case '"':
case '\'':
q = c;
sb = new StringBuilder();
for (; ; ) {
c = next();
if (c == 0) {
throw syntaxError("Unterminated string");
}
if (c == q) {
return sb.toString();
}
if (c == '&') {
sb.append(nextEntity(c));
} else {
sb.append(c);
}
}
default:
// Name
sb = new StringBuilder();
for (; ; ) {
sb.append(c);
c = next();
if (Character.isWhitespace(c)) {
return sb.toString();
}
switch (c) {
case 0:
return sb.toString();
case '>':
case '/':
case '=':
case '!':
case '?':
case '[':
case ']':
back();
return sb.toString();
case '<':
case '"':
case '\'':
throw syntaxError("Bad character in a name");
}
}
}
}
/**
* Skip characters until past the requested string. If it is not found, we are left at the end of the source with a result of false.
*
* @param to A string to skip past.
* @return skip
* @throws JSONException JSON
*/
public boolean skipPast(String to) throws JSONException {
boolean b;
char c;
int i;
int j;
int offset = 0;
int length = to.length();
char[] circle = new char[length];
/*
* First fill the circle buffer with as many characters as are in the to string. If we reach an early end, bail.
*/
for (i = 0; i < length; i += 1) {
c = next();
if (c == 0) {
return false;
}
circle[i] = c;
}
/* We will loop, possibly for all of the remaining characters. */
for (; ; ) {
j = offset;
b = true;
/* Compare the circle buffer with the to string. */
for (i = 0; i < length; i += 1) {
if (circle[j] != to.charAt(i)) {
b = false;
break;
}
j += 1;
if (j >= length) {
j -= length;
}
}
/* If we exit the loop with b intact, then victory is ours. */
if (b) {
return true;
}
/* Get the next character. If there isn't one, then defeat is ours. */
c = next();
if (c == 0) {
return false;
}
/*
* Shove the character in the circle buffer and advance the circle offset. The offset is mod n.
*/
circle[offset] = c;
offset += 1;
if (offset >= length) {
offset -= length;
}
}
}
}

View File

@ -0,0 +1,6 @@
/**
* JSONjson.org
*
* @author looly
*/
package aiyh.utils.tool.cn.hutool.json;

View File

@ -0,0 +1,112 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.core.map.SafeConcurrentHashMap;
import aiyh.utils.tool.cn.hutool.json.JSON;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* <br>
* JSONJava使
*
* @author Looly
*/
public class GlobalSerializeMapping {
private static Map<Type, JSONSerializer<? extends JSON, ?>> serializerMap;
private static Map<Type, JSONDeserializer<?>> deserializerMap;
static {
serializerMap = new SafeConcurrentHashMap<>();
deserializerMap = new SafeConcurrentHashMap<>();
final TemporalAccessorSerializer localDateSerializer = new TemporalAccessorSerializer(LocalDate.class);
serializerMap.put(LocalDate.class, localDateSerializer);
deserializerMap.put(LocalDate.class, localDateSerializer);
final TemporalAccessorSerializer localDateTimeSerializer = new TemporalAccessorSerializer(LocalDateTime.class);
serializerMap.put(LocalDateTime.class, localDateTimeSerializer);
deserializerMap.put(LocalDateTime.class, localDateTimeSerializer);
final TemporalAccessorSerializer localTimeSerializer = new TemporalAccessorSerializer(LocalTime.class);
serializerMap.put(LocalTime.class, localTimeSerializer);
deserializerMap.put(LocalTime.class, localTimeSerializer);
}
/**
*
*
* @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 SafeConcurrentHashMap<>();
}
serializerMap.put(type, serializer);
}
/**
*
*
* @param type
* @param deserializer
*/
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);
}
}

View File

@ -0,0 +1,14 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.json.JSONArray;
/**
* JSON{@link JSONArray}
*
* @param <V>
* @author Looly
*/
@FunctionalInterface
public interface JSONArraySerializer<V> extends JSONSerializer<JSONArray, V> {
}

View File

@ -0,0 +1,22 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.json.JSON;
/**
* JSON
*
* @param <T>
* @author Looly
*/
@FunctionalInterface
public interface JSONDeserializer<T> {
/**
* JSON
*
* @param json {@link JSON}
* @return
*/
T deserialize(JSON json);
}

View File

@ -0,0 +1,14 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.json.JSONObject;
/**
* {@link JSONObject}
*
* @param <V>
* @author Looly
*/
@FunctionalInterface
public interface JSONObjectSerializer<V> extends JSONSerializer<JSONObject, V> {
}

View File

@ -0,0 +1,24 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.json.JSON;
/**
* JSON
*
* @param <T> JSONJSONObjectJSONArray
* @param <V>
* @author Looly
*/
@FunctionalInterface
public interface JSONSerializer<T extends JSON, V> {
/**
* {@link JSON}<br>
* JSONObjectJSONArraynewJSONputJSON
*
* @param json JSONJSONObjectJSONArray
* @param bean
*/
void serialize(T json, V bean);
}

View File

@ -0,0 +1,431 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.date.DateUtil;
import aiyh.utils.tool.cn.hutool.core.date.TemporalAccessorUtil;
import aiyh.utils.tool.cn.hutool.core.date.format.GlobalCustomFormat;
import aiyh.utils.tool.cn.hutool.core.io.IORuntimeException;
import aiyh.utils.tool.cn.hutool.core.lang.Filter;
import aiyh.utils.tool.cn.hutool.core.lang.mutable.MutablePair;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.CharUtil;
import aiyh.utils.tool.cn.hutool.core.util.NumberUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import aiyh.utils.tool.cn.hutool.json.*;
import java.io.IOException;
import java.io.Writer;
import java.time.MonthDay;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
/**
* JSON<br>
* appendJSON{@link Writer}
*
* @author looly
* @since 5.7.3
*/
public class JSONWriter extends Writer {
/**
*
*/
private final int indentFactor;
/**
*
*/
private final int indent;
/**
* Writer
*/
private final Writer writer;
/**
* JSON
*/
private final JSONConfig config;
/**
*
*/
private boolean needSeparator;
/**
* JSONArray
*/
private boolean arrayMode;
/**
* JSONWriter
*
* @param writer {@link Writer}
* @param indentFactor
* @param indent
* @param config JSON
* @return JSONWriter
*/
public static JSONWriter of(Writer writer, int indentFactor, int indent, JSONConfig config) {
return new JSONWriter(writer, indentFactor, indent, config);
}
/**
*
*
* @param writer {@link Writer}
* @param indentFactor
* @param indent
* @param config JSON
*/
public JSONWriter(Writer writer, int indentFactor, int indent, JSONConfig config) {
this.writer = writer;
this.indentFactor = indentFactor;
this.indent = indent;
this.config = config;
}
/**
* JSONObject"{"
*
* @return this
*/
public JSONWriter beginObj() {
writeRaw(CharUtil.DELIM_START);
return this;
}
/**
* JSONArray"["
*
* @return this
*/
public JSONWriter beginArray() {
writeRaw(CharUtil.BRACKET_START);
arrayMode = true;
return this;
}
/**
* "}""]"
*
* @return this
*/
public JSONWriter end() {
// 换行缩进
writeLF().writeSpace(indent);
writeRaw(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END);
flush();
arrayMode = false;
// 当前对象或数组结束,当新的
needSeparator = true;
return this;
}
/**
*
*
* @param key
* @return this
*/
public JSONWriter writeKey(String key) {
if (needSeparator) {
writeRaw(CharUtil.COMMA);
}
// 换行缩进
writeLF().writeSpace(indentFactor + indent);
return writeRaw(JSONUtil.quote(key));
}
/**
* <br>
* {@code null}{@link JSONNull}null
*
* @param value
* @return this
*/
public JSONWriter writeValue(Object value) {
if (JSONUtil.isNull(value) && config.isIgnoreNullValue()) {
return this;
}
return writeValueDirect(value, null);
}
/**
* {@code null}null
*
* @param key
* @param value
* @return this
* @since 5.7.6
* @deprecated 使 {@link #writeField(MutablePair, Filter)}
*/
@Deprecated
public JSONWriter writeField(String key, Object value) {
if (JSONUtil.isNull(value) && config.isIgnoreNullValue()) {
return this;
}
return writeKey(key).writeValueDirect(value, null);
}
/**
* {@code null}null
*
* @param pair
* @param filter
* @return this
* @since 5.8.6
*/
public JSONWriter writeField(MutablePair<Object, Object> pair, Filter<MutablePair<Object, Object>> filter) {
if (JSONUtil.isNull(pair.getValue()) && config.isIgnoreNullValue()) {
return this;
}
if (null == filter || filter.accept(pair)) {
if (!arrayMode) {
// JSONArray只写值JSONObject写键值对
writeKey(StrUtil.toString(pair.getKey()));
}
return writeValueDirect(pair.getValue(), filter);
}
return this;
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
this.writer.write(cbuf, off, len);
}
@Override
public void flush() {
try {
this.writer.flush();
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
@Override
public void close() throws IOException {
this.writer.close();
}
// ------------------------------------------------------------------------------ Private methods
/**
*
*
* @param value
* @param filter
* @return this
*/
private JSONWriter writeValueDirect(Object value, Filter<MutablePair<Object, Object>> filter) {
if (arrayMode) {
if (needSeparator) {
writeRaw(CharUtil.COMMA);
}
// 换行缩进
writeLF().writeSpace(indentFactor + indent);
} else {
writeRaw(CharUtil.COLON).writeSpace(1);
}
needSeparator = true;
return writeObjValue(value, filter);
}
/**
* JSON
*
* @param value
* @param filter
* @return this
*/
private JSONWriter writeObjValue(Object value, Filter<MutablePair<Object, Object>> filter) {
final int indent = indentFactor + this.indent;
if (value == null || value instanceof JSONNull) {
writeRaw(JSONNull.NULL.toString());
} else if (value instanceof JSON) {
if (value instanceof JSONObject) {
((JSONObject) value).write(writer, indentFactor, indent, filter);
} else if (value instanceof JSONArray) {
((JSONArray) value).write(writer, indentFactor, indent, filter);
}
} else if (value instanceof Map || value instanceof Map.Entry) {
new JSONObject(value).write(writer, indentFactor, indent);
} else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) {
new JSONArray(value).write(writer, indentFactor, indent);
} else if (value instanceof Number) {
writeNumberValue((Number) value);
} else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) {
// issue#2572@Github
if (value instanceof MonthDay) {
writeStrValue(value.toString());
return this;
}
final String format = (null == config) ? null : config.getDateFormat();
writeRaw(formatDate(value, format));
} else if (value instanceof Boolean) {
writeBooleanValue((Boolean) value);
} else if (value instanceof JSONString) {
writeJSONStringValue((JSONString) value);
} else {
writeStrValue(value.toString());
}
return this;
}
/**
* {@link JSONConfig#isStripTrailingZeros()} <br>
* Double0<br>
*
*
* @param number
*/
private void writeNumberValue(Number number) {
// since 5.6.2可配置是否去除末尾多余0例如如果为true,5.0返回5
final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros();
writeRaw(NumberUtil.toStr(number, isStripTrailingZeros));
}
/**
* Booleantruefalse,
*
* @param value Boolean
*/
private void writeBooleanValue(Boolean value) {
writeRaw(value.toString());
}
/**
* {@link JSONString}{@link JSONString#toJSONString()}JSON<br>
* {@link JSONString}JSONJSON<br>
* toJSONString()nulltoString()使
*
* @param jsonString {@link JSONString}
*/
private void writeJSONStringValue(JSONString jsonString) {
String valueStr;
try {
valueStr = jsonString.toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
if (null != valueStr) {
writeRaw(valueStr);
} else {
writeStrValue(jsonString.toString());
}
}
/**
* <br>
* 使<br>
* HTML&lt;/&lt;\/<br>
* JSON
*
* @param csq
*/
private void writeStrValue(String csq) {
try {
JSONUtil.quote(csq, writer);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
/**
*
*
* @param count
*/
private void writeSpace(int count) {
if (indentFactor > 0) {
for (int i = 0; i < count; i++) {
writeRaw(CharUtil.SPACE);
}
}
}
/**
*
*
* @return this
*/
private JSONWriter writeLF() {
if (indentFactor > 0) {
writeRaw(CharUtil.LF);
}
return this;
}
/**
*
*
* @param csq
* @return this
*/
private JSONWriter writeRaw(String csq) {
try {
writer.append(csq);
} catch (IOException e) {
throw new IORuntimeException(e);
}
return this;
}
/**
*
*
* @param c
* @return this
*/
private JSONWriter writeRaw(char c) {
try {
writer.write(c);
} catch (IOException e) {
throw new IORuntimeException(e);
}
return this;
}
/**
*
*
* @param dateObj DateCalendar
* @param format
* @return
*/
private static String formatDate(Object dateObj, String format) {
if (StrUtil.isNotBlank(format)) {
final String dateStr;
if (dateObj instanceof TemporalAccessor) {
dateStr = TemporalAccessorUtil.format((TemporalAccessor) dateObj, format);
} else {
dateStr = DateUtil.format(Convert.toDate(dateObj), format);
}
if (GlobalCustomFormat.FORMAT_SECONDS.equals(format)
|| GlobalCustomFormat.FORMAT_MILLISECONDS.equals(format)) {
// Hutool自定义的秒和毫秒表示默认不包装双引号
return dateStr;
}
// 用户定义了日期格式
return JSONUtil.quote(dateStr);
}
// 默认使用时间戳
long timeMillis;
if (dateObj instanceof TemporalAccessor) {
timeMillis = TemporalAccessorUtil.toEpochMilli((TemporalAccessor) dateObj);
} else if (dateObj instanceof Date) {
timeMillis = ((Date) dateObj).getTime();
} else if (dateObj instanceof Calendar) {
timeMillis = ((Calendar) dateObj).getTimeInMillis();
} else {
throw new UnsupportedOperationException("Unsupported Date type: " + dateObj.getClass());
}
return String.valueOf(timeMillis);
}
}

View File

@ -0,0 +1,76 @@
package aiyh.utils.tool.cn.hutool.json.serialize;
import aiyh.utils.tool.cn.hutool.json.JSON;
import aiyh.utils.tool.cn.hutool.json.JSONException;
import aiyh.utils.tool.cn.hutool.json.JSONObject;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAccessor;
/**
* {@link TemporalAccessor}JSON
*
* @author looly
* @since 5.7.22
*/
public class TemporalAccessorSerializer implements JSONObjectSerializer<TemporalAccessor>, JSONDeserializer<TemporalAccessor> {
private static final String YEAR_KEY = "year";
private static final String MONTH_KEY = "month";
private static final String DAY_KEY = "day";
private static final String HOUR_KEY = "hour";
private static final String MINUTE_KEY = "minute";
private static final String SECOND_KEY = "second";
private static final String NANO_KEY = "nano";
private final Class<? extends TemporalAccessor> temporalAccessorClass;
public TemporalAccessorSerializer(Class<? extends TemporalAccessor> temporalAccessorClass) {
this.temporalAccessorClass = temporalAccessorClass;
}
@Override
public void serialize(JSONObject json, TemporalAccessor bean) {
if (bean instanceof LocalDate) {
final LocalDate localDate = (LocalDate) bean;
json.set(YEAR_KEY, localDate.getYear());
json.set(MONTH_KEY, localDate.getMonthValue());
json.set(DAY_KEY, localDate.getDayOfMonth());
} else if (bean instanceof LocalDateTime) {
final LocalDateTime localDateTime = (LocalDateTime) bean;
json.set(YEAR_KEY, localDateTime.getYear());
json.set(MONTH_KEY, localDateTime.getMonthValue());
json.set(DAY_KEY, localDateTime.getDayOfMonth());
json.set(HOUR_KEY, localDateTime.getHour());
json.set(MINUTE_KEY, localDateTime.getMinute());
json.set(SECOND_KEY, localDateTime.getSecond());
json.set(NANO_KEY, localDateTime.getNano());
} else if (bean instanceof LocalTime) {
final LocalTime localTime = (LocalTime) bean;
json.set(HOUR_KEY, localTime.getHour());
json.set(MINUTE_KEY, localTime.getMinute());
json.set(SECOND_KEY, localTime.getSecond());
json.set(NANO_KEY, localTime.getNano());
} else {
throw new JSONException("Unsupported type to JSON: {}", bean.getClass().getName());
}
}
@Override
public TemporalAccessor deserialize(JSON json) {
final JSONObject jsonObject = (JSONObject) json;
if (LocalDate.class.equals(this.temporalAccessorClass)) {
return LocalDate.of(jsonObject.getInt(YEAR_KEY), jsonObject.getInt(MONTH_KEY), jsonObject.getInt(DAY_KEY));
} else if (LocalDateTime.class.equals(this.temporalAccessorClass)) {
return LocalDateTime.of(jsonObject.getInt(YEAR_KEY), jsonObject.getInt(MONTH_KEY), jsonObject.getInt(DAY_KEY),
jsonObject.getInt(HOUR_KEY), jsonObject.getInt(MINUTE_KEY), jsonObject.getInt(SECOND_KEY), jsonObject.getInt(NANO_KEY));
} else if (LocalTime.class.equals(this.temporalAccessorClass)) {
return LocalTime.of(jsonObject.getInt(HOUR_KEY), jsonObject.getInt(MINUTE_KEY), jsonObject.getInt(SECOND_KEY), jsonObject.getInt(NANO_KEY));
}
throw new JSONException("Unsupported type from JSON: {}", this.temporalAccessorClass);
}
}

View File

@ -0,0 +1,6 @@
/**
* JSON
*
* @author Looly
*/
package aiyh.utils.tool.cn.hutool.json.serialize;

View File

@ -0,0 +1,179 @@
package aiyh.utils.tool.cn.hutool.json.xml;
import aiyh.utils.tool.cn.hutool.json.*;
/**
* XMLXMLJSON
*
* @author JSON.org, looly
* @since 5.7.11
*/
public class JSONXMLParser {
/**
* XMLJSONObject
* JSONJSONArray
*
* @param jo JSONObject
* @param xmlStr XML
* @param keepStrings {@code true}Stringboolean
* @throws JSONException
*/
public static void parseJSONObject(JSONObject jo, String xmlStr, boolean keepStrings) throws JSONException {
XMLTokener x = new XMLTokener(xmlStr, jo.getConfig());
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, keepStrings);
}
}
/**
* Scan the content following the named tag, attaching it to the context.
*
* @param x The XMLTokener containing the source string.
* @param context The JSONObject that will include the new material.
* @param name The tag name.
* @return true if the close tag is processed.
* @throws JSONException JSON
*/
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) throws JSONException {
char c;
int i;
JSONObject jsonobject;
String string;
String tagName;
Object token;
token = x.nextToken();
if (token == XML.BANG) {
c = x.next();
if (c == '-') {
if (x.next() == '-') {
x.skipPast("-->");
return false;
}
x.back();
} else if (c == '[') {
token = x.nextToken();
if ("CDATA".equals(token)) {
if (x.next() == '[') {
string = x.nextCDATA();
if (string.length() > 0) {
context.accumulate("content", string);
}
return false;
}
}
throw x.syntaxError("Expected 'CDATA['");
}
i = 1;
do {
token = x.nextMeta();
if (token == null) {
throw x.syntaxError("Missing '>' after '<!'.");
} else if (token == XML.LT) {
i += 1;
} else if (token == XML.GT) {
i -= 1;
}
} while (i > 0);
return false;
} else if (token == XML.QUEST) {
// <?
x.skipPast("?>");
return false;
} else if (token == XML.SLASH) {
// Close tag </
token = x.nextToken();
if (name == null) {
throw x.syntaxError("Mismatched close tag " + token);
}
if (!token.equals(name)) {
throw x.syntaxError("Mismatched " + name + " and " + token);
}
if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped close tag");
}
return true;
} else if (token instanceof Character) {
throw x.syntaxError("Misshaped tag");
// Open tag <
} else {
tagName = (String) token;
token = null;
jsonobject = new JSONObject();
for (; ; ) {
if (token == null) {
token = x.nextToken();
}
// attribute = value
if (token instanceof String) {
string = (String) token;
token = x.nextToken();
if (token == XML.EQ) {
token = x.nextToken();
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
}
} else if (token == XML.SLASH) {
// Empty tag <.../>
if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped tag");
}
if (jsonobject.size() > 0) {
context.accumulate(tagName, jsonobject);
} else {
context.accumulate(tagName, "");
}
return false;
} else if (token == XML.GT) {
// Content, between <...> and </...>
for (; ; ) {
token = x.nextContent();
if (token == null) {
if (tagName != null) {
throw x.syntaxError("Unclosed tag " + tagName);
}
return false;
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content", keepStrings ? token : InternalJSONUtil.stringToValue(string));
}
} else if (token == XML.LT) {
// Nested element
if (parse(x, jsonobject, tagName, keepStrings)) {
if (jsonobject.size() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
context.accumulate(tagName, jsonobject.get("content"));
} else {
context.accumulate(tagName, jsonobject);
}
return false;
}
}
}
} else {
throw x.syntaxError("Misshaped tag");
}
}
}
}
}

View File

@ -0,0 +1,159 @@
package aiyh.utils.tool.cn.hutool.json.xml;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.CharUtil;
import aiyh.utils.tool.cn.hutool.core.util.EscapeUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import aiyh.utils.tool.cn.hutool.json.JSONArray;
import aiyh.utils.tool.cn.hutool.json.JSONException;
import aiyh.utils.tool.cn.hutool.json.JSONObject;
/**
* JSONXML
*
* @author looly
* @since 5.7.11
*/
public class JSONXMLSerializer {
/**
* JSONObjectXML
* Convert a JSONObject into a well-formed, element-normal XML string.
*
* @param object A JSONObject.
* @return A string.
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toXml(Object object) throws JSONException {
return toXml(object, null);
}
/**
* JSONObjectXML
*
* @param object JSON
* @param tagName
* @return A string.
* @throws JSONException JSON
*/
public static String toXml(Object object, String tagName) throws JSONException {
return toXml(object, tagName, "content");
}
/**
* JSONObjectXML
*
* @param object JSON
* @param tagName
* @param contentKeys key,key
* @return A string.
* @throws JSONException JSON
*/
public static String toXml(Object object, String tagName, String... contentKeys) throws JSONException {
if (null == object) {
return null;
}
final StringBuilder sb = new StringBuilder();
if (object instanceof JSONObject) {
// Emit <tagName>
appendTag(sb, tagName, false);
// Loop thru the keys.
((JSONObject) object).forEach((key, value) -> {
if (ArrayUtil.isArray(value)) {
value = new JSONArray(value);
}
// Emit content in body
if (ArrayUtil.contains(contentKeys, key)) {
if (value instanceof JSONArray) {
int i = 0;
for (Object val : (JSONArray) value) {
if (i > 0) {
sb.append(CharUtil.LF);
}
sb.append(EscapeUtil.escapeXml(val.toString()));
i++;
}
} else {
sb.append(EscapeUtil.escapeXml(value.toString()));
}
// Emit an array of similar keys
} else if (StrUtil.isEmptyIfStr(value)) {
sb.append(wrapWithTag(null, key));
} else if (value instanceof JSONArray) {
for (Object val : (JSONArray) value) {
if (val instanceof JSONArray) {
sb.append(wrapWithTag(toXml(val, null, contentKeys), key));
} else {
sb.append(toXml(val, key, contentKeys));
}
}
} else {
sb.append(toXml(value, key, contentKeys));
}
});
// Emit the </tagname> close tag
appendTag(sb, tagName, true);
return sb.toString();
}
if (ArrayUtil.isArray(object)) {
object = new JSONArray(object);
}
if (object instanceof JSONArray) {
for (Object val : (JSONArray) object) {
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// <array> element.
sb.append(toXml(val, tagName == null ? "array" : tagName, contentKeys));
}
return sb.toString();
}
return wrapWithTag(EscapeUtil.escapeXml(object.toString()), tagName);
}
/**
*
*
* @param sb XML
* @param tagName
* @param isEndTag
* @since 5.7.11
*/
private static void appendTag(StringBuilder sb, String tagName, boolean isEndTag) {
if (StrUtil.isNotBlank(tagName)) {
sb.append('<');
if (isEndTag) {
sb.append('/');
}
sb.append(tagName).append('>');
}
}
/**
* 使XML
*
* @param tagName
* @param content
* @return XML
* @since 5.7.11
*/
private static String wrapWithTag(String content, String tagName) {
if (StrUtil.isBlank(tagName)) {
return StrUtil.wrap(content, "\"");
}
if (StrUtil.isEmpty(content)) {
return "<" + tagName + "/>";
} else {
return "<" + tagName + ">" + content + "</" + tagName + ">";
}
}
}

View File

@ -0,0 +1,6 @@
/**
* JSONXMLjson.org
*
* @author looly
*/
package aiyh.utils.tool.cn.hutool.json.xml;

View File

@ -91,8 +91,7 @@ public class CaElectronicSignatureAction extends SafeCusBaseAction {
Map<String, Object> responseMap = responeVo.getResponseMap();
Map<String, Object> data = (Map<String, Object>) responseMap.get("data");
if (Objects.isNull(data)) {
Util.actionFail(requestInfo.getRequestManager(), URLDecoder.decode(Util.null2String(responseMap.get("ret_msg")), "UTF-8"));
return;
Util.actionFailException(requestInfo.getRequestManager(), URLDecoder.decode(Util.null2String(responseMap.get("ret_msg")), "UTF-8"));
}
String documentNo = Util.null2String(data.get("document_no"));
String pdf = Util.null2String(data.get("ofd"));

View File

@ -14,6 +14,7 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* <h1></h1>
@ -28,7 +29,11 @@ public class GetOfdKeywordPageValue implements CusInterfaceGetValue {
@Override
public Object execute(Map<String, Object> mainMap, Map<String, Object> detailMap, String currentValue, Map<String, String> pathParam) {
try {
DocImageInfo docImageInfo = Util.selectImageInfoByDocId(currentValue);
List<DocImageInfo> docImageInfoList = Util.selectImageInfoByDocIds(currentValue);
DocImageInfo docImageInfo = findMaxImageFileId(docImageInfoList);
if (Objects.isNull(docImageInfo)) {
throw new CustomerException("未找到实体文件数据!");
}
InputStream inputStream = ImageFileManager.getInputStreamById(docImageInfo.getImageFileId());
String filePath = Util.createTempFile(inputStream, docImageInfo.getImageFileName(), "ofd");
String keywordType = pathParam.get("keywordType");
@ -47,14 +52,28 @@ public class GetOfdKeywordPageValue implements CusInterfaceGetValue {
List<OFDReader.KeywordInfoRange> keywordInfos = reader.findKeywords();
Files.delete(Paths.get(filePath));
if (keywordInfos.isEmpty()) {
throw new CustomerException("关键字定位异常!未找到关键字");
throw new CustomerException("关键字定位异常!未找到关键字" + keywordValue);
} else {
String pageNumber = keywordInfos.get(keywordInfos.size() - 1).getStart().getPageNumber();
return Integer.parseInt(pageNumber) + 1;
}
} catch (Exception e) {
log.error("关键字定位异常: " + Util.getErrString(e));
throw new CustomerException("关键字定位异常!", e);
throw new CustomerException("关键字定位异常!");
}
}
public DocImageInfo findMaxImageFileId(List<DocImageInfo> list) {
DocImageInfo maxImageFileIdObj = null;
Integer maxImageFileId = null;
for (DocImageInfo obj : list) {
if (maxImageFileId == null || obj.getImageFileId() > maxImageFileId) {
maxImageFileId = obj.getImageFileId();
maxImageFileIdObj = obj;
}
}
return maxImageFileIdObj;
}
}

View File

@ -1,5 +1,6 @@
package weaver.youhong.ai.intellectualproperty.util;
import lombok.ToString;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@ -98,6 +99,7 @@ public class OFDReader {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream);
NodeList textNodes = doc.getElementsByTagName("ofd:TextObject");
int startK = 0;
KeywordInfo startNode = null;
List<KeywordInfo> keywordInfos = new ArrayList<>();
for (int i = 0; i < textNodes.getLength(); i++) {
Node textNode = textNodes.item(i);
@ -111,21 +113,24 @@ public class OFDReader {
if (contentChar == keywordChar) {
j++;
if (j == chars.length) {
if (k == keywordChars.length - 1) {
// 已经找到关键字
startK = 0;
KeywordInfo keywordNode = createKeywordNode(pageFolder, keywordInfos, textNode);
if (startNode != null) {
keywordInfos.add(startNode);
startNode = null;
}
keywordInfos.add(keywordNode);
break;
}
startK = j;
Node boundaryNode = textNode.getAttributes().getNamedItem("Boundary");
String boundary = boundaryNode.getNodeValue();
String[] boundarySegments = boundary.split(" ");
double x = Double.parseDouble(boundarySegments[0]);
double y = Double.parseDouble(boundarySegments[1]);
double width = Double.parseDouble(boundarySegments[2]);
double height = Double.parseDouble(boundarySegments[3]);
KeywordInfo keywordInfo = new KeywordInfo(pageFolder, x, y, width, height);
keywordInfos.add(keywordInfo);
startNode = createKeywordNode(pageFolder, keywordInfos, textNode);
break;
}
} else {
startK = 0;
keywordInfos.clear();
startNode = null;
break;
}
}
@ -138,6 +143,18 @@ public class OFDReader {
return new KeywordInfoRange(keywordInfos.get(0), keywordInfos.get(keywordInfos.size() - 1));
}
private static KeywordInfo createKeywordNode(String pageFolder, List<KeywordInfo> keywordInfos, Node textNode) {
Node boundaryNode = textNode.getAttributes().getNamedItem("Boundary");
String boundary = boundaryNode.getNodeValue();
String[] boundarySegments = boundary.split(" ");
double x = Double.parseDouble(boundarySegments[0]);
double y = Double.parseDouble(boundarySegments[1]);
double width = Double.parseDouble(boundarySegments[2]);
double height = Double.parseDouble(boundarySegments[3]);
return new KeywordInfo(pageFolder, x, y, width, height);
}
@ToString
public static class KeywordInfoRange {
private final KeywordInfo start;
@ -157,6 +174,7 @@ public class OFDReader {
}
}
@ToString
public static class KeywordInfo {
private final String pageFolder;
private final double x;

View File

@ -1,9 +1,17 @@
package youhong.ai.intellectualproperty;
import aiyh.utils.GenerateFileUtil;
import aiyh.utils.Util;
import basetest.BaseTest;
import com.alibaba.fastjson.JSON;
import org.junit.Test;
import weaver.youhong.ai.intellectualproperty.action.CaElectronicSignatureAction;
import weaver.youhong.ai.intellectualproperty.util.OFDReader;
import java.io.*;
import java.util.Base64;
import java.util.List;
import java.util.Map;
/**
* <h1></h1>
@ -19,4 +27,38 @@ public class TestAction extends BaseTest {
public void test() {
GenerateFileUtil.createActionDocument(CaElectronicSignatureAction.class);
}
@Test
public void testet() throws Exception {
String path = "/Users/aoey.oct.22/Downloads/关于反馈《中国(上海)自由贸易试验区十周年总结报告》征求意见的复函(5.29.ofd";
OFDReader ofdReader = new OFDReader(path, "@Signature_position@");
List<OFDReader.KeywordInfoRange> keywords = ofdReader.findKeywords();
System.out.println(keywords);
Map<String, String> stringStringMap = Util.parseCusInterfacePathParam("weaver.youhong.ai.intellectualproperty.cusgetvalue.GetOfdKeywordPageValue?keywordType=0&keyword=`@Signature_position@`");
System.out.println(JSON.toJSONString(stringStringMap));
}
@Test
public void tesetet() {
String longString = "";
try (BufferedReader reader = new BufferedReader(new FileReader("/Users/aoey.oct.22/Downloads/base64.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
longString += line;
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] decodedBytes = Base64.getDecoder().decode(longString); // 解码为字节数组
try (OutputStream outputStream = new FileOutputStream("/Users/aoey.oct.22/Downloads/example.ofd")) {
outputStream.write(decodedBytes); // 将字节数组写入文件
System.out.println("文件已写入成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -40,7 +40,7 @@ public class PDFODFTest extends BaseTest {
@Test
public void tesetOfdKeyWorkdasdf() throws Exception {
weaver.youhong.ai.intellectualproperty.util.OFDReader reader = new OFDReader("/Users/aoey.oct.22/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/44e92f459afe6c0b31d119efb268a257/Message/MessageTemp/65ac172b9cb23c7967462468b4b5be81/File/1684915381834-ofd-4e579378-0925-43b3-9f89-89b661772521测试文档01.ofd", "签章位置001");
weaver.youhong.ai.intellectualproperty.util.OFDReader reader = new OFDReader("/Users/aoey.oct.22/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/44e92f459afe6c0b31d119efb268a257/Message/MessageTemp/65ac172b9cb23c7967462468b4b5be81/File/2b6319c0-3395-4a74-8062-07bc2089c607.ofd", "签章位置001");
System.out.println(JSON.toJSONString(reader.findKeywords()));
}