All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.wjybxx.dson.codec.ConverterUtils Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * Copyright 2023-2024 wjybxx([email protected])
 *
 * 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 cn.wjybxx.dson.codec;

import cn.wjybxx.dson.codec.codecs.*;
import cn.wjybxx.dson.text.*;
import cn.wjybxx.dson.types.*;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

/**
 * @author wjybxx
 * date 2023/3/31
 */
public class ConverterUtils {

    private static final MethodType SUPPLIER_INVOKE_TYPE = MethodType.methodType(Supplier.class);
    private static final MethodType SUPPLIER_GET_METHOD_TYPE = MethodType.methodType(Object.class);

    private static final Map, Class> wrapperToPrimitiveTypeMap = new IdentityHashMap<>(9);
    private static final Map, Class> primitiveTypeToWrapperMap = new IdentityHashMap<>(9);
    private static final Map, Object> primitiveTypeDefaultValueMap = new IdentityHashMap<>(9);

    /** 类型id注册表 */
    public static final TypeMetaRegistry TYPE_META_REGISTRY;
    /** 内置的所有编解码器 */
    public static final List> BUILTIN_CODECS;

    static {
        wrapperToPrimitiveTypeMap.put(Boolean.class, boolean.class);
        wrapperToPrimitiveTypeMap.put(Byte.class, byte.class);
        wrapperToPrimitiveTypeMap.put(Character.class, char.class);
        wrapperToPrimitiveTypeMap.put(Double.class, double.class);
        wrapperToPrimitiveTypeMap.put(Float.class, float.class);
        wrapperToPrimitiveTypeMap.put(Integer.class, int.class);
        wrapperToPrimitiveTypeMap.put(Long.class, long.class);
        wrapperToPrimitiveTypeMap.put(Short.class, short.class);
        wrapperToPrimitiveTypeMap.put(Void.class, void.class);

        for (Map.Entry, Class> entry : wrapperToPrimitiveTypeMap.entrySet()) {
            primitiveTypeToWrapperMap.put(entry.getValue(), entry.getKey());
        }

        primitiveTypeDefaultValueMap.put(Boolean.class, Boolean.FALSE);
        primitiveTypeDefaultValueMap.put(Byte.class, (byte) 0);
        primitiveTypeDefaultValueMap.put(Character.class, (char) 0);
        primitiveTypeDefaultValueMap.put(Double.class, 0d);
        primitiveTypeDefaultValueMap.put(Float.class, 0f);
        primitiveTypeDefaultValueMap.put(Integer.class, 0);
        primitiveTypeDefaultValueMap.put(Long.class, 0L);
        primitiveTypeDefaultValueMap.put(Short.class, (short) 0);
        primitiveTypeDefaultValueMap.put(Void.class, null);

        // 内置codec类型
        TYPE_META_REGISTRY = TypeMetaRegistries.fromMetas(builtinTypeMetas());
        BUILTIN_CODECS = builtinCodecs();
    }

    // region 初始化

    private static TypeMeta typeMetaOf(Class clazz, int classId, String clsName) {
        if (clsName == null) {
            clsName = clazz.getSimpleName();
        }
        return TypeMeta.of(clazz, ObjectStyle.INDENT, clsName, ClassId.ofDefaultNameSpace(classId));
    }

    private static List builtinTypeMetas() {
        return List.of(
                typeMetaOf(int[].class, (1), null),
                typeMetaOf(long[].class, (2), null),
                typeMetaOf(float[].class, (3), null),
                typeMetaOf(double[].class, (4), null),
                typeMetaOf(boolean[].class, (5), null),
                typeMetaOf(String[].class, (6), null),
                typeMetaOf(short[].class, (7), null),
                typeMetaOf(char[].class, (8), null),

                typeMetaOf(Object[].class, (11), null),
                typeMetaOf(Collection.class, (12), null),
                typeMetaOf(Map.class, (13), null),

                // 常用具体类型集合
                typeMetaOf(LinkedList.class, (21), null),
                typeMetaOf(ArrayDeque.class, (22), null),
                typeMetaOf(IdentityHashMap.class, (23), null),
                typeMetaOf(ConcurrentHashMap.class, (24), null),

                // 日期
                typeMetaOf(LocalDateTime.class, (26), null),
                typeMetaOf(LocalDate.class, (27), null),
                typeMetaOf(LocalTime.class, (28), null),
                typeMetaOf(Instant.class, (29), null),
                typeMetaOf(DurationCodec.class, (30), null),

                // dson内建结构
                typeMetaOf(Binary.class, (31), "bin"),
                typeMetaOf(ExtInt32.class, (32), "ei"),
                typeMetaOf(ExtInt64.class, (33), "eL"),
                typeMetaOf(ExtDouble.class, (34), "ed"),
                typeMetaOf(ExtString.class, (35), "es"),
                typeMetaOf(ObjectRef.class, (36), "ref"),
                typeMetaOf(OffsetTimestamp.class, (37), "dt")
        );
    }

    private static List> builtinCodecs() {
        return List.of(
                new IntArrayCodec(),
                new LongArrayCodec(),
                new FloatArrayCodec(),
                new DoubleArrayCodec(),
                new BooleanArrayCodec(),
                new StringArrayCodec(),
                new ShortArrayCodec(),
                new CharArrayCodec(),

                new ObjectArrayCodec(),
                new CollectionCodec<>(Collection.class, null),
                new MapCodec<>(Map.class, null),

                // 常用具体类型集合 -- 不含默认解码类型的超类
                new CollectionCodec<>(LinkedList.class, LinkedList::new),
                new CollectionCodec<>(ArrayDeque.class, ArrayDeque::new),
                new MapCodec<>(IdentityHashMap.class, IdentityHashMap::new),
                new MapCodec<>(ConcurrentHashMap.class, ConcurrentHashMap::new),

                // 日期类型
                new LocalDateTimeCodec(),
                new LocalDateCodec(),
                new LocalTimeCodec(),
                new InstantCodec(),
                new DurationCodec(),

                // dson内建结构
                new BinaryCodec(),
                new ExtInt32Codec(),
                new ExtInt64Codec(),
                new ExtDoubleCodec(),
                new ExtStringCodec(),
                new ObjectRefCodec(),
                new TimestampCodec()
        );
    }

    // endregion

    public static TypeMetaRegistry getDefaultTypeMetaRegistry() {
        return TYPE_META_REGISTRY;
    }

    public static Object getDefaultValue(Class type) {
        return type.isPrimitive() ? primitiveTypeDefaultValueMap.get(type) : null;
    }

    public static Class boxIfPrimitiveType(Class type) {
        return type.isPrimitive() ? primitiveTypeToWrapperMap.get(type) : type;
    }

    public static Class unboxIfWrapperType(Class type) {
        final Class result = wrapperToPrimitiveTypeMap.get(type);
        return result == null ? type : result;
    }

    public static boolean isBoxType(Class type) {
        return wrapperToPrimitiveTypeMap.containsKey(type);
    }

    public static boolean isPrimitiveType(Class type) {
        return type.isPrimitive();
    }

    /**
     * 测试右手边的类型是否可以赋值给左边的类型。
     * 基本类型和其包装类型之间将认为是可赋值的。
     *
     * @param lhsType 基类型
     * @param rhsType 测试的类型
     * @return 如果测试的类型可以赋值给基类型则返回true,否则返回false
     */
    public static boolean isAssignable(Class lhsType, Class rhsType) {
        Objects.requireNonNull(lhsType, "Left-hand side type must not be null");
        Objects.requireNonNull(rhsType, "Right-hand side type must not be null");
        if (lhsType.isAssignableFrom(rhsType)) {
            return true;
        }
        if (lhsType.isPrimitive()) {
            Class resolvedPrimitive = wrapperToPrimitiveTypeMap.get(rhsType);
            return (lhsType == resolvedPrimitive);
        } else {
            // rhsType.isPrimitive
            Class resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
            return (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper));
        }
    }

    /**
     * 测试给定的值是否可以赋值给定的类型。
     * 基本类型和其包装类型之间将认为是可赋值的,但null值不可以赋值给基本类型。
     *
     * @param type  目标类型
     * @param value 测试的值
     * @return 如果目标值可以赋值给目标类型则返回true
     */
    public static boolean isAssignableValue(Class type, @Nullable Object value) {
        Objects.requireNonNull(type, "Type must not be null");
        return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive());
    }

    /**
     * {@code java.lang.ClassCastException: Cannot cast java.lang.Integer to int}
     * {@link Class#cast(Object)}对基本类型有坑。。。。
     */
    public static  T castValue(Class type, Object value) {
        if (type.isPrimitive()) {
            @SuppressWarnings("unchecked") final Class boxedType = (Class) primitiveTypeToWrapperMap.get(type);
            return boxedType.cast(value);
        } else {
            return type.cast(value);
        }
    }

    /** List转Array */
    @SuppressWarnings("unchecked")
    public static  T convertList2Array(List list, Class arrayType) {
        final Class componentType = arrayType.getComponentType();
        final int length = list.size();

        if (list.getClass() == ArrayList.class && !componentType.isPrimitive()) {
            final E[] tempArray = (E[]) Array.newInstance(componentType, length);
            return (T) list.toArray(tempArray);
        }
        // System.arrayCopy并不支持对象数组到基础类型数组
        final T tempArray = (T) Array.newInstance(componentType, length);
        for (int index = 0; index < length; index++) {
            Object element = list.get(index);
            Array.set(tempArray, index, element);
        }
        return tempArray;
    }

    // region converter

    /** 枚举实例可能是枚举类的子类,如果枚举实例声明了代码块{},在编解码时需要转换为声明类 */
    public static Class getEncodeClass(Object value) {
        if (value instanceof Enum e) {
            return e.getDeclaringClass();
        } else {
            return value.getClass();
        }
    }

    /** 注意:默认情况下map是一个数组对象,而不是普通的对象 */
    public static  boolean isEncodeAsArray(Class encoderClass) {
        return encoderClass.isArray()
                || Collection.class.isAssignableFrom(encoderClass)
                || Map.class.isAssignableFrom(encoderClass);
    }

    @Nonnull
    public static INumberStyle castNumberStyle(IStyle style) {
        return style instanceof INumberStyle numberStyle ? numberStyle : NumberStyle.SIMPLE;
    }

    @Nonnull
    public static StringStyle castStringStyle(IStyle style) {
        return style instanceof StringStyle stringStyle ? stringStyle : StringStyle.AUTO;
    }

    @Nullable
    public static ObjectStyle castObjectStyle(IStyle style) {
        return style instanceof ObjectStyle objectStyle ? objectStyle : null;
    }

    /** 查找数组成员类型的泛型参数 */
    public static TypeArgInfo findComponentTypeArg(Class declaredType) {
        Class componentType = declaredType.getComponentType();
        if (componentType == null) {
            throw new IllegalArgumentException("declaredType is not arrayType, info " + declaredType);
        }
        return TypeArgInfo.of(componentType);
    }
    // endregion

    // region 对外api

    /** 无参构造函数转lambda实例 -- 可避免解码过程中的反射 */
    public static  Supplier noArgConstructorToSupplier(MethodHandles.Lookup lookup, Constructor constructor) throws Throwable {
        Class returnType = constructor.getDeclaringClass();
        CallSite callSite = LambdaMetafactory.metafactory(lookup,
                "get", SUPPLIER_INVOKE_TYPE, SUPPLIER_GET_METHOD_TYPE,
                lookup.unreflectConstructor(constructor),
                MethodType.methodType(returnType));

        @SuppressWarnings("unchecked") Supplier supplier = (Supplier) callSite.getTarget().invoke();
        return supplier;
    }

    /** @param lookup 外部缓存实例,避免每次创建的开销 */
    public static > CollectionCodec createCollectionCodec(MethodHandles.Lookup lookup, Class clazz) {
        try {
            Constructor constructor = clazz.getConstructor();
            Supplier factory = noArgConstructorToSupplier(lookup, constructor);
            return new CollectionCodec<>(clazz, factory);
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static > MapCodec createMapCodec(MethodHandles.Lookup lookup, Class clazz) throws Throwable {
        try {
            Constructor constructor = clazz.getConstructor();
            Supplier factory = noArgConstructorToSupplier(lookup, constructor);
            return new MapCodec<>(clazz, factory);
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    // endregion
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy