mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix code
This commit is contained in:
parent
1d4d4e0e76
commit
f970dc7632
@ -10,12 +10,7 @@ import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Bean路径表达式,用于获取多层嵌套Bean中的字段值或Bean对象<br>
|
||||
@ -119,11 +114,14 @@ public class BeanPath implements Serializable {
|
||||
public void set(final Object bean, final Object value) {
|
||||
Objects.requireNonNull(bean);
|
||||
|
||||
Object subBean = bean, previousBean;
|
||||
Object subBean = bean;
|
||||
Object previousBean = null;
|
||||
boolean isFirst = true;
|
||||
String patternPart;
|
||||
// 尝试找到倒数第二个子对象, 最终需要设置它的字段值
|
||||
final int length = patternParts.size() - 1;
|
||||
|
||||
// 填充父字段缺失的对象
|
||||
for (int i = 0; i < length; i++) {
|
||||
patternPart = patternParts.get(i);
|
||||
// 保存当前操作的bean, 以便subBean不存在时, 可以用来填充缺失的子对象
|
||||
@ -145,8 +143,13 @@ public class BeanPath implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置最终的字段值
|
||||
BeanUtil.setFieldValue(subBean, patternParts.get(length), value);
|
||||
|
||||
// 设置最终的(当前)字段值
|
||||
final Object newSubBean = BeanUtil.setFieldValue(subBean, patternParts.get(length), value);
|
||||
if(newSubBean != subBean && null != previousBean){
|
||||
// 对象变更,重新加入
|
||||
BeanUtil.setFieldValue(previousBean, patternParts.get(length - 1), newSubBean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -166,7 +169,7 @@ public class BeanPath implements Serializable {
|
||||
private Object get(final List<String> patternParts, final Object bean) {
|
||||
Object subBean = bean;
|
||||
boolean isFirst = true;
|
||||
for (String patternPart : patternParts) {
|
||||
for (final String patternPart : patternParts) {
|
||||
subBean = getFieldValue(subBean, patternPart);
|
||||
if (null == subBean) {
|
||||
// 支持表达式的第一个对象为Bean本身(若用户定义表达式$开头,则不做此操作)
|
||||
|
@ -118,7 +118,7 @@ public class BeanUtil {
|
||||
if (method.getParameterCount() == 0) {
|
||||
final String name = method.getName();
|
||||
if (name.startsWith("get") || name.startsWith("is")) {
|
||||
if(false == "getClass".equals(name)){
|
||||
if (false == "getClass".equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -311,24 +311,32 @@ public class BeanUtil {
|
||||
|
||||
/**
|
||||
* 设置字段值,通过反射设置字段值,并不调用setXXX方法<br>
|
||||
* 对象同样支持Map类型,fieldNameOrIndex即为key
|
||||
* 对象同样支持Map类型,fieldNameOrIndex即为key,支持:
|
||||
* <ul>
|
||||
* <li>Map</li>
|
||||
* <li>List</li>
|
||||
* <li>Bean</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param bean Bean
|
||||
* @param fieldNameOrIndex 字段名或序号,序号支持负数
|
||||
* @param value 值
|
||||
* @return bean,当为数组时,返回一个新的数组
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static void setFieldValue(final Object bean, final String fieldNameOrIndex, final Object value) {
|
||||
public static Object setFieldValue(final Object bean, final String fieldNameOrIndex, final Object value) {
|
||||
if (bean instanceof Map) {
|
||||
((Map) bean).put(fieldNameOrIndex, value);
|
||||
} else if (bean instanceof List) {
|
||||
ListUtil.setOrPadding((List) bean, Convert.toInt(fieldNameOrIndex), value);
|
||||
} else if (ArrayUtil.isArray(bean)) {
|
||||
ArrayUtil.setOrAppend(bean, Convert.toInt(fieldNameOrIndex), value);
|
||||
// issue#3008,追加产生新数组,此处返回新数组
|
||||
return ArrayUtil.setOrAppend(bean, Convert.toInt(fieldNameOrIndex), value);
|
||||
} else {
|
||||
// 普通Bean对象
|
||||
FieldUtil.setFieldValue(bean, fieldNameOrIndex, value);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -701,7 +701,7 @@ public class IoUtil extends NioUtil {
|
||||
* @return {@link InputStream}
|
||||
* @since 4.0.9
|
||||
*/
|
||||
public static InputStream toMarkSupportStream(final InputStream in) {
|
||||
public static InputStream toMarkSupport(final InputStream in) {
|
||||
if (null == in) {
|
||||
return null;
|
||||
}
|
||||
@ -711,6 +711,23 @@ public class IoUtil extends NioUtil {
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@link Reader}转换为支持mark标记的Reader<br>
|
||||
* 若原Reader支持mark标记,则返回原Reader,否则使用{@link BufferedReader} 包装之
|
||||
*
|
||||
* @param reader {@link Reader}
|
||||
* @return {@link Reader}
|
||||
*/
|
||||
public static Reader toMarkSupport(final Reader reader) {
|
||||
if (null == reader) {
|
||||
return null;
|
||||
}
|
||||
if (false == reader.markSupported()) {
|
||||
return new BufferedReader(reader);
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得{@link PushbackReader}<br>
|
||||
* 如果是{@link PushbackReader}强转返回,否则新建
|
||||
|
@ -53,6 +53,31 @@ public class ReaderWrapper extends Reader implements Wrapper<Reader> {
|
||||
return raw.read(buffer, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return this.raw.markSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark(final int readAheadLimit) throws IOException {
|
||||
this.raw.mark(readAheadLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(final long n) throws IOException {
|
||||
return this.raw.skip(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ready() throws IOException {
|
||||
return this.raw.ready();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
this.raw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
raw.close();
|
||||
|
@ -624,7 +624,8 @@ public class NetUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主机名称,一次获取会缓存名称
|
||||
* 获取主机名称,一次获取会缓存名称<br>
|
||||
* 注意此方法会触发反向DNS解析,导致阻塞,阻塞时间取决于网络!
|
||||
*
|
||||
* @return 主机名称
|
||||
* @since 5.4.4
|
||||
|
@ -266,16 +266,17 @@ public class FieldUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字段值
|
||||
* 设置字段值,如果值类型必须与字段类型匹配,会自动转换对象类型
|
||||
*
|
||||
* @param obj 对象,如果是static字段,此参数为null
|
||||
* @param field 字段
|
||||
* @param value 值,值类型必须与字段类型匹配,不会自动转换对象类型
|
||||
* @param value 值,类型不匹配会自动转换对象类型
|
||||
* @throws UtilException UtilException 包装IllegalAccessException异常
|
||||
*/
|
||||
public static void setFieldValue(final Object obj, final Field field, Object value) throws UtilException {
|
||||
Assert.notNull(field, "Field in [{}] not exist !", obj);
|
||||
|
||||
// 值类型检查和转换
|
||||
final Class<?> fieldType = field.getType();
|
||||
if (null != value) {
|
||||
if (false == fieldType.isAssignableFrom(value.getClass())) {
|
||||
@ -290,6 +291,18 @@ public class FieldUtil {
|
||||
value = ClassUtil.getDefaultValue(fieldType);
|
||||
}
|
||||
|
||||
setFieldValueExact(obj, field, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字段值,传入的字段值必须和字段类型一致,否则抛出异常
|
||||
*
|
||||
* @param obj 对象,如果是static字段,此参数为null
|
||||
* @param field 字段
|
||||
* @param value 值,值类型必须与字段类型匹配
|
||||
* @throws UtilException UtilException 包装IllegalAccessException异常
|
||||
*/
|
||||
public static void setFieldValueExact(final Object obj, final Field field, final Object value) throws UtilException {
|
||||
ReflectUtil.setAccessible(field);
|
||||
try {
|
||||
field.set(obj instanceof Class ? null : obj, value);
|
||||
|
@ -3,6 +3,8 @@ package cn.hutool.core.bean;
|
||||
import cn.hutool.core.lang.test.bean.ExamInfoDict;
|
||||
import cn.hutool.core.lang.test.bean.UserInfoDict;
|
||||
import cn.hutool.core.map.Dict;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import lombok.Data;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -152,4 +154,36 @@ public class BeanPathTest {
|
||||
BeanPath.of("aa.bb").set(dict, "BB");
|
||||
Assert.assertEquals("{aa={bb=BB}}", dict.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendArrayTest(){
|
||||
// issue#3008@Github
|
||||
final MyUser myUser = new MyUser();
|
||||
BeanPath.of("hobby[0]").set(myUser, "LOL");
|
||||
BeanPath.of("hobby[1]").set(myUser, "KFC");
|
||||
BeanPath.of("hobby[2]").set(myUser, "COFFE");
|
||||
|
||||
Assert.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getHobby()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendArrayTest2(){
|
||||
// issue#3008@Github
|
||||
final MyUser2 myUser = new MyUser2();
|
||||
BeanPath.of("myUser.hobby[0]").set(myUser, "LOL");
|
||||
BeanPath.of("myUser.hobby[1]").set(myUser, "KFC");
|
||||
BeanPath.of("myUser.hobby[2]").set(myUser, "COFFE");
|
||||
|
||||
Assert.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getMyUser().getHobby()));
|
||||
}
|
||||
|
||||
@Data
|
||||
static class MyUser {
|
||||
private String[] hobby;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class MyUser2 {
|
||||
private MyUser myUser;
|
||||
}
|
||||
}
|
||||
|
@ -78,10 +78,17 @@ public class NetUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void getLocalHostNameTest() {
|
||||
// 注意此方法会触发反向DNS解析,导致阻塞,阻塞时间取决于网络!
|
||||
Assert.assertNotNull(NetUtil.getLocalHostName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLocalHostTest() {
|
||||
Assert.assertNotNull(NetUtil.getLocalhost());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pingTest(){
|
||||
Assert.assertTrue(NetUtil.ping("127.0.0.1"));
|
||||
|
@ -74,7 +74,7 @@ public class CompressUtil {
|
||||
* @return {@link CompressorOutputStream}
|
||||
*/
|
||||
public static CompressorInputStream getIn(String compressorName, InputStream in) {
|
||||
in = IoUtil.toMarkSupportStream(in);
|
||||
in = IoUtil.toMarkSupport(in);
|
||||
try {
|
||||
if(StrUtil.isBlank(compressorName)){
|
||||
compressorName = CompressorStreamFactory.detect(in);
|
||||
|
@ -21,9 +21,7 @@ import cn.hutool.json.serialize.JSONStringer;
|
||||
import cn.hutool.json.writer.GlobalValueWriterMapping;
|
||||
import cn.hutool.json.writer.JSONValueWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.SQLException;
|
||||
@ -316,7 +314,7 @@ public final class InternalJSONUtil {
|
||||
*/
|
||||
public static Writer quote(final String str, final Writer writer, final boolean isWrap) throws IORuntimeException {
|
||||
try {
|
||||
return doQuote(str, writer, isWrap);
|
||||
return _quote(str, writer, isWrap);
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
@ -422,7 +420,7 @@ public final class InternalJSONUtil {
|
||||
* @throws IOException IO异常
|
||||
* @since 3.3.1
|
||||
*/
|
||||
private static Writer doQuote(final String str, final Writer writer, final boolean isWrap) throws IOException {
|
||||
private static Writer _quote(final String str, final Writer writer, final boolean isWrap) throws IOException {
|
||||
if (StrUtil.isEmpty(str)) {
|
||||
if (isWrap) {
|
||||
writer.write("\"\"");
|
||||
|
@ -8,7 +8,7 @@ import cn.hutool.core.lang.mutable.MutableEntry;
|
||||
import cn.hutool.core.lang.mutable.MutableObj;
|
||||
import cn.hutool.core.text.StrJoiner;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.json.mapper.ArrayMapper;
|
||||
import cn.hutool.json.mapper.JSONArrayMapper;
|
||||
import cn.hutool.json.writer.JSONWriter;
|
||||
|
||||
import java.io.StringWriter;
|
||||
@ -148,7 +148,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
*/
|
||||
public JSONArray(final Object object, final JSONConfig jsonConfig, final Predicate<Mutable<Object>> predicate) throws JSONException {
|
||||
this(DEFAULT_CAPACITY, jsonConfig);
|
||||
ArrayMapper.of(object, predicate).mapTo(this);
|
||||
JSONArrayMapper.of(object, predicate).mapTo(this);
|
||||
}
|
||||
// endregion
|
||||
|
||||
|
@ -9,7 +9,7 @@ import cn.hutool.core.lang.mutable.MutableEntry;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.map.MapWrapper;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.json.mapper.ObjectMapper;
|
||||
import cn.hutool.json.mapper.JSONObjectMapper;
|
||||
import cn.hutool.json.writer.JSONWriter;
|
||||
|
||||
import java.io.StringWriter;
|
||||
@ -132,7 +132,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
*/
|
||||
public JSONObject(final Object source, final JSONConfig config, final Predicate<MutableEntry<String, Object>> predicate) {
|
||||
this(DEFAULT_CAPACITY, config);
|
||||
ObjectMapper.of(source, predicate).mapTo(this);
|
||||
JSONObjectMapper.of(source, predicate).mapTo(this);
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------------------------- Constructor end
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package cn.hutool.json;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.ReaderWrapper;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
@ -14,7 +14,7 @@ import java.io.StringReader;
|
||||
*
|
||||
* @author from JSON.org
|
||||
*/
|
||||
public class JSONTokener {
|
||||
public class JSONTokener extends ReaderWrapper {
|
||||
|
||||
private long character;
|
||||
/**
|
||||
@ -37,10 +37,6 @@ public class JSONTokener {
|
||||
* 是否使用前一个字符
|
||||
*/
|
||||
private boolean usePrevious;
|
||||
/**
|
||||
* 源
|
||||
*/
|
||||
private final Reader reader;
|
||||
|
||||
/**
|
||||
* JSON配置
|
||||
@ -48,24 +44,6 @@ public class JSONTokener {
|
||||
private final JSONConfig config;
|
||||
|
||||
// ------------------------------------------------------------------------------------ Constructor start
|
||||
|
||||
/**
|
||||
* 从Reader中构建
|
||||
*
|
||||
* @param reader Reader
|
||||
* @param config JSON配置
|
||||
*/
|
||||
public JSONTokener(final Reader reader, final 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编码
|
||||
*
|
||||
@ -86,6 +64,23 @@ public class JSONTokener {
|
||||
public JSONTokener(final CharSequence s, final JSONConfig config) {
|
||||
this(new StringReader(StrUtil.str(s)), config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Reader中构建
|
||||
*
|
||||
* @param reader Reader
|
||||
* @param config JSON配置
|
||||
*/
|
||||
public JSONTokener(final Reader reader, final JSONConfig config) {
|
||||
super(IoUtil.toMarkSupport(reader));
|
||||
this.eof = false;
|
||||
this.usePrevious = false;
|
||||
this.previous = 0;
|
||||
this.index = 0;
|
||||
this.character = 1;
|
||||
this.line = 1;
|
||||
this.config = config;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------ Constructor end
|
||||
|
||||
/**
|
||||
@ -138,7 +133,7 @@ public class JSONTokener {
|
||||
c = this.previous;
|
||||
} else {
|
||||
try {
|
||||
c = this.reader.read();
|
||||
c = read();
|
||||
} catch (final IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
@ -390,11 +385,11 @@ public class JSONTokener {
|
||||
final long startIndex = this.index;
|
||||
final long startCharacter = this.character;
|
||||
final long startLine = this.line;
|
||||
this.reader.mark(1000000);
|
||||
mark(1000000);
|
||||
do {
|
||||
c = this.next();
|
||||
if (c == 0) {
|
||||
this.reader.reset();
|
||||
reset();
|
||||
this.index = startIndex;
|
||||
this.character = startCharacter;
|
||||
this.line = startLine;
|
||||
|
@ -6,18 +6,14 @@ import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.convert.ConvertException;
|
||||
import cn.hutool.core.convert.Converter;
|
||||
import cn.hutool.core.convert.RegisterConverter;
|
||||
import cn.hutool.core.convert.impl.ArrayConverter;
|
||||
import cn.hutool.core.convert.impl.CollectionConverter;
|
||||
import cn.hutool.core.convert.impl.DateConverter;
|
||||
import cn.hutool.core.convert.impl.MapConverter;
|
||||
import cn.hutool.core.convert.impl.TemporalAccessorConverter;
|
||||
import cn.hutool.core.convert.impl.*;
|
||||
import cn.hutool.core.map.MapWrapper;
|
||||
import cn.hutool.core.math.NumberUtil;
|
||||
import cn.hutool.core.reflect.ConstructorUtil;
|
||||
import cn.hutool.core.reflect.TypeReference;
|
||||
import cn.hutool.core.reflect.TypeUtil;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.json.*;
|
||||
import cn.hutool.json.serialize.JSONDeserializer;
|
||||
import cn.hutool.json.serialize.JSONStringer;
|
||||
@ -111,36 +107,45 @@ public class JSONConverter implements Converter {
|
||||
/**
|
||||
* 实现Object对象转换为{@link JSON},支持的对象:
|
||||
* <ul>
|
||||
* <li>String: 转换为相应的对象,</li>
|
||||
* <li>String: 转换为相应的对象,"和'包围的字符串返回原字符串,""返回{@code null}</li>
|
||||
* <li>Array、Iterable、Iterator:转换为JSONArray</li>
|
||||
* <li>Bean对象:转为JSONObject</li>
|
||||
* <li>Number:返回原对象</li>
|
||||
* <li>null:返回{@code null}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param obj 被转换的对象
|
||||
* @return 转换后的对象
|
||||
* @throws JSONException 转换异常
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public Object toJSON(final Object obj) throws JSONException {
|
||||
if(null == obj){
|
||||
return null;
|
||||
}
|
||||
final JSON json;
|
||||
if (obj instanceof JSON || obj instanceof Number) {
|
||||
return obj;
|
||||
} else if (obj instanceof CharSequence) {
|
||||
final String jsonStr = StrUtil.trim((CharSequence) obj);
|
||||
switch (jsonStr.charAt(0)){
|
||||
case '"':
|
||||
case '\'':
|
||||
// JSON字符串值
|
||||
return jsonStr;
|
||||
if(jsonStr.isEmpty()){
|
||||
// 空按照null值处理
|
||||
return null;
|
||||
}
|
||||
final char firstC = jsonStr.charAt(0);
|
||||
switch (firstC){
|
||||
case '[':
|
||||
return new JSONArray(jsonStr, config);
|
||||
case '{':
|
||||
return new JSONObject(jsonStr, config);
|
||||
default:
|
||||
if(NumberUtil.isNumber(jsonStr)){
|
||||
return NumberUtil.toBigDecimal(jsonStr);
|
||||
// RFC8259,JSON字符串值、number, boolean, or null
|
||||
final Object value = new JSONTokener(jsonStr, config).nextValue();
|
||||
if(ObjUtil.equals(value, jsonStr)){
|
||||
// 原值返回,意味着非正常数字、Boolean或null
|
||||
throw new JSONException("Unsupported JSON String: {}", jsonStr);
|
||||
}
|
||||
throw new JSONException("Unsupported String to JSON: {}", jsonStr);
|
||||
return value;
|
||||
}
|
||||
} else if (obj instanceof MapWrapper) {
|
||||
// MapWrapper实现了Iterable会被当作JSONArray,此处做修正
|
||||
|
@ -32,7 +32,7 @@ import java.util.function.Predicate;
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class ArrayMapper {
|
||||
public class JSONArrayMapper {
|
||||
/**
|
||||
* 创建ArrayMapper
|
||||
*
|
||||
@ -40,8 +40,8 @@ public class ArrayMapper {
|
||||
* @param predicate 值过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留
|
||||
* @return ObjectMapper
|
||||
*/
|
||||
public static ArrayMapper of(final Object source, final Predicate<Mutable<Object>> predicate) {
|
||||
return new ArrayMapper(source, predicate);
|
||||
public static JSONArrayMapper of(final Object source, final Predicate<Mutable<Object>> predicate) {
|
||||
return new JSONArrayMapper(source, predicate);
|
||||
}
|
||||
|
||||
private final Object source;
|
||||
@ -53,7 +53,7 @@ public class ArrayMapper {
|
||||
* @param source 来源对象
|
||||
* @param predicate 值过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留
|
||||
*/
|
||||
public ArrayMapper(final Object source, final Predicate<Mutable<Object>> predicate) {
|
||||
public JSONArrayMapper(final Object source, final Predicate<Mutable<Object>> predicate) {
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
@ -78,7 +78,9 @@ public class ArrayMapper {
|
||||
return;
|
||||
}
|
||||
|
||||
if (source instanceof CharSequence) {
|
||||
if (source instanceof JSONTokener) {
|
||||
mapFromTokener((JSONTokener) source, jsonArray);
|
||||
}else if (source instanceof CharSequence) {
|
||||
// JSON字符串
|
||||
mapFromStr((CharSequence) source, jsonArray);
|
||||
} else if (source instanceof Reader) {
|
||||
@ -96,8 +98,6 @@ public class ArrayMapper {
|
||||
jsonArray.add(b);
|
||||
}
|
||||
}
|
||||
} else if (source instanceof JSONTokener) {
|
||||
mapFromTokener((JSONTokener) source, jsonArray);
|
||||
} else {
|
||||
final Iterator<?> iter;
|
||||
if (ArrayUtil.isArray(source)) {// 数组
|
||||
@ -107,7 +107,11 @@ public class ArrayMapper {
|
||||
} 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.");
|
||||
if(false == jsonArray.getConfig().isIgnoreError()){
|
||||
throw new JSONException("JSONArray initial value should be a string or collection or array.");
|
||||
}
|
||||
// 如果用户选择跳过异常,则跳过此值转换
|
||||
return;
|
||||
}
|
||||
|
||||
Object next;
|
@ -39,7 +39,7 @@ import java.util.function.Predicate;
|
||||
* @author looly
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public class ObjectMapper {
|
||||
public class JSONObjectMapper {
|
||||
|
||||
/**
|
||||
* 创建ObjectMapper
|
||||
@ -48,8 +48,8 @@ public class ObjectMapper {
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
* @return ObjectMapper
|
||||
*/
|
||||
public static ObjectMapper of(final Object source, final Predicate<MutableEntry<String, Object>> predicate) {
|
||||
return new ObjectMapper(source, predicate);
|
||||
public static JSONObjectMapper of(final Object source, final Predicate<MutableEntry<String, Object>> predicate) {
|
||||
return new JSONObjectMapper(source, predicate);
|
||||
}
|
||||
|
||||
private final Object source;
|
||||
@ -61,7 +61,7 @@ public class ObjectMapper {
|
||||
* @param source 来源对象
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
*/
|
||||
public ObjectMapper(final Object source, final Predicate<MutableEntry<String, Object>> predicate) {
|
||||
public JSONObjectMapper(final Object source, final Predicate<MutableEntry<String, Object>> predicate) {
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
@ -90,7 +90,10 @@ public class ObjectMapper {
|
||||
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
|
||||
}
|
||||
|
||||
if (source instanceof Map) {
|
||||
if (source instanceof JSONTokener) {
|
||||
// JSONTokener
|
||||
mapFromTokener((JSONTokener) source, jsonObject);
|
||||
}else if (source instanceof Map) {
|
||||
// Map
|
||||
for (final Map.Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
|
||||
jsonObject.set(Convert.toStr(e.getKey()), e.getValue(), predicate, false);
|
||||
@ -107,18 +110,18 @@ public class ObjectMapper {
|
||||
mapFromTokener(new JSONTokener((InputStream) source, jsonObject.getConfig()), jsonObject);
|
||||
} else if (source instanceof byte[]) {
|
||||
mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source), jsonObject.getConfig()), jsonObject);
|
||||
} else if (source instanceof JSONTokener) {
|
||||
// JSONTokener
|
||||
mapFromTokener((JSONTokener) source, jsonObject);
|
||||
} else if (source instanceof ResourceBundle) {
|
||||
// JSONTokener
|
||||
// ResourceBundle
|
||||
mapFromResourceBundle((ResourceBundle) source, jsonObject);
|
||||
} else if (BeanUtil.isReadableBean(source.getClass())) {
|
||||
// 普通Bean
|
||||
mapFromBean(source, jsonObject);
|
||||
} else {
|
||||
// 不支持对象类型转换为JSONObject
|
||||
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
|
||||
if(false == jsonObject.getConfig().isIgnoreError()){
|
||||
// 不支持对象类型转换为JSONObject
|
||||
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
|
||||
}
|
||||
// 如果用户选择跳过异常,则跳过此值转换
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,6 @@ package cn.hutool.json;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class IssueI6LBZATest {
|
||||
@Test
|
||||
public void parseJSONStringTest() {
|
||||
@ -31,6 +29,6 @@ public class IssueI6LBZATest {
|
||||
public void parseJSONNumberTest() {
|
||||
final String a = "123";
|
||||
final Object parse = JSONUtil.parse(a);
|
||||
Assert.assertEquals(BigDecimal.class, parse.getClass());
|
||||
Assert.assertEquals(Integer.class, parse.getClass());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package cn.hutool.json;
|
||||
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JSONTokenerTest {
|
||||
@Test
|
||||
public void parseTest() {
|
||||
final JSONObject jsonObject = JSONUtil.parseObj(ResourceUtil.getUtf8Reader("issue1200.json"));
|
||||
Assert.assertNotNull(jsonObject);
|
||||
}
|
||||
}
|
@ -17,6 +17,42 @@ import java.util.*;
|
||||
|
||||
public class JSONUtilTest {
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void parseInvalid() {
|
||||
JSONUtil.parse("abc");
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void parseInvalid2() {
|
||||
JSONUtil.parse("'abc");
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void parseInvalid3() {
|
||||
JSONUtil.parse("\"abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseValueTest() {
|
||||
Object parse = JSONUtil.parse(123);
|
||||
Assert.assertEquals(123, parse);
|
||||
|
||||
parse = JSONUtil.parse("\"abc\"");
|
||||
Assert.assertEquals("abc", parse);
|
||||
|
||||
parse = JSONUtil.parse("true");
|
||||
Assert.assertEquals(true, parse);
|
||||
|
||||
parse = JSONUtil.parse("False");
|
||||
Assert.assertEquals(false, parse);
|
||||
|
||||
parse = JSONUtil.parse("null");
|
||||
Assert.assertNull(parse);
|
||||
|
||||
parse = JSONUtil.parse("");
|
||||
Assert.assertNull(parse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 出现语法错误时报错,检查解析\x字符时是否会导致死循环异常
|
||||
*/
|
||||
@ -29,20 +65,39 @@ public class JSONUtilTest {
|
||||
* 数字解析为JSONArray报错
|
||||
*/
|
||||
@Test(expected = JSONException.class)
|
||||
public void parseNumberTest() {
|
||||
public void parseNumberToJSONArrayTest() {
|
||||
final JSONArray json = JSONUtil.parseArray(123L);
|
||||
Assert.assertNotNull(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字解析为JSONArray报错
|
||||
*/
|
||||
@Test
|
||||
public void parseNumberToJSONArrayTest2() {
|
||||
final JSONArray json = JSONUtil.parseArray(123L,
|
||||
JSONConfig.of().setIgnoreError(true));
|
||||
Assert.assertNotNull(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字解析为JSONArray报错
|
||||
*/
|
||||
@Test(expected = JSONException.class)
|
||||
public void parseNumberTest2() {
|
||||
public void parseNumberToJSONObjectTest() {
|
||||
final JSONObject json = JSONUtil.parseObj(123L);
|
||||
Assert.assertNotNull(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字解析为JSONObject,忽略错误
|
||||
*/
|
||||
@Test
|
||||
public void parseNumberToJSONObjectTest2() {
|
||||
final JSONObject json = JSONUtil.parseObj(123L, JSONConfig.of().setIgnoreError(true));
|
||||
Assert.assertEquals(new JSONObject(), json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toJsonStrTest() {
|
||||
final UserA a1 = new UserA();
|
||||
|
@ -93,7 +93,7 @@ public class ExcelUtil {
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static void readBySax(InputStream in, final int rid, final RowHandler rowHandler) {
|
||||
in = IoUtil.toMarkSupportStream(in);
|
||||
in = IoUtil.toMarkSupport(in);
|
||||
final ExcelSaxReader<?> reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(in), rowHandler);
|
||||
reader.read(in, rid);
|
||||
}
|
||||
@ -107,7 +107,7 @@ public class ExcelUtil {
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(InputStream in, final String idOrRidOrSheetName, final RowHandler rowHandler) {
|
||||
in = IoUtil.toMarkSupportStream(in);
|
||||
in = IoUtil.toMarkSupport(in);
|
||||
final ExcelSaxReader<?> reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(in), rowHandler);
|
||||
reader.read(in, idOrRidOrSheetName);
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ public class WorkbookUtil {
|
||||
*/
|
||||
public static Workbook createBook(final InputStream in, final String password) {
|
||||
try {
|
||||
return WorkbookFactory.create(IoUtil.toMarkSupportStream(in), password);
|
||||
return WorkbookFactory.create(IoUtil.toMarkSupport(in), password);
|
||||
} catch (final Exception e) {
|
||||
throw new POIException(e);
|
||||
} finally {
|
||||
|
@ -348,7 +348,7 @@ public final class Props extends Properties implements TypeGetter<CharSequence>
|
||||
BeanUtil.setProperty(bean, StrUtil.subSuf(key, prefix.length()), entry.getValue());
|
||||
} catch (final Exception e) {
|
||||
// 忽略注入失败的字段(这些字段可能用于其它配置)
|
||||
StaticLog.debug("Ignore property: [{}]", key);
|
||||
StaticLog.debug("Ignore property: [{}],because of: {}", key, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
package cn.hutool.setting;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.setting.dialect.Props;
|
||||
import cn.hutool.setting.dialect.PropsUtil;
|
||||
import lombok.Data;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class Issue3008Test {
|
||||
/**
|
||||
* 数组字段追加后生成新的数组,造成赋值丢失<br>
|
||||
* 修复见:BeanUtil.setFieldValue
|
||||
*/
|
||||
@Test
|
||||
public void toBeanTest() {
|
||||
final Props props = PropsUtil.get("issue3008");
|
||||
final MyUser user = props.toBean(MyUser.class, "person");
|
||||
Assert.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(user.getHobby()));
|
||||
}
|
||||
|
||||
@Data
|
||||
static class MyUser {
|
||||
private String[] hobby;
|
||||
}
|
||||
}
|
@ -112,4 +112,6 @@ public class PropsTest {
|
||||
private Date theStageTime;//当前阶段开始日期
|
||||
private Date nextStageTime;//当前阶段结束日期/下一阶段开始日期
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
3
hutool-setting/src/test/resources/issue3008.properties
Normal file
3
hutool-setting/src/test/resources/issue3008.properties
Normal file
@ -0,0 +1,3 @@
|
||||
person.hobby[0]=LOL
|
||||
person.hobby[1]=KFC
|
||||
person.hobby[2]=COFFE
|
Loading…
x
Reference in New Issue
Block a user