This commit is contained in:
Looly 2024-09-13 22:02:25 +08:00
parent 47fe46c495
commit ee13716d42
18 changed files with 646 additions and 522 deletions

View File

@ -30,6 +30,7 @@ import org.dromara.hutool.core.comparator.PinyinComparator;
import org.dromara.hutool.core.comparator.PropertyComparator; import org.dromara.hutool.core.comparator.PropertyComparator;
import org.dromara.hutool.core.convert.CompositeConverter; import org.dromara.hutool.core.convert.CompositeConverter;
import org.dromara.hutool.core.convert.ConvertUtil; import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.exception.ExceptionUtil; import org.dromara.hutool.core.exception.ExceptionUtil;
import org.dromara.hutool.core.func.SerBiConsumer; import org.dromara.hutool.core.func.SerBiConsumer;
import org.dromara.hutool.core.func.SerConsumer3; import org.dromara.hutool.core.func.SerConsumer3;
@ -401,7 +402,7 @@ public class CollUtil {
* @return 单差集 * @return 单差集
*/ */
public static <T> Collection<T> subtract(final Collection<T> coll1, final Collection<T> coll2) { public static <T> Collection<T> subtract(final Collection<T> coll1, final Collection<T> coll2) {
if(isEmpty(coll1) || isEmpty(coll2)){ if (isEmpty(coll1) || isEmpty(coll2)) {
return coll1; return coll1;
} }
@ -530,7 +531,7 @@ public class CollUtil {
} }
// Set直接判定 // Set直接判定
if(coll1 instanceof Set){ if (coll1 instanceof Set) {
return coll1.containsAll(coll2); return coll1.containsAll(coll2);
} }
@ -1571,8 +1572,24 @@ public class CollUtil {
* @param elementType 元素类型为空时使用Object类型来接纳所有类型 * @param elementType 元素类型为空时使用Object类型来接纳所有类型
* @return 被加入集合 * @return 被加入集合
*/ */
public static <T> Collection<T> addAll(final Collection<T> collection, final Object value, final Type elementType) {
return addAll(collection, value, elementType, null);
}
/**
* 将指定对象全部加入到集合中<br>
* 提供的对象如果为集合类型会自动转换为目标元素类型<br>
* 如果为String支持类似于[1,2,3,4] 或者 1,2,3,4 这种格式
*
* @param <T> 元素类型
* @param collection 被加入的集合
* @param value 对象可能为IteratorIterableEnumerationArray或者与集合元素类型一致
* @param elementType 元素类型为空时使用Object类型来接纳所有类型
* @param converter 自定义元素类型转换器{@code null}表示使用默认转换器
* @return 被加入集合
*/
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public static <T> Collection<T> addAll(final Collection<T> collection, final Object value, Type elementType) { public static <T> Collection<T> addAll(final Collection<T> collection, final Object value, Type elementType, final Converter converter) {
if (null == collection || null == value) { if (null == collection || null == value) {
return collection; return collection;
} }
@ -1595,7 +1612,7 @@ public class CollUtil {
iter = IterUtil.getIter(value); iter = IterUtil.getIter(value);
} }
final CompositeConverter convert = CompositeConverter.getInstance(); final Converter convert = ObjUtil.defaultIfNull(converter, CompositeConverter::getInstance);
while (iter.hasNext()) { while (iter.hasNext()) {
collection.add((T) convert.convert(elementType, iter.next())); collection.add((T) convert.convert(elementType, iter.next()));
} }
@ -2316,12 +2333,12 @@ public class CollUtil {
* </ul> * </ul>
* *
* @param subCollection 第一个Iterable对象即子集合 * @param subCollection 第一个Iterable对象即子集合
* @param collection 第二个Iterable对象可以为任何实现了Iterable接口的集合 * @param collection 第二个Iterable对象可以为任何实现了Iterable接口的集合
* @return 如果subCollection是collection的子集合则返回true否则返回false * @return 如果subCollection是collection的子集合则返回true否则返回false
* @since 6.0.0 * @since 6.0.0
*/ */
public static boolean isSub(final Collection<?> subCollection, final Collection<?> collection) { public static boolean isSub(final Collection<?> subCollection, final Collection<?> collection) {
if(size(subCollection) > size(collection)){ if (size(subCollection) > size(collection)) {
return false; return false;
} }
return IterUtil.isSub(subCollection, collection); return IterUtil.isSub(subCollection, collection);
@ -2354,13 +2371,13 @@ public class CollUtil {
* <li>如果不忽略顺序两个{@link Iterable}所有具有相同下标的元素皆满足{@link Objects#equals(Object, Object)}</li> * <li>如果不忽略顺序两个{@link Iterable}所有具有相同下标的元素皆满足{@link Objects#equals(Object, Object)}</li>
* </ul> * </ul>
* *
* @param coll1 集合1 * @param coll1 集合1
* @param coll2 集合2 * @param coll2 集合2
* @param ignoreOrder 是否忽略顺序 * @param ignoreOrder 是否忽略顺序
* @return 是否相同 * @return 是否相同
*/ */
public static boolean equals(final Collection<?> coll1, final Collection<?> coll2, final boolean ignoreOrder) { public static boolean equals(final Collection<?> coll1, final Collection<?> coll2, final boolean ignoreOrder) {
if(size(coll1) != size(coll2)){ if (size(coll1) != size(coll2)) {
return false; return false;
} }

View File

@ -23,6 +23,7 @@ import org.dromara.hutool.core.reflect.TypeReference;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
import java.io.Serializable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Optional; import java.util.Optional;
@ -36,7 +37,7 @@ import java.util.Optional;
* *
* @author Looly * @author Looly
*/ */
public class CompositeConverter extends RegisterConverter { public class CompositeConverter implements Converter, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -46,7 +47,12 @@ public class CompositeConverter extends RegisterConverter {
/** /**
* 静态初始化器由JVM来保证线程安全 * 静态初始化器由JVM来保证线程安全
*/ */
private static final CompositeConverter INSTANCE = new CompositeConverter(); private static final CompositeConverter INSTANCE;
static {
INSTANCE = new CompositeConverter();
INSTANCE.registerConverter = new RegisterConverter(INSTANCE);
INSTANCE.specialConverter = new SpecialConverter(INSTANCE);
}
} }
/** /**
@ -58,11 +64,38 @@ public class CompositeConverter extends RegisterConverter {
return SingletonHolder.INSTANCE; return SingletonHolder.INSTANCE;
} }
private RegisterConverter registerConverter;
private SpecialConverter specialConverter;
/** /**
* 构造 * 构造
*/ */
public CompositeConverter() { private CompositeConverter() {
super(); }
/**
* 登记自定义转换器符合{@link MatcherConverter#match(Type, Class, Object)}则使用其转换器<br>
* 注意如果单例使用此方法会影响全局
*
* @param converter 转换器
* @return this
*/
public CompositeConverter register(final MatcherConverter converter) {
registerConverter.register(converter);
return this;
}
/**
* 登记自定义转换器登记的目标类型必须一致<br>
* 注意如果单例使用此方法会影响全局
*
* @param type 转换的目标类型
* @param converter 转换器
* @return this
*/
public CompositeConverter register(final Type type, final Converter converter) {
registerConverter.register(type, converter);
return this;
} }
/** /**
@ -142,7 +175,7 @@ public class CompositeConverter extends RegisterConverter {
} }
// 标准转换器 // 标准转换器
final Converter converter = getConverter(type, value, isCustomFirst); final Converter converter = registerConverter.getConverter(type, value, isCustomFirst);
if (null != converter) { if (null != converter) {
return converter.convert(type, value, defaultValue); return converter.convert(type, value, defaultValue);
} }
@ -157,7 +190,7 @@ public class CompositeConverter extends RegisterConverter {
} }
// 特殊类型转换包括CollectionMap强转Array等 // 特殊类型转换包括CollectionMap强转Array等
final T result = (T) SpecialConverter.getInstance().convert(type, rawType, value); final T result = (T) specialConverter.convert(type, rawType, value);
if (null != result) { if (null != result) {
return result; return result;
} }

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.core.convert;
import org.dromara.hutool.core.lang.Assert;
/**
* 带根的转换器<br>
* 在嵌套对象转换中如果涉及子对象的转换使用根转换器转换
*
* @author Looly
* @since 6.0.0
*/
public abstract class ConverterWithRoot implements Converter {
protected final Converter rootConverter;
/**
* 构造
*
* @param rootConverter 根转换器
*/
public ConverterWithRoot(final Converter rootConverter) {
this.rootConverter = Assert.notNull(rootConverter);
}
/**
* 获取根转换器用于子转换器转换
*
* @return 根转换器
*/
public Converter getRootConverter() {
return rootConverter;
}
}

View File

@ -54,28 +54,9 @@ import java.util.concurrent.atomic.AtomicReference;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class RegisterConverter implements Converter, Serializable { public class RegisterConverter extends ConverterWithRoot implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 类级的内部类也就是静态的成员式内部类该内部类的实例与外部类的实例 没有绑定关系而且只有被调用到才会装载从而实现了延迟加载
*/
private static class SingletonHolder {
/**
* 静态初始化器由JVM来保证线程安全
*/
private static final RegisterConverter INSTANCE = new RegisterConverter();
}
/**
* 获得单例的 RegisterConverter
*
* @return RegisterConverter
*/
public static RegisterConverter getInstance() {
return RegisterConverter.SingletonHolder.INSTANCE;
}
/** /**
* 用户自定义类型转换器存储自定义匹配规则的一类对象的转换器 * 用户自定义类型转换器存储自定义匹配规则的一类对象的转换器
*/ */
@ -88,13 +69,16 @@ public class RegisterConverter implements Converter, Serializable {
/** /**
* 默认类型转换器 * 默认类型转换器
*/ */
private Map<Class<?>, Converter> defaultConverterMap; private final Map<Class<?>, Converter> defaultConverterMap;
/** /**
* 构造 * 构造
*
* @param rootConverter 根转换器用于子转换器转换
*/ */
public RegisterConverter() { public RegisterConverter(final Converter rootConverter) {
registerDefault(); super(rootConverter);
this.defaultConverterMap = initDefault(rootConverter);
} }
@Override @Override
@ -121,7 +105,7 @@ public class RegisterConverter implements Converter, Serializable {
Converter converter; Converter converter;
if (isCustomFirst) { if (isCustomFirst) {
converter = this.getCustomConverter(type, value); converter = this.getCustomConverter(type, value);
if(null == converter){ if (null == converter) {
converter = this.getCustomConverter(type); converter = this.getCustomConverter(type);
} }
if (null == converter) { if (null == converter) {
@ -132,7 +116,7 @@ public class RegisterConverter implements Converter, Serializable {
if (null == converter) { if (null == converter) {
converter = this.getCustomConverter(type, value); converter = this.getCustomConverter(type, value);
} }
if(null == converter){ if (null == converter) {
converter = this.getCustomConverter(type); converter = this.getCustomConverter(type);
} }
} }
@ -179,7 +163,7 @@ public class RegisterConverter implements Converter, Serializable {
* *
* @param type 转换的目标类型 * @param type 转换的目标类型
* @param converter 转换器 * @param converter 转换器
* @return ConverterRegistry * @return this
*/ */
public RegisterConverter register(final Type type, final Converter converter) { public RegisterConverter register(final Type type, final Converter converter) {
if (null == customConverterMap) { if (null == customConverterMap) {
@ -197,7 +181,7 @@ public class RegisterConverter implements Converter, Serializable {
* 登记自定义转换器符合{@link MatcherConverter#match(Type, Class, Object)}则使用其转换器 * 登记自定义转换器符合{@link MatcherConverter#match(Type, Class, Object)}则使用其转换器
* *
* @param converter 转换器 * @param converter 转换器
* @return ConverterRegistry * @return this
*/ */
public RegisterConverter register(final MatcherConverter converter) { public RegisterConverter register(final MatcherConverter converter) {
if (null == this.converterSet) { if (null == this.converterSet) {
@ -212,65 +196,68 @@ public class RegisterConverter implements Converter, Serializable {
} }
/** /**
* 注册默认转换器 * 初始化默认转换器
*
* @return 默认转换器
*/ */
private void registerDefault() { private static Map<Class<?>, Converter> initDefault(final Converter rootConverter) {
final Map<Class<?>, Converter> defaultConverterMap = new SafeConcurrentHashMap<>(64); final Map<Class<?>, Converter> converterMap = new SafeConcurrentHashMap<>(64);
// 包装类转换器 // 包装类转换器
defaultConverterMap.put(Character.class, CharacterConverter.INSTANCE); converterMap.put(Character.class, CharacterConverter.INSTANCE);
defaultConverterMap.put(Boolean.class, BooleanConverter.INSTANCE); converterMap.put(Boolean.class, BooleanConverter.INSTANCE);
defaultConverterMap.put(AtomicBoolean.class, AtomicBooleanConverter.INSTANCE);// since 3.0.8 converterMap.put(AtomicBoolean.class, AtomicBooleanConverter.INSTANCE);// since 3.0.8
final StringConverter stringConverter = new StringConverter(); final StringConverter stringConverter = new StringConverter();
defaultConverterMap.put(CharSequence.class, stringConverter); converterMap.put(CharSequence.class, stringConverter);
defaultConverterMap.put(String.class, stringConverter); converterMap.put(String.class, stringConverter);
// URI and URL // URI and URL
defaultConverterMap.put(URI.class, new URIConverter()); converterMap.put(URI.class, new URIConverter());
defaultConverterMap.put(URL.class, new URLConverter()); converterMap.put(URL.class, new URLConverter());
// 日期时间 // 日期时间
defaultConverterMap.put(Calendar.class, new CalendarConverter()); converterMap.put(Calendar.class, new CalendarConverter());
defaultConverterMap.put(XMLGregorianCalendar.class, new XMLGregorianCalendarConverter()); converterMap.put(XMLGregorianCalendar.class, new XMLGregorianCalendarConverter());
// 日期时间 JDK8+(since 5.0.0) // 日期时间 JDK8+(since 5.0.0)
defaultConverterMap.put(TemporalAccessor.class, TemporalAccessorConverter.INSTANCE); converterMap.put(TemporalAccessor.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(Instant.class, TemporalAccessorConverter.INSTANCE); converterMap.put(Instant.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(LocalDateTime.class, TemporalAccessorConverter.INSTANCE); converterMap.put(LocalDateTime.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(LocalDate.class, TemporalAccessorConverter.INSTANCE); converterMap.put(LocalDate.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(LocalTime.class, TemporalAccessorConverter.INSTANCE); converterMap.put(LocalTime.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(ZonedDateTime.class, TemporalAccessorConverter.INSTANCE); converterMap.put(ZonedDateTime.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(OffsetDateTime.class, TemporalAccessorConverter.INSTANCE); converterMap.put(OffsetDateTime.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(OffsetTime.class, TemporalAccessorConverter.INSTANCE); converterMap.put(OffsetTime.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(DayOfWeek.class, TemporalAccessorConverter.INSTANCE); converterMap.put(DayOfWeek.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(Month.class, TemporalAccessorConverter.INSTANCE); converterMap.put(Month.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(MonthDay.class, TemporalAccessorConverter.INSTANCE); converterMap.put(MonthDay.class, TemporalAccessorConverter.INSTANCE);
defaultConverterMap.put(Period.class, new PeriodConverter()); converterMap.put(Period.class, new PeriodConverter());
defaultConverterMap.put(Duration.class, new DurationConverter()); converterMap.put(Duration.class, new DurationConverter());
// Reference // Reference
defaultConverterMap.put(WeakReference.class, ReferenceConverter.INSTANCE);// since 3.0.8 final ReferenceConverter referenceConverter = new ReferenceConverter(rootConverter);
defaultConverterMap.put(SoftReference.class, ReferenceConverter.INSTANCE);// since 3.0.8 converterMap.put(WeakReference.class, referenceConverter);// since 3.0.8
defaultConverterMap.put(AtomicReference.class, new AtomicReferenceConverter());// since 3.0.8 converterMap.put(SoftReference.class, referenceConverter);// since 3.0.8
converterMap.put(AtomicReference.class, new AtomicReferenceConverter(rootConverter));// since 3.0.8
//AtomicXXXArraysince 5.4.5 //AtomicXXXArraysince 5.4.5
defaultConverterMap.put(AtomicIntegerArray.class, new AtomicIntegerArrayConverter()); converterMap.put(AtomicIntegerArray.class, new AtomicIntegerArrayConverter());
defaultConverterMap.put(AtomicLongArray.class, new AtomicLongArrayConverter()); converterMap.put(AtomicLongArray.class, new AtomicLongArrayConverter());
// 其它类型 // 其它类型
defaultConverterMap.put(Locale.class, new LocaleConverter()); converterMap.put(Locale.class, new LocaleConverter());
defaultConverterMap.put(Charset.class, new CharsetConverter()); converterMap.put(Charset.class, new CharsetConverter());
defaultConverterMap.put(Path.class, new PathConverter()); converterMap.put(Path.class, new PathConverter());
defaultConverterMap.put(Currency.class, new CurrencyConverter());// since 3.0.8 converterMap.put(Currency.class, new CurrencyConverter());// since 3.0.8
defaultConverterMap.put(UUID.class, new UUIDConverter());// since 4.0.10 converterMap.put(UUID.class, new UUIDConverter());// since 4.0.10
defaultConverterMap.put(StackTraceElement.class, new StackTraceElementConverter());// since 4.5.2 converterMap.put(StackTraceElement.class, new StackTraceElementConverter());// since 4.5.2
defaultConverterMap.put(Optional.class, new OptionalConverter());// since 5.0.0 converterMap.put(Optional.class, new OptionalConverter());// since 5.0.0
defaultConverterMap.put(Opt.class, new OptConverter());// since 5.7.16 converterMap.put(Opt.class, new OptConverter());// since 5.7.16
defaultConverterMap.put(Pair.class, PairConverter.INSTANCE);// since 6.0.0 converterMap.put(Pair.class, new PairConverter(rootConverter));// since 6.0.0
defaultConverterMap.put(Triple.class, TripleConverter.INSTANCE);// since 6.0.0 converterMap.put(Triple.class, new TripleConverter(rootConverter));// since 6.0.0
defaultConverterMap.put(Tuple.class, TupleConverter.INSTANCE);// since 6.0.0 converterMap.put(Tuple.class, TupleConverter.INSTANCE);// since 6.0.0
this.defaultConverterMap = defaultConverterMap; return converterMap;
} }
} }

View File

@ -17,6 +17,7 @@
package org.dromara.hutool.core.convert; package org.dromara.hutool.core.convert;
import org.dromara.hutool.core.convert.impl.*; import org.dromara.hutool.core.convert.impl.*;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.stream.StreamUtil; import org.dromara.hutool.core.stream.StreamUtil;
@ -33,28 +34,9 @@ import java.util.Set;
* @author Looly * @author Looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class SpecialConverter implements Converter, Serializable { public class SpecialConverter extends ConverterWithRoot implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 类级的内部类也就是静态的成员式内部类该内部类的实例与外部类的实例 没有绑定关系而且只有被调用到才会装载从而实现了延迟加载
*/
private static class SingletonHolder {
/**
* 静态初始化器由JVM来保证线程安全
*/
private static final SpecialConverter INSTANCE = new SpecialConverter();
}
/**
* 获得单例的 CustomConverter
*
* @return CustomConverter
*/
public static SpecialConverter getInstance() {
return SpecialConverter.SingletonHolder.INSTANCE;
}
/** /**
* 类型转换器集合<br> * 类型转换器集合<br>
* 此集合初始化后不再加入新值因此单例使用线程安全 * 此集合初始化后不再加入新值因此单例使用线程安全
@ -63,42 +45,12 @@ public class SpecialConverter implements Converter, Serializable {
/** /**
* 构造 * 构造
*
* @param rootConverter 父转换器
*/ */
private SpecialConverter() { public SpecialConverter(final Converter rootConverter) {
final Set<MatcherConverter> converterSet = new LinkedHashSet<>(64); super(rootConverter);
this.converterSet = initDefault(Assert.notNull(rootConverter));
// 集合转换含有泛型参数不可以默认强转
converterSet.add(CollectionConverter.INSTANCE);
// Map类型含有泛型参数不可以默认强转
converterSet.add(MapConverter.INSTANCE);
// issue#I6SZYB Entry类含有泛型参数不可以默认强转
converterSet.add(EntryConverter.INSTANCE);
// 默认强转
converterSet.add(CastConverter.INSTANCE);
// 日期java.sql中的日期以及自定义日期统一处理
converterSet.add(DateConverter.INSTANCE);
// 原始类型转换
converterSet.add(PrimitiveConverter.INSTANCE);
// 数字类型转换
converterSet.add(NumberConverter.INSTANCE);
// 枚举转换
converterSet.add(EnumConverter.INSTANCE);
// 数组转换
converterSet.add(ArrayConverter.INSTANCE);
// Record
converterSet.add(RecordConverter.INSTANCE);
// Kotlin Bean
converterSet.add(KBeanConverter.INSTANCE);
// issue#I7FQ29 Class
converterSet.add(ClassConverter.INSTANCE);
// // 空值转空Bean
converterSet.add(EmptyBeanConverter.INSTANCE);
// 日期相关
converterSet.add(TimeZoneConverter.INSTANCE);
converterSet.add(ZoneIdConverter.INSTANCE);
this.converterSet = converterSet;
} }
@Override @Override
@ -141,4 +93,47 @@ public class SpecialConverter implements Converter, Serializable {
private static Converter getConverterFromSet(final Set<? extends MatcherConverter> converterSet, final Type type, final Class<?> rawType, final Object value) { private static Converter getConverterFromSet(final Set<? extends MatcherConverter> converterSet, final Type type, final Class<?> rawType, final Object value) {
return StreamUtil.of(converterSet).filter((predicate) -> predicate.match(type, rawType, value)).findFirst().orElse(null); return StreamUtil.of(converterSet).filter((predicate) -> predicate.match(type, rawType, value)).findFirst().orElse(null);
} }
/**
* 初始化默认转换器
*
* @param rootConverter 根转换器用于递归子对象转换
* @return 转换器集合
*/
private static Set<MatcherConverter> initDefault(final Converter rootConverter) {
final Set<MatcherConverter> converterSet = new LinkedHashSet<>(64);
// 集合转换含有泛型参数不可以默认强转
converterSet.add(CollectionConverter.INSTANCE);
// Map类型含有泛型参数不可以默认强转
converterSet.add(new MapConverter(rootConverter));
// issue#I6SZYB Entry类含有泛型参数不可以默认强转
converterSet.add(new EntryConverter(rootConverter));
// 默认强转
converterSet.add(CastConverter.INSTANCE);
// 日期java.sql中的日期以及自定义日期统一处理
converterSet.add(DateConverter.INSTANCE);
// 原始类型转换
converterSet.add(PrimitiveConverter.INSTANCE);
// 数字类型转换
converterSet.add(NumberConverter.INSTANCE);
// 枚举转换
converterSet.add(EnumConverter.INSTANCE);
// 数组转换
converterSet.add(ArrayConverter.INSTANCE);
// Record
converterSet.add(RecordConverter.INSTANCE);
// Kotlin Bean
converterSet.add(KBeanConverter.INSTANCE);
// issue#I7FQ29 Class
converterSet.add(ClassConverter.INSTANCE);
// // 空值转空Bean
converterSet.add(EmptyBeanConverter.INSTANCE);
// 日期相关
converterSet.add(TimeZoneConverter.INSTANCE);
converterSet.add(ZoneIdConverter.INSTANCE);
return converterSet;
}
} }

View File

@ -17,7 +17,7 @@
package org.dromara.hutool.core.convert.impl; package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.convert.AbstractConverter; import org.dromara.hutool.core.convert.AbstractConverter;
import org.dromara.hutool.core.convert.CompositeConverter; import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -32,16 +32,27 @@ import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceConverter extends AbstractConverter { public class AtomicReferenceConverter extends AbstractConverter {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Converter converter;
/**
* 构造
*
* @param converter 用于转换AtomicReference包装的对象类型
*/
public AtomicReferenceConverter(final Converter converter) {
this.converter = converter;
}
@Override @Override
protected AtomicReference<?> convertInternal(final Class<?> targetClass, final Object value) { protected AtomicReference<?> convertInternal(final Class<?> targetClass, final Object value) {
//尝试将值转换为Reference泛型的类型 //尝试将值转换为Reference泛型的类型
Object targetValue = null; Object targetValue = null;
final Type paramType = TypeUtil.getTypeArgument(AtomicReference.class); final Type paramType = TypeUtil.getTypeArgument(AtomicReference.class);
if(!TypeUtil.isUnknown(paramType)){ if (!TypeUtil.isUnknown(paramType)) {
targetValue = CompositeConverter.getInstance().convert(paramType, value); targetValue = converter.convert(paramType, value);
} }
if(null == targetValue){ if (null == targetValue) {
targetValue = value; targetValue = value;
} }

View File

@ -17,8 +17,8 @@
package org.dromara.hutool.core.convert.impl; package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.bean.BeanUtil; import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.convert.CompositeConverter;
import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.convert.ConvertException;
import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.convert.MatcherConverter; import org.dromara.hutool.core.convert.MatcherConverter;
import org.dromara.hutool.core.lang.tuple.Pair; import org.dromara.hutool.core.lang.tuple.Pair;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
@ -46,10 +46,16 @@ import java.util.Map;
public class EntryConverter implements MatcherConverter, Serializable { public class EntryConverter implements MatcherConverter, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Converter convert;
/** /**
* 单例 * 构造
*
* @param converter 转换器用于将Entry中key和value转换为指定类型的对象
*/ */
public static final EntryConverter INSTANCE = new EntryConverter(); public EntryConverter(final Converter converter) {
this.convert = converter;
}
@Override @Override
public boolean match(final Type targetType, final Class<?> rawType, final Object value) { public boolean match(final Type targetType, final Class<?> rawType, final Object value) {
@ -132,7 +138,7 @@ public class EntryConverter implements MatcherConverter, Serializable {
* @return Entry * @return Entry
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private static Map.Entry<?, ?> mapToEntry(final Type targetType, final Type keyType, final Type valueType, final Map map) { private Map.Entry<?, ?> mapToEntry(final Type targetType, final Type keyType, final Type valueType, final Map map) {
final Object key; final Object key;
final Object value; final Object value;
@ -146,7 +152,6 @@ public class EntryConverter implements MatcherConverter, Serializable {
value = map.get("value"); value = map.get("value");
} }
final CompositeConverter convert = CompositeConverter.getInstance();
return (Map.Entry<?, ?>) ConstructorUtil.newInstance(TypeUtil.getClass(targetType), return (Map.Entry<?, ?>) ConstructorUtil.newInstance(TypeUtil.getClass(targetType),
TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key), TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key),
TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value) TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value)

View File

@ -17,9 +17,7 @@
package org.dromara.hutool.core.convert.impl; package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.bean.BeanUtil; import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.convert.CompositeConverter; import org.dromara.hutool.core.convert.*;
import org.dromara.hutool.core.convert.ConvertException;
import org.dromara.hutool.core.convert.MatcherConverter;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.reflect.TypeReference; import org.dromara.hutool.core.reflect.TypeReference;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
@ -40,13 +38,22 @@ import java.util.Objects;
* @author Looly * @author Looly
* @since 3.0.8 * @since 3.0.8
*/ */
public class MapConverter implements MatcherConverter, Serializable { public class MapConverter extends ConverterWithRoot implements MatcherConverter, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 单例 * 单例
*/ */
public static MapConverter INSTANCE = new MapConverter(); public static final MapConverter INSTANCE = new MapConverter(CompositeConverter.getInstance());
/**
* 构造
*
* @param rootConverter 根转换器用于转换Map中键值对中的值{@code null}
*/
public MapConverter(final Converter rootConverter) {
super(rootConverter);
}
@Override @Override
public boolean match(final Type targetType, final Class<?> rawType, final Object value) { public boolean match(final Type targetType, final Class<?> rawType, final Object value) {
@ -111,10 +118,9 @@ public class MapConverter implements MatcherConverter, Serializable {
*/ */
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
private void convertMapToMap(final Type keyType, final Type valueType, final Map<?, ?> srcMap, final Map targetMap) { private void convertMapToMap(final Type keyType, final Type valueType, final Map<?, ?> srcMap, final Map targetMap) {
final CompositeConverter convert = CompositeConverter.getInstance();
srcMap.forEach((key, value) -> targetMap.put( srcMap.forEach((key, value) -> targetMap.put(
TypeUtil.isUnknown(keyType) ? key : convert.convert(keyType, key), TypeUtil.isUnknown(keyType) ? key : rootConverter.convert(keyType, key),
TypeUtil.isUnknown(valueType) ? value : convert.convert(valueType, value) TypeUtil.isUnknown(valueType) ? value : rootConverter.convert(valueType, value)
)); ));
} }
} }

View File

@ -17,9 +17,9 @@
package org.dromara.hutool.core.convert.impl; package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.bean.BeanUtil; import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.convert.CompositeConverter;
import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.convert.ConvertException;
import org.dromara.hutool.core.convert.Converter; import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.convert.ConverterWithRoot;
import org.dromara.hutool.core.lang.tuple.Pair; import org.dromara.hutool.core.lang.tuple.Pair;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.reflect.TypeReference; import org.dromara.hutool.core.reflect.TypeReference;
@ -27,6 +27,7 @@ import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
@ -41,12 +42,17 @@ import java.util.Map;
* *
* @author looly * @author looly
*/ */
public class PairConverter implements Converter { public class PairConverter extends ConverterWithRoot implements Serializable {
private static final long serialVersionUID = 1L;
/** /**
* 单例 * 构造
*
* @param rootConverter 根转换器用于转换Pair中的值
*/ */
public static final PairConverter INSTANCE = new PairConverter(); public PairConverter(final Converter rootConverter) {
super(rootConverter);
}
@Override @Override
public Object convert(Type targetType, final Object value) throws ConvertException { public Object convert(Type targetType, final Object value) throws ConvertException {
@ -122,7 +128,7 @@ public class PairConverter implements Converter {
* @return Pair * @return Pair
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private static Pair<?, ?> mapToPair(final Type keyType, final Type valueType, final Map map) { private Pair<?, ?> mapToPair(final Type keyType, final Type valueType, final Map map) {
final Object left; final Object left;
final Object right; final Object right;
@ -136,10 +142,9 @@ public class PairConverter implements Converter {
right = map.get("right"); right = map.get("right");
} }
final CompositeConverter convert = CompositeConverter.getInstance();
return Pair.of( return Pair.of(
TypeUtil.isUnknown(keyType) ? left : convert.convert(keyType, left), TypeUtil.isUnknown(keyType) ? left : rootConverter.convert(keyType, left),
TypeUtil.isUnknown(valueType) ? right : convert.convert(valueType, right) TypeUtil.isUnknown(valueType) ? right : rootConverter.convert(valueType, right)
); );
} }
} }

View File

@ -17,9 +17,10 @@
package org.dromara.hutool.core.convert.impl; package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.convert.AbstractConverter; import org.dromara.hutool.core.convert.AbstractConverter;
import org.dromara.hutool.core.convert.CompositeConverter; import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
@ -36,10 +37,16 @@ import java.lang.reflect.Type;
public class ReferenceConverter extends AbstractConverter { public class ReferenceConverter extends AbstractConverter {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Converter rootConverter;
/** /**
* 单例 * 构造
*
* @param rootConverter 根转换器用于转换Reference泛型的类型
*/ */
public static ReferenceConverter INSTANCE = new ReferenceConverter(); public ReferenceConverter(final Converter rootConverter) {
this.rootConverter = Assert.notNull(rootConverter);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
@ -49,7 +56,7 @@ public class ReferenceConverter extends AbstractConverter {
Object targetValue = null; Object targetValue = null;
final Type paramType = TypeUtil.getTypeArgument(targetClass); final Type paramType = TypeUtil.getTypeArgument(targetClass);
if(!TypeUtil.isUnknown(paramType)){ if(!TypeUtil.isUnknown(paramType)){
targetValue = CompositeConverter.getInstance().convert(paramType, value); targetValue = rootConverter.convert(paramType, value);
} }
if(null == targetValue){ if(null == targetValue){
targetValue = value; targetValue = value;

View File

@ -17,13 +17,14 @@
package org.dromara.hutool.core.convert.impl; package org.dromara.hutool.core.convert.impl;
import org.dromara.hutool.core.bean.BeanUtil; import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.convert.CompositeConverter;
import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.convert.ConvertException;
import org.dromara.hutool.core.convert.Converter; import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.convert.ConverterWithRoot;
import org.dromara.hutool.core.lang.tuple.Triple; import org.dromara.hutool.core.lang.tuple.Triple;
import org.dromara.hutool.core.reflect.TypeReference; import org.dromara.hutool.core.reflect.TypeReference;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import java.io.Serializable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
@ -36,12 +37,17 @@ import java.util.Map;
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class TripleConverter implements Converter { public class TripleConverter extends ConverterWithRoot implements Serializable {
private static final long serialVersionUID = 1L;
/** /**
* 单例 * 构造
*
* @param rootConverter 根转换器用于转换无法被识别的对象
*/ */
public static final TripleConverter INSTANCE = new TripleConverter(); public TripleConverter(final Converter rootConverter) {
super(rootConverter);
}
@Override @Override
public Object convert(Type targetType, final Object value) throws ConvertException { public Object convert(Type targetType, final Object value) throws ConvertException {
@ -69,9 +75,9 @@ public class TripleConverter implements Converter {
public Triple<?, ?, ?> convert(final Type leftType, final Type middleType, final Type rightType, final Object value) public Triple<?, ?, ?> convert(final Type leftType, final Type middleType, final Type rightType, final Object value)
throws ConvertException { throws ConvertException {
Map map = null; Map map = null;
if(value instanceof Map){ if (value instanceof Map) {
map = (Map) value; map = (Map) value;
}else if (BeanUtil.isReadableBean(value.getClass())) { } else if (BeanUtil.isReadableBean(value.getClass())) {
// 一次性只读场景包装为Map效率更高 // 一次性只读场景包装为Map效率更高
map = BeanUtil.toBeanMap(value); map = BeanUtil.toBeanMap(value);
} }
@ -92,17 +98,16 @@ public class TripleConverter implements Converter {
* @return Entry * @return Entry
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private static Triple<?, ?, ?> mapToTriple(final Type leftType, final Type middleType, final Type rightType, final Map map) { private Triple<?, ?, ?> mapToTriple(final Type leftType, final Type middleType, final Type rightType, final Map map) {
final Object left = map.get("left"); final Object left = map.get("left");
final Object middle = map.get("middle"); final Object middle = map.get("middle");
final Object right = map.get("right"); final Object right = map.get("right");
final CompositeConverter convert = CompositeConverter.getInstance();
return Triple.of( return Triple.of(
TypeUtil.isUnknown(leftType) ? left : convert.convert(leftType, left), TypeUtil.isUnknown(leftType) ? left : rootConverter.convert(leftType, left),
TypeUtil.isUnknown(middleType) ? middle : convert.convert(middleType, middle), TypeUtil.isUnknown(middleType) ? middle : rootConverter.convert(middleType, middle),
TypeUtil.isUnknown(rightType) ? right : convert.convert(rightType, right) TypeUtil.isUnknown(rightType) ? right : rootConverter.convert(rightType, right)
); );
} }
} }

View File

@ -16,10 +16,10 @@
package org.dromara.hutool.core.lang; package org.dromara.hutool.core.lang;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
import java.util.Map; import java.util.Map;
@ -35,6 +35,7 @@ public class Assert {
private static final String TEMPLATE_VALUE_MUST_BE_BETWEEN_AND = "The value must be between {} and {}."; private static final String TEMPLATE_VALUE_MUST_BE_BETWEEN_AND = "The value must be between {} and {}.";
// region ----- isTrue and isFalse
/** /**
* 断言是否为真如果为 {@code false} 抛出给定的异常<br> * 断言是否为真如果为 {@code false} 抛出给定的异常<br>
@ -135,6 +136,9 @@ public class Assert {
public static void isFalse(final boolean expression) throws IllegalArgumentException { public static void isFalse(final boolean expression) throws IllegalArgumentException {
isFalse(expression, "[Assertion failed] - this expression must be false"); isFalse(expression, "[Assertion failed] - this expression must be false");
} }
// endregion
// region ----- isNull or notNull
/** /**
* 断言对象是否为{@code null} 如果不为{@code null} 抛出指定类型异常 * 断言对象是否为{@code null} 如果不为{@code null} 抛出指定类型异常
@ -186,8 +190,6 @@ public class Assert {
isNull(object, "[Assertion failed] - the object argument must be null"); isNull(object, "[Assertion failed] - the object argument must be null");
} }
// ----------------------------------------------------------------------------------------------------------- Check not null
/** /**
* 断言对象是否不为{@code null} 如果为{@code null} 抛出指定类型异常 * 断言对象是否不为{@code null} 如果为{@code null} 抛出指定类型异常
* 并使用指定的函数获取错误信息返回 * 并使用指定的函数获取错误信息返回
@ -214,10 +216,10 @@ public class Assert {
} }
/** /**
* 断言对象是否不为{@code null} 如果为{@code null} 抛出{@link IllegalArgumentException} 异常 Assert that an object is not {@code null} . * 断言对象是否不为{@code null} 如果为{@code null} 抛出{@link IllegalArgumentException}
* <pre class="code"> * <pre>{@code
* Assert.notNull(clazz, "The class must not be null"); * Assert.notNull(clazz, "The class must not be null");
* </pre> * }</pre>
* *
* @param <T> 被检查对象泛型类型 * @param <T> 被检查对象泛型类型
* @param object 被检查对象 * @param object 被检查对象
@ -227,14 +229,17 @@ public class Assert {
* @throws IllegalArgumentException if the object is {@code null} * @throws IllegalArgumentException if the object is {@code null}
*/ */
public static <T> T notNull(final T object, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException { public static <T> T notNull(final T object, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notNull(object, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params))); if (null == object) {
throw new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params));
}
return object;
} }
/** /**
* 断言对象是否不为{@code null} 如果为{@code null} 抛出{@link IllegalArgumentException} 异常 * 断言对象是否不为{@code null} 如果为{@code null} 抛出{@link IllegalArgumentException} 异常
* <pre class="code"> * <pre>{@code
* Assert.notNull(clazz); * Assert.notNull(clazz);
* </pre> * }</pre>
* *
* @param <T> 被检查对象类型 * @param <T> 被检查对象类型
* @param object 被检查对象 * @param object 被检查对象
@ -242,193 +247,14 @@ public class Assert {
* @throws IllegalArgumentException if the object is {@code null} * @throws IllegalArgumentException if the object is {@code null}
*/ */
public static <T> T notNull(final T object) throws IllegalArgumentException { public static <T> T notNull(final T object) throws IllegalArgumentException {
return notNull(object, "[Assertion failed] - this argument is required; it must not be null"); if (null == object) {
} throw new IllegalArgumentException("[Assertion failed] - this argument is required; it must not be null");
// ----------------------------------------------------------------------------------------------------------- Check empty
/**
* 检查给定字符串是否为空为空抛出自定义异常并使用指定的函数获取错误信息返回
* <pre class="code">
* Assert.notEmpty(name, ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return");
* });
* </pre>
*
* @param <X> 异常类型
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorSupplier 错误抛出异常附带的消息生产接口
* @return 非空字符串
* @throws X 被检查字符串为空抛出此异常
* @see StrUtil#isNotEmpty(CharSequence)
* @since 5.4.5
*/
public static <T extends CharSequence, X extends Throwable> T notEmpty(final T text, final Supplier<X> errorSupplier) throws X {
if (StrUtil.isEmpty(text)) {
throw errorSupplier.get();
} }
return text; return object;
} }
// endregion
/** // region ----- notEmpty and notBlank
* 检查给定字符串是否为空为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notEmpty(name, "Name must not be empty");
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorMsgTemplate 错误消息模板变量使用{}表示
* @param params 参数
* @return 非空字符串
* @throws IllegalArgumentException 被检查字符串为空
* @see StrUtil#isNotEmpty(CharSequence)
*/
public static <T extends CharSequence> T notEmpty(final T text, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notEmpty(text, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 检查给定字符串是否为空为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notEmpty(name);
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @return 被检查的字符串
* @throws IllegalArgumentException 被检查字符串为空
* @see StrUtil#isNotEmpty(CharSequence)
*/
public static <T extends CharSequence> T notEmpty(final T text) throws IllegalArgumentException {
return notEmpty(text, "[Assertion failed] - this String argument must have length; it must not be null or empty");
}
/**
* 检查给定字符串是否为空白null空串或只包含空白符为空抛出自定义异常
* 并使用指定的函数获取错误信息返回
* <pre class="code">
* Assert.notBlank(name, ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return");
* });
* </pre>
*
* @param <X> 异常类型
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorMsgSupplier 错误抛出异常附带的消息生产接口
* @return 非空字符串
* @throws X 被检查字符串为空白
* @see StrUtil#isNotBlank(CharSequence)
*/
public static <T extends CharSequence, X extends Throwable> T notBlank(final T text, final Supplier<X> errorMsgSupplier) throws X {
if (StrUtil.isBlank(text)) {
throw errorMsgSupplier.get();
}
return text;
}
/**
* 检查给定字符串是否为空白null空串或只包含空白符为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notBlank(name, "Name must not be blank");
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorMsgTemplate 错误消息模板变量使用{}表示
* @param params 参数
* @return 非空字符串
* @throws IllegalArgumentException 被检查字符串为空白
* @see StrUtil#isNotBlank(CharSequence)
*/
public static <T extends CharSequence> T notBlank(final T text, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notBlank(text, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 检查给定字符串是否为空白null空串或只包含空白符为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notBlank(name);
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @return 非空字符串
* @throws IllegalArgumentException 被检查字符串为空白
* @see StrUtil#isNotBlank(CharSequence)
*/
public static <T extends CharSequence> T notBlank(final T text) throws IllegalArgumentException {
return notBlank(text, "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
}
/**
* 断言给定字符串是否不被另一个字符串包含即是否为子串并使用指定的函数获取错误信息返回<br>
* 如果非子串返回子串如果是子串则抛出{@link IllegalArgumentException}异常
* <pre class="code">
* Assert.notContain(name, "rod", ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return ");
* });
* </pre>
*
* @param <T> 字符串类型
* @param <X> 异常类型
* @param textToSearch 被搜索的字符串
* @param substring 被检查的子串
* @param errorSupplier 错误抛出异常附带的消息生产接口
* @return 被检查的子串
* @throws X 非子串抛出异常
* @see StrUtil#contains(CharSequence, CharSequence)
* @since 5.4.5
*/
public static <T extends CharSequence, X extends Throwable> T notContain(final CharSequence textToSearch, final T substring, final Supplier<X> errorSupplier) throws X {
if (StrUtil.contains(textToSearch, substring)) {
throw errorSupplier.get();
}
return substring;
}
/**
* 断言给定字符串是否不被另一个字符串包含即是否为子串<br>
* 如果非子串返回子串如果是子串则抛出{@link IllegalArgumentException}异常
* <pre class="code">
* Assert.notContain(name, "rod", "Name must not contain 'rod'");
* </pre>
*
* @param textToSearch 被搜索的字符串
* @param subString 被检查的子串
* @param errorMsgTemplate 异常时的消息模板
* @param params 参数列表
* @return 被检查的子串
* @throws IllegalArgumentException 非子串抛出异常
*/
public static String notContain(final String textToSearch, final String subString, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notContain(textToSearch, subString, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 断言给定字符串是否不被另一个字符串包含即是否为子串即subString是否不是textToSearch的子串<br>
* 如果非子串返回子串如果是子串则抛出{@link IllegalArgumentException}异常
* <pre class="code">
* Assert.notContain(name, "rod");
* </pre>
*
* @param textToSearch 被搜索的字符串
* @param subString 被检查的子串
* @return 被检查的子串
* @throws IllegalArgumentException 非子串抛出异常
*/
public static String notContain(final String textToSearch, final String subString) throws IllegalArgumentException {
return notContain(textToSearch, subString, "[Assertion failed] - this String argument must not contain the substring [{}]", subString);
}
/** /**
* 断言给定数组是否包含元素数组必须不为 {@code null} 且至少包含一个元素 * 断言给定数组是否包含元素数组必须不为 {@code null} 且至少包含一个元素
@ -488,64 +314,6 @@ public class Assert {
return notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element"); return notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element");
} }
/**
* 断言给定数组是否不包含{@code null}元素如果数组为空或 {@code null}将被认为不包含
* 并使用指定的函数获取错误信息返回
* <pre class="code">
* Assert.noNullElements(array, ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return ");
* });
* </pre>
*
* @param <T> 数组元素类型
* @param <X> 异常类型
* @param array 被检查的数组
* @param errorSupplier 错误抛出异常附带的消息生产接口
* @return 被检查的数组
* @throws X if the object array contains a {@code null} element
* @see ArrayUtil#hasNull(Object[])
* @since 5.4.5
*/
public static <T, X extends Throwable> T[] noNullElements(final T[] array, final Supplier<X> errorSupplier) throws X {
if (ArrayUtil.hasNull(array)) {
throw errorSupplier.get();
}
return array;
}
/**
* 断言给定数组是否不包含{@code null}元素如果数组为空或 {@code null}将被认为不包含
* <pre class="code">
* Assert.noNullElements(array, "The array must not have null elements");
* </pre>
*
* @param <T> 数组元素类型
* @param array 被检查的数组
* @param errorMsgTemplate 异常时的消息模板
* @param params 参数列表
* @return 被检查的数组
* @throws IllegalArgumentException if the object array contains a {@code null} element
*/
public static <T> T[] noNullElements(final T[] array, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return noNullElements(array, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 断言给定数组是否不包含{@code null}元素如果数组为空或 {@code null}将被认为不包含
* <pre class="code">
* Assert.noNullElements(array);
* </pre>
*
* @param <T> 数组元素类型
* @param array 被检查的数组
* @return 被检查的数组
* @throws IllegalArgumentException if the object array contains a {@code null} element
*/
public static <T> T[] noNullElements(final T[] array) throws IllegalArgumentException {
return noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
}
/** /**
* 断言给定集合非空 * 断言给定集合非空
* 并使用指定的函数获取错误信息返回 * 并使用指定的函数获取错误信息返回
@ -671,6 +439,255 @@ public class Assert {
return notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry"); return notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
} }
/**
* 检查给定字符串是否为空为空抛出自定义异常并使用指定的函数获取错误信息返回
* <pre class="code">
* Assert.notEmpty(name, ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return");
* });
* </pre>
*
* @param <X> 异常类型
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorSupplier 错误抛出异常附带的消息生产接口
* @return 非空字符串
* @throws X 被检查字符串为空抛出此异常
* @see StrUtil#isNotEmpty(CharSequence)
* @since 5.4.5
*/
public static <T extends CharSequence, X extends Throwable> T notEmpty(final T text, final Supplier<X> errorSupplier) throws X {
if (StrUtil.isEmpty(text)) {
throw errorSupplier.get();
}
return text;
}
/**
* 检查给定字符串是否为空为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notEmpty(name, "Name must not be empty");
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorMsgTemplate 错误消息模板变量使用{}表示
* @param params 参数
* @return 非空字符串
* @throws IllegalArgumentException 被检查字符串为空
* @see StrUtil#isNotEmpty(CharSequence)
*/
public static <T extends CharSequence> T notEmpty(final T text, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notEmpty(text, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 检查给定字符串是否为空为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notEmpty(name);
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @return 被检查的字符串
* @throws IllegalArgumentException 被检查字符串为空
* @see StrUtil#isNotEmpty(CharSequence)
*/
public static <T extends CharSequence> T notEmpty(final T text) throws IllegalArgumentException {
return notEmpty(text, "[Assertion failed] - this String argument must have length; it must not be null or empty");
}
/**
* 检查给定字符串是否为空白null空串或只包含空白符为空抛出自定义异常
* 并使用指定的函数获取错误信息返回
* <pre class="code">
* Assert.notBlank(name, ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return");
* });
* </pre>
*
* @param <X> 异常类型
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorMsgSupplier 错误抛出异常附带的消息生产接口
* @return 非空字符串
* @throws X 被检查字符串为空白
* @see StrUtil#isNotBlank(CharSequence)
*/
public static <T extends CharSequence, X extends Throwable> T notBlank(final T text, final Supplier<X> errorMsgSupplier) throws X {
if (StrUtil.isBlank(text)) {
throw errorMsgSupplier.get();
}
return text;
}
/**
* 检查给定字符串是否为空白null空串或只包含空白符为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notBlank(name, "Name must not be blank");
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @param errorMsgTemplate 错误消息模板变量使用{}表示
* @param params 参数
* @return 非空字符串
* @throws IllegalArgumentException 被检查字符串为空白
* @see StrUtil#isNotBlank(CharSequence)
*/
public static <T extends CharSequence> T notBlank(final T text, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notBlank(text, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 检查给定字符串是否为空白null空串或只包含空白符为空抛出 {@link IllegalArgumentException}
*
* <pre class="code">
* Assert.notBlank(name);
* </pre>
*
* @param <T> 字符串类型
* @param text 被检查字符串
* @return 非空字符串
* @throws IllegalArgumentException 被检查字符串为空白
* @see StrUtil#isNotBlank(CharSequence)
*/
public static <T extends CharSequence> T notBlank(final T text) throws IllegalArgumentException {
return notBlank(text, "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
}
// endregion
// region ----- notContain
/**
* 断言给定字符串是否不被另一个字符串包含即是否为子串并使用指定的函数获取错误信息返回<br>
* 如果非子串返回子串如果是子串则抛出{@link IllegalArgumentException}异常
* <pre class="code">
* Assert.notContain(name, "rod", ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return ");
* });
* </pre>
*
* @param <T> 字符串类型
* @param <X> 异常类型
* @param textToSearch 被搜索的字符串
* @param substring 被检查的子串
* @param errorSupplier 错误抛出异常附带的消息生产接口
* @return 被检查的子串
* @throws X 非子串抛出异常
* @see StrUtil#contains(CharSequence, CharSequence)
* @since 5.4.5
*/
public static <T extends CharSequence, X extends Throwable> T notContain(final CharSequence textToSearch, final T substring, final Supplier<X> errorSupplier) throws X {
if (StrUtil.contains(textToSearch, substring)) {
throw errorSupplier.get();
}
return substring;
}
/**
* 断言给定字符串是否不被另一个字符串包含即是否为子串<br>
* 如果非子串返回子串如果是子串则抛出{@link IllegalArgumentException}异常
* <pre class="code">
* Assert.notContain(name, "rod", "Name must not contain 'rod'");
* </pre>
*
* @param textToSearch 被搜索的字符串
* @param subString 被检查的子串
* @param errorMsgTemplate 异常时的消息模板
* @param params 参数列表
* @return 被检查的子串
* @throws IllegalArgumentException 非子串抛出异常
*/
public static String notContain(final String textToSearch, final String subString, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return notContain(textToSearch, subString, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 断言给定字符串是否不被另一个字符串包含即是否为子串即subString是否不是textToSearch的子串<br>
* 如果非子串返回子串如果是子串则抛出{@link IllegalArgumentException}异常
* <pre class="code">
* Assert.notContain(name, "rod");
* </pre>
*
* @param textToSearch 被搜索的字符串
* @param subString 被检查的子串
* @return 被检查的子串
* @throws IllegalArgumentException 非子串抛出异常
*/
public static String notContain(final String textToSearch, final String subString) throws IllegalArgumentException {
return notContain(textToSearch, subString, "[Assertion failed] - this String argument must not contain the substring [{}]", subString);
}
// endregion
// region ----- noNullElements
/**
* 断言给定数组是否不包含{@code null}元素如果数组为空或 {@code null}将被认为不包含
* 并使用指定的函数获取错误信息返回
* <pre class="code">
* Assert.noNullElements(array, ()-&gt;{
* // to query relation message
* return new IllegalArgumentException("relation message to return ");
* });
* </pre>
*
* @param <T> 数组元素类型
* @param <X> 异常类型
* @param array 被检查的数组
* @param errorSupplier 错误抛出异常附带的消息生产接口
* @return 被检查的数组
* @throws X if the object array contains a {@code null} element
* @see ArrayUtil#hasNull(Object[])
* @since 5.4.5
*/
public static <T, X extends Throwable> T[] noNullElements(final T[] array, final Supplier<X> errorSupplier) throws X {
if (ArrayUtil.hasNull(array)) {
throw errorSupplier.get();
}
return array;
}
/**
* 断言给定数组是否不包含{@code null}元素如果数组为空或 {@code null}将被认为不包含
* <pre class="code">
* Assert.noNullElements(array, "The array must not have null elements");
* </pre>
*
* @param <T> 数组元素类型
* @param array 被检查的数组
* @param errorMsgTemplate 异常时的消息模板
* @param params 参数列表
* @return 被检查的数组
* @throws IllegalArgumentException if the object array contains a {@code null} element
*/
public static <T> T[] noNullElements(final T[] array, final String errorMsgTemplate, final Object... params) throws IllegalArgumentException {
return noNullElements(array, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}
/**
* 断言给定数组是否不包含{@code null}元素如果数组为空或 {@code null}将被认为不包含
* <pre class="code">
* Assert.noNullElements(array);
* </pre>
*
* @param <T> 数组元素类型
* @param array 被检查的数组
* @return 被检查的数组
* @throws IllegalArgumentException if the object array contains a {@code null} element
*/
public static <T> T[] noNullElements(final T[] array) throws IllegalArgumentException {
return noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
}
// endregion
// region ----- isInstanceOf and isAssignable
/** /**
* 断言给定对象是否是给定类的实例 * 断言给定对象是否是给定类的实例
* <pre class="code"> * <pre class="code">
@ -743,6 +760,9 @@ public class Assert {
throw new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)); throw new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params));
} }
} }
// endregion
// region ----- state
/** /**
* 检查boolean表达式当检查结果为false时抛出 {@code IllegalStateException} * 检查boolean表达式当检查结果为false时抛出 {@code IllegalStateException}
@ -793,7 +813,9 @@ public class Assert {
public static void state(final boolean expression) throws IllegalStateException { public static void state(final boolean expression) throws IllegalStateException {
state(expression, "[Assertion failed] - this state invariant must be true"); state(expression, "[Assertion failed] - this state invariant must be true");
} }
// endregion
// region ----- checkIndex
/** /**
* 检查下标数组集合字符串是否符合要求下标必须满足 * 检查下标数组集合字符串是否符合要求下标必须满足
* *
@ -834,6 +856,9 @@ public class Assert {
} }
return index; return index;
} }
// endregion
// region ----- checkBetween
/** /**
* 检查值是否在指定范围内 * 检查值是否在指定范围内
@ -1001,6 +1026,10 @@ public class Assert {
return value; return value;
} }
// endregion
// region ----- equals and notEquals
/** /**
* 断言两个对象是否不相等,如果两个对象相等 抛出IllegalArgumentException 异常 * 断言两个对象是否不相等,如果两个对象相等 抛出IllegalArgumentException 异常
* <pre class="code"> * <pre class="code">
@ -1045,7 +1074,6 @@ public class Assert {
throw errorSupplier.get(); throw errorSupplier.get();
} }
} }
// ----------------------------------------------------------------------------------------------------------- Check not equals
/** /**
* 断言两个对象是否相等,如果两个对象不相等 抛出IllegalArgumentException 异常 * 断言两个对象是否相等,如果两个对象不相等 抛出IllegalArgumentException 异常
@ -1091,8 +1119,7 @@ public class Assert {
throw errorSupplier.get(); throw errorSupplier.get();
} }
} }
// endregion
// ----------------------------------------------------------------------------------------------------------- Check is equals
// -------------------------------------------------------------------------------------------------------------------------------------------- Private method start // -------------------------------------------------------------------------------------------------------------------------------------------- Private method start

View File

@ -40,12 +40,6 @@ public class CompositeConverterTest {
@Data @Data
public static class EmptyBean {} public static class EmptyBean {}
@Test
public void getConverterTest() {
final Converter converter = CompositeConverter.getInstance().getConverter(CharSequence.class, null, false);
assertNotNull(converter);
}
@Test @Test
public void customTest() { public void customTest() {
final int a = 454553; final int a = 454553;

View File

@ -74,8 +74,6 @@ public class JdkHttpConnection implements HeaderOperation<JdkHttpConnection>, Cl
return new JdkHttpConnection(url, proxy); return new JdkHttpConnection(url, proxy);
} }
// region --------------------------------------------------------------- Constructor
/** /**
* 构造HttpConnection * 构造HttpConnection
* *
@ -92,9 +90,7 @@ public class JdkHttpConnection implements HeaderOperation<JdkHttpConnection>, Cl
this.conn.setDoInput(true); this.conn.setDoInput(true);
} }
// endregion --------------------------------------------------------------- Constructor // region ----- Getters And Setters
// region --------------------------------------------------------------- Getters And Setters
/** /**
* 获取请求方法,GET/POST * 获取请求方法,GET/POST
@ -279,9 +275,9 @@ public class JdkHttpConnection implements HeaderOperation<JdkHttpConnection>, Cl
return this; return this;
} }
// endregion --------------------------------------------------------------- Getters And Setters // endregion ----- Getters And Setters
// region ---------------------------------------------------------------- Headers // region ------ Headers
/** /**
* 设置请求头<br> * 设置请求头<br>
@ -327,7 +323,7 @@ public class JdkHttpConnection implements HeaderOperation<JdkHttpConnection>, Cl
return this.conn.getHeaderFields(); return this.conn.getHeaderFields();
} }
// endregion---------------------------------------------------------------- Headers // endregion------ Headers
/** /**
* 连接 * 连接

View File

@ -29,6 +29,7 @@ import org.dromara.hutool.core.reflect.TypeReference;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import org.dromara.hutool.core.reflect.kotlin.KClassUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.*; import org.dromara.hutool.json.*;
import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
@ -59,13 +60,6 @@ public class JSONConverter implements Converter, Serializable {
*/ */
public static final JSONConverter INSTANCE = new JSONConverter(null); public static final JSONConverter INSTANCE = new JSONConverter(null);
static {
final RegisterConverter converter = RegisterConverter.getInstance();
converter.register(JSONObject.class, INSTANCE);
converter.register(JSONArray.class, INSTANCE);
converter.register(JSONPrimitive.class, INSTANCE);
}
/** /**
* 创建JSON转换器 * 创建JSON转换器
* *
@ -73,17 +67,25 @@ public class JSONConverter implements Converter, Serializable {
* @return JSONConverter * @return JSONConverter
*/ */
public static JSONConverter of(final JSONConfig config) { public static JSONConverter of(final JSONConfig config) {
return new JSONConverter(config); final JSONConverter jsonConverter = new JSONConverter(config);
jsonConverter.registerConverter = new RegisterConverter(jsonConverter)
.register(JSONObject.class, INSTANCE)
.register(JSONArray.class, INSTANCE)
.register(JSONPrimitive.class, INSTANCE);
jsonConverter.specialConverter = new SpecialConverter(jsonConverter);
return jsonConverter;
} }
private final JSONConfig config; private final JSONConfig config;
private RegisterConverter registerConverter;
private SpecialConverter specialConverter;
/** /**
* 构造 * 构造
* *
* @param config JSON配置 * @param config JSON配置
*/ */
public JSONConverter(final JSONConfig config) { private JSONConverter(final JSONConfig config) {
this.config = config; this.config = config;
} }
@ -150,7 +152,7 @@ public class JSONConverter implements Converter, Serializable {
obj = ((Opt<?>) obj).getOrNull(); obj = ((Opt<?>) obj).getOrNull();
} }
if(obj instanceof JSON){ if (obj instanceof JSON) {
return (JSON) obj; return (JSON) obj;
} }
@ -242,33 +244,41 @@ public class JSONConverter implements Converter, Serializable {
final Object value; final Object value;
// JSON原始类型 // JSON原始类型
if(json instanceof JSONPrimitive){ if (json instanceof JSONPrimitive) {
value = ((JSONPrimitive) json).getValue(); value = ((JSONPrimitive) json).getValue();
} else { } else {
value = json; value = json;
} }
// 标准转换器 final JSONConfig config = ObjUtil.defaultIfNull(json.config(), JSONConfig::of);
final Converter converter = RegisterConverter.getInstance().getConverter(targetType, value, true); final boolean ignoreError = config.isIgnoreError();
if (null != converter) { try {
return (T) converter.convert(targetType, value); // 标准转换器
} final Converter converter = registerConverter.getConverter(targetType, value, true);
if (null != converter) {
return (T) converter.convert(targetType, value);
}
// 特殊类型转换包括CollectionMap强转Array等 // 特殊类型转换包括CollectionMap强转Array等
final T result = (T) SpecialConverter.getInstance().convert(targetType, rawType, value); final T result = (T) specialConverter.convert(targetType, rawType, value);
if (null != result) { if (null != result) {
return result; return result;
}
} catch (final ConvertException e) {
if (ignoreError) {
return null;
}
} }
// 尝试转Bean // 尝试转Bean
if (BeanUtil.isWritableBean(rawType)) { if (BeanUtil.isWritableBean(rawType)) {
return BeanCopier.of(value, return BeanCopier.of(value,
ConstructorUtil.newInstanceIfPossible(rawType), targetType, ConstructorUtil.newInstanceIfPossible(rawType), targetType,
InternalJSONUtil.toCopyOptions(json.config())).copy(); InternalJSONUtil.toCopyOptions(config)).copy();
} }
// 跳过异常时返回null // 跳过异常时返回null
if (json.config().isIgnoreError()) { if (ignoreError) {
return null; return null;
} }

View File

@ -16,28 +16,41 @@
package org.dromara.hutool.json; package org.dromara.hutool.json;
import lombok.Data;
import org.dromara.hutool.core.io.resource.ResourceUtil; import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.lang.Console; import org.junit.jupiter.api.Assertions;
import org.dromara.hutool.json.test.bean.ResultBean;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List;
/** /**
* 测试在bean转换时使用BeanConverter默认忽略转换失败的字段 * 转换失败则在设置setIgnoreError(true)不报错
* 现阶段Converter的问题在于无法更细粒度的控制转换失败的范围例如Bean的一个字段为List
* list任意一个item转换失败都会导致这个list为null
* <p>
* TODO 需要在Converter中添加ConvertOption用于更细粒度的控制转换规则
*/ */
public class Issue1200Test { public class Issue1200Test {
@Test @Test
@Disabled public void toBeanTest() {
public void toBeanTest(){ final JSONObject jsonObject = JSONUtil.parseObj(
final JSONObject jsonObject = JSONUtil.parseObj(ResourceUtil.readUtf8Str("issue1200.json")); ResourceUtil.readUtf8Str("issue1200.json"),
Console.log(jsonObject); JSONConfig.of().setIgnoreError(true));
final ResultBean resultBean = jsonObject.toBean(ResultBean.class); final ResultBean resultBean = jsonObject.toBean(ResultBean.class);
Console.log(resultBean); Assertions.assertNull(resultBean.getItems().get(0).get(0));
}
@Data
static
class ResultBean {
public List<List<List<ResultBean.ItemsBean>>> items;
@Data
public static class ItemsBean {
public ResultBean.ItemsBean.DetailBean detail;
@Data
public static class DetailBean {
public String visitorStatus;
}
}
} }
} }

View File

@ -193,7 +193,7 @@ public class JSONArrayTest {
@Test @Test
public void toListWithErrorTest() { public void toListWithErrorTest() {
Assertions.assertThrows(ConvertException.class, ()->{ Assertions.assertThrows(JSONException.class, ()->{
final String json = "[['aaa',{'akey':'avalue','bkey':'bvalue'}]]"; final String json = "[['aaa',{'akey':'avalue','bkey':'bvalue'}]]";
final JSONArray ja = JSONUtil.parseArray(json); final JSONArray ja = JSONUtil.parseArray(json);

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.json.test.bean;
import lombok.Data;
import java.util.List;
@Data
public class ResultBean {
public List<List<List<ItemsBean>>> items;
@Data
public static class ItemsBean {
public DetailBean detail;
@Data
public static class DetailBean {
public String visitorStatus;
}
}
}