add Deserializer

This commit is contained in:
Looly 2024-09-20 01:35:28 +08:00
parent 91d425ba63
commit b68e23ac32
16 changed files with 491 additions and 52 deletions

View File

@ -24,10 +24,10 @@ import java.lang.reflect.Type;
* 在Bean注入过程中Bean获得字段名通过外部方式根据这个字段名查找相应的字段值然后注入Bean<br>
*
* @author Looly
* @param <T> KEY类型一般情况下为 {@link String}
* @param <K> KEY类型一般情况下为 {@link String}
*
*/
public interface ValueProvider<T>{
public interface ValueProvider<K>{
/**
* 获取值<br>
@ -37,7 +37,7 @@ public interface ValueProvider<T>{
* @param valueType 被注入的值的类型
* @return 对应参数名的值
*/
Object value(T key, Type valueType);
Object value(K key, Type valueType);
/**
* 是否包含指定KEY如果不包含则忽略注入<br>
@ -46,5 +46,5 @@ public interface ValueProvider<T>{
* @param key Bean对象中参数名
* @return 是否包含指定KEY
*/
boolean containsKey(T key);
boolean containsKey(K key);
}

View File

@ -740,11 +740,17 @@ public class CollUtil {
*
* @param <T> 集合元素类型rawtype ArrayList.class, EnumSet.class ...
* @param collectionType 集合类型
* @param elementType 集合元素类只用于EnumSet创建如果创建EnumSet则此参数必须非空
* @return 集合类型对应的实例
* @since 3.0.8
*/
public static <T> Collection<T> create(final Class<?> collectionType) {
return create(collectionType, null);
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> Collection<T> create(final Class<?> collectionType, final Class<T> elementType) {
if (collectionType.isAssignableFrom(EnumSet.class)) {
return (Collection<T>) EnumSet.noneOf((Class<Enum>) Assert.notNull(elementType));
}
return create(collectionType);
}
/**
@ -752,12 +758,11 @@ public class CollUtil {
*
* @param <T> 集合元素类型rawtype ArrayList.class, EnumSet.class ...
* @param collectionType 集合类型
* @param elementType 集合元素类只用于EnumSet创建如果创建EnumSet则此参数必须非空
* @return 集合类型对应的实例
* @since 3.0.8
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> Collection<T> create(final Class<?> collectionType, final Class<T> elementType) {
@SuppressWarnings({"unchecked"})
public static <T> Collection<T> create(final Class<?> collectionType) {
final Collection<T> list;
if (collectionType.isAssignableFrom(AbstractCollection.class)) {
// 抽象集合默认使用ArrayList
@ -777,8 +782,6 @@ public class CollUtil {
}
return CompareUtil.compare(o1.toString(), o2.toString());
});
} else if (collectionType.isAssignableFrom(EnumSet.class)) {
list = (Collection<T>) EnumSet.noneOf((Class<Enum>) Assert.notNull(elementType));
}
// List

View File

@ -38,7 +38,7 @@ import java.util.function.Predicate;
*
* @author Looly
*/
public interface JSON extends Converter, Cloneable, Serializable {
public interface JSON extends Converter, Serializable {
/**
* 获取JSON配置

View File

@ -50,7 +50,7 @@ public class JSONArray extends ListWrapper<JSON> implements JSON, JSONGetter<Int
/**
* 配置项
*/
private JSONConfig config;
private final JSONConfig config;
// region ----- Constructors
@ -314,11 +314,4 @@ public class JSONArray extends ListWrapper<JSON> implements JSON, JSONGetter<Int
CollUtil.forEach(this, (index, value) -> writer.writeField(new MutableEntry<>(index, value)));
writer.endArray();
}
@Override
public Object clone() throws CloneNotSupportedException {
final JSONArray clone = (JSONArray) super.clone();
clone.config = this.config;
return clone;
}
}

View File

@ -46,15 +46,6 @@ public class JSONPrimitive implements Wrapper<Object>, JSON {
*/
private JSONConfig config;
/**
* 构造
*
* @param value
*/
public JSONPrimitive(final Object value) {
this(value, null);
}
/**
* 构造
*
@ -116,6 +107,24 @@ public class JSONPrimitive implements Wrapper<Object>, JSON {
return value instanceof Number;
}
/**
* 是否为布尔类型
*
* @return 是否为布尔类型
*/
public boolean isBoolean() {
return value instanceof Boolean;
}
/**
* 是否为字符串类型
*
* @return 是否为字符串类型
*/
public boolean isString() {
return value instanceof String;
}
/**
* 自增仅支持数字类型包括
* <ul>

View File

@ -106,28 +106,38 @@ class JSONArrayMapper {
return;
}
Object next;
while (iter.hasNext()) {
next = iter.next();
// 检查循环引用
if (next != source) {
if(null != this.predicate){
final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), next);
if (predicate.test(entry)) {
// 使用修改后的键值对
next = entry.getValue();
jsonArray.set(next);
}
}else {
mapFromIterator(iter, jsonArray);
}
}
/**
* 从Iterator中读取数据并添加到JSONArray中
*
* @param iter {@link Iterator}
* @param jsonArray {@link JSONArray}
*/
private void mapFromIterator(final Iterator<?> iter, final JSONArray jsonArray) {
Object next;
while (iter.hasNext()) {
next = iter.next();
// 检查循环引用
if (next != source) {
if (null != this.predicate) {
final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), next);
if (predicate.test(entry)) {
// 使用修改后的键值对
next = entry.getValue();
jsonArray.set(next);
}
} else {
jsonArray.set(next);
}
}
}
}
/**
* 初始化
* 从JSONTokener中读取数据并添加到JSONArray中
*
* @param x {@link JSONTokener}
* @param jsonArray {@link JSONArray}

View File

@ -264,11 +264,11 @@ public class JSONParser {
case CharUtil.DOUBLE_QUOTES:
case CharUtil.SINGLE_QUOTE:
// 引号包围表示字符串值
return new JSONPrimitive(tokener.nextWrapString(firstChar));
return new JSONPrimitive(tokener.nextWrapString(firstChar), config);
default:
final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(firstChar));
// 非引号包围可能为boolean数字null等
return null == value ? null : new JSONPrimitive(value);
return null == value ? null : new JSONPrimitive(value, config);
}
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.serializer;
import org.dromara.hutool.core.bean.copier.ValueProvider;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONObject;
import java.lang.reflect.Type;
/**
* JSONObject值提供者用于将JSONObject中的值注入Bean
*
* @author Looly
* @since 6.0.0
*/
public class JSONObjectValueProvider implements ValueProvider<String> {
private final JSONObject jsonObject;
/**
* 构造
*
* @param jsonObject JSON对象
*/
public JSONObjectValueProvider(final JSONObject jsonObject) {
this.jsonObject = jsonObject;
}
@Override
public Object value(final String key, final Type valueType) {
final JSON value = jsonObject.get(key);
if (null == value) {
return null;
}
return value.toBean(valueType);
}
@Override
public boolean containsKey(final String key) {
return jsonObject.containsKey(key);
}
}

View File

@ -23,9 +23,7 @@ import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.serializer.impl.KotlinDeserializer;
import org.dromara.hutool.json.serializer.impl.TemporalAccessorSerializer;
import org.dromara.hutool.json.serializer.impl.TimeZoneSerializer;
import org.dromara.hutool.json.serializer.impl.*;
import java.lang.reflect.Type;
import java.time.LocalDate;
@ -313,7 +311,11 @@ public class SerializerManager {
manager.register((MatcherJSONDeserializer<TimeZone>) TimeZoneSerializer.INSTANCE);
// issue#I5WDP0 对于Kotlin对象由于参数可能非空限制导致无法创建一个默认的对象再赋值
manager.register(KotlinDeserializer.INSTANCE);
manager.register(KBeanDeserializer.INSTANCE);
manager.register(CollectionDeserializer.INSTANCE);
manager.register(MapDeserializer.INSTANCE);
manager.register(EntryDeserializer.INSTANCE);
manager.register(RecordDeserializer.INSTANCE);
}
// endregion
}

View File

@ -0,0 +1,94 @@
/*
* 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.serializer.impl;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONArray;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
/**
* 集合类型反序列化器
*
* @author looly
* @since 6.0.0
*/
public class CollectionDeserializer implements MatcherJSONDeserializer<Collection<?>> {
/**
* 单例
*/
public static final CollectionDeserializer INSTANCE = new CollectionDeserializer();
@Override
public boolean match(final JSON json, final Type deserializeType) {
if(json instanceof JSONArray || json instanceof JSONObject){
final Class<?> rawType = TypeUtil.getClass(deserializeType);
return Collection.class.isAssignableFrom(rawType);
}
return false;
}
@Override
public Collection<?> deserialize(final JSON json, final Type deserializeType) {
if (json instanceof JSONObject) {
return toCollection((JSONObject) json, deserializeType, TypeUtil.getClass(deserializeType));
}
return toCollection((JSONArray) json, deserializeType, TypeUtil.getClass(deserializeType));
}
/**
* 将JSONObject转换为集合
*
* @param json JSONObject
* @param deserializeType 反序列化类型
* @param rawType 集合类型
* @return 集合
*/
private Collection<?> toCollection(final JSONObject json, final Type deserializeType, final Class<?> rawType) {
final Type elementType = TypeUtil.getTypeArgument(deserializeType);
final Collection<?> result = CollUtil.create(rawType, TypeUtil.getClass(elementType));
for (final Map.Entry<String, JSON> entry : json) {
result.add(entry.getValue().toBean(elementType));
}
return result;
}
/**
* 将JSONArray转换为集合
*
* @param json JSONArray
* @param deserializeType 反序列化类型
* @param rawType 集合类型
* @return 集合
*/
private Collection<?> toCollection(final JSONArray json, final Type deserializeType, final Class<?> rawType) {
final Type elementType = TypeUtil.getTypeArgument(deserializeType);
final Collection<?> result = CollUtil.create(rawType, TypeUtil.getClass(elementType));
for (final JSON element : json) {
result.add(element.toBean(elementType));
}
return result;
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.serializer.impl;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.*;
import org.dromara.hutool.json.serializer.JSONDeserializer;
import java.lang.reflect.Type;
/**
* 默认反序列化器用于处理未匹配的JSON类型
*
* @author looly
* @since 6.0.0
*/
public class DefaultDeserializer implements JSONDeserializer<Object> {
@Override
public Object deserialize(final JSON json, final Type deserializeType) {
// 当目标类型不确定时返回原JSON
final Class<?> rawType = TypeUtil.getClass(deserializeType);
if (null == rawType || JSON.class.isAssignableFrom(rawType)) {
return json;
}
if (json instanceof JSONObject) {
return fromJSONObject((JSONObject) json, deserializeType, rawType);
} else if (json instanceof JSONArray) {
return fromJSONArray((JSONArray) json, deserializeType, rawType);
} else if (json instanceof JSONPrimitive) {
return fromJSONPrimitive((JSONPrimitive) json, deserializeType, rawType);
}
throw new JSONException("Unsupported JSON type: {}", json.getClass());
}
private Object fromJSONObject(final JSONObject json, final Type deserializeType, final Class<?> rawType) {
return json;
}
private Object fromJSONArray(final JSONArray json, final Type deserializeType, final Class<?> rawType) {
return json;
}
private Object fromJSONPrimitive(final JSONPrimitive json, final Type deserializeType, final Class<?> rawType) {
return json;
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.serializer.impl;
import org.dromara.hutool.core.convert.CompositeConverter;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
import java.lang.reflect.Type;
import java.util.Map;
/**
* Map.Entry反序列化器用于将JSON对象转换为Map.Entry对象
*
* @author looly
* @since 6.0.0
*/
public class EntryDeserializer implements MatcherJSONDeserializer<Map.Entry<?, ?>> {
/**
* 单例
*/
public static final EntryDeserializer INSTANCE = new EntryDeserializer();
@Override
public boolean match(final JSON json, final Type deserializeType) {
if(json instanceof JSONObject){
final Class<?> rawType = TypeUtil.getClass(deserializeType);
return Map.Entry.class.isAssignableFrom(rawType);
}
return false;
}
@Override
public Map.Entry<?, ?> deserialize(final JSON json, final Type deserializeType) {
final Type keyType = TypeUtil.getTypeArgument(deserializeType, 0);
final Type valueType = TypeUtil.getTypeArgument(deserializeType, 1);
return toEntry(deserializeType, keyType, valueType, (JSONObject) json);
}
/**
* Map转Entry
*
* @param targetType 目标的Map类型
* @param keyType 键类型
* @param valueType 值类型
* @param json JSONObject
* @return Entry
*/
private Map.Entry<?, ?> toEntry(final Type targetType, final Type keyType,
final Type valueType, final JSONObject json) {
final String key;
final JSON value;
if (1 == json.size()) {
final Map.Entry<String, JSON> entry = json.iterator().next();
key = entry.getKey();
value = entry.getValue();
} else {
// 忽略Map中其它属性
key = json.getStr("key");
value = json.get("value");
}
return (Map.Entry<?, ?>) ConstructorUtil.newInstance(TypeUtil.getClass(targetType),
TypeUtil.isUnknown(keyType) ? key : CompositeConverter.getInstance().convert(keyType, key),
TypeUtil.isUnknown(valueType) ? value : value.toBean(valueType)
);
}
}

View File

@ -32,12 +32,12 @@ import java.lang.reflect.Type;
* @author looly
* @since 6.0.0
*/
public class KotlinDeserializer implements MatcherJSONDeserializer<Object> {
public class KBeanDeserializer implements MatcherJSONDeserializer<Object> {
/**
* 单例
*/
public static final MatcherJSONDeserializer<?> INSTANCE = new KotlinDeserializer();
public static final MatcherJSONDeserializer<?> INSTANCE = new KBeanDeserializer();
@Override
public boolean match(final JSON json, final Type deserializeType) {

View File

@ -0,0 +1,68 @@
/*
* 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.serializer.impl;
import org.dromara.hutool.core.convert.CompositeConverter;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Map反序列化器用于将JSON对象转换为Map对象
*
* @author looly
* @since 6.0.0
*/
public class MapDeserializer implements MatcherJSONDeserializer<Map<?, ?>> {
/**
* 单例
*/
public static final MapDeserializer INSTANCE = new MapDeserializer();
@Override
public boolean match(final JSON json, final Type deserializeType) {
if(json instanceof JSONObject){
final Class<?> rawType = TypeUtil.getClass(deserializeType);
return Map.class.isAssignableFrom(rawType);
}
return false;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Map<?, ?> deserialize(final JSON json, final Type deserializeType) {
final Map map = MapUtil.createMap(TypeUtil.getClass(deserializeType), LinkedHashMap::new);
final Type keyType = TypeUtil.getTypeArgument(deserializeType, 0);
final Type valueType = TypeUtil.getTypeArgument(deserializeType, 1);
for (final Map.Entry<String, JSON> entry : (JSONObject) json) {
map.put(
// key类型为String转目标类型使用标准转换器
CompositeConverter.getInstance().convert(keyType, entry.getKey()),
entry.getValue().toBean(valueType)
);
}
return map;
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.serializer.impl;
import org.dromara.hutool.core.bean.RecordUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.serializer.JSONObjectValueProvider;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
import java.lang.reflect.Type;
/**
* Record反序列化器用于将JSON对象转换为Record类型对象
*
* @author looly
* @since 6.0.0
*/
public class RecordDeserializer implements MatcherJSONDeserializer<Object> {
/**
* 单例
*/
public static final RecordDeserializer INSTANCE = new RecordDeserializer();
@Override
public boolean match(final JSON json, final Type deserializeType) {
if(json instanceof JSONObject){
final Class<?> rawType = TypeUtil.getClass(deserializeType);
return RecordUtil.isRecord(rawType);
}
return false;
}
@Override
public Object deserialize(final JSON json, final Type deserializeType) {
return RecordUtil.newInstance(TypeUtil.getClass(deserializeType),
new JSONObjectValueProvider((JSONObject) json));
}
}

View File

@ -51,7 +51,7 @@ public class TimeZoneSerializer implements MatcherJSONSerializer<TimeZone>, Matc
@Override
public JSON serialize(final TimeZone bean, final JSONContext context) {
return new JSONPrimitive(bean.getID());
return new JSONPrimitive(bean.getID(), context.config());
}
@Override