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

pers.clare.hisql.util.ClassUtil Maven / Gradle / Ivy

The newest version!
package pers.clare.hisql.util;

import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;
import pers.clare.hisql.repository.SQLCrudRepository;

import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;

public class ClassUtil {

    private static final ConcurrentMap, Method[]> classDeclaredMethodsMap = new ConcurrentHashMap<>();
    private static final ConcurrentMap, Field[]> classDeclaredFieldsMap = new ConcurrentHashMap<>();

    private static final ConcurrentMap, Map> classNameFieldMap = new ConcurrentHashMap<>();
    private static final ConcurrentMap, List> classOrderMethodsMap = new ConcurrentHashMap<>();
    private static final ConcurrentMap, List> classOrderFieldsMap = new ConcurrentHashMap<>();


    public static Method[] getDeclaredMethods(Class clazz) {
        return classDeclaredMethodsMap.computeIfAbsent(clazz, Class::getDeclaredMethods);
    }

    public static Field[] getDeclaredFields(Class clazz) {
        return classDeclaredFieldsMap.computeIfAbsent(clazz, (c) -> {
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
            }
            return fields;
        });
    }

    public static Map getNameFieldMap(Class clazz) {
        return classNameFieldMap.computeIfAbsent(clazz, ClassUtil::toNameFieldMap);
    }

    private static Map toNameFieldMap(Class clazz) {
        Map fieldMap = new HashMap<>();
        for (Field field : getDeclaredFields(clazz)) {
            fieldMap.put(field.getName(), field);
        }
        return fieldMap;
    }

    public static List getOrderGetMethods(Class clazz) {
        return classOrderMethodsMap.computeIfAbsent(clazz, ClassUtil::toOrderGetMethods);
    }

    private static List toOrderGetMethods(Class clazz) {
        Map fieldMap = getNameFieldMap(clazz);
        return sort(ClassUtil.getDeclaredMethods(clazz), ClassUtil::isGetMethod, (o) -> {
            Order order = o.getAnnotation(Order.class);
            if (order == null) {
                Field field = fieldMap.get(methodToFieldName(o.getName()));
                if (field != null) {
                    order = field.getAnnotation(Order.class);
                }
            }
            return order;
        });
    }

    public static List getOrderFields(Class clazz) {
        return classOrderFieldsMap.computeIfAbsent(clazz, ClassUtil::toOrderFields);
    }

    private static List toOrderFields(Class clazz) {
        return sort(ClassUtil.getDeclaredFields(clazz), (f) -> true, (f) -> f.getAnnotation(Order.class));
    }

    private static  List sort(T[] array, Function filter, Function getOrder) {
        List> orderObjects = new ArrayList<>();
        List others = new ArrayList<>();
        for (T o : array) {
            if (!filter.apply(o)) continue;
            Order order = getOrder.apply(o);
            if (order == null) {
                others.add(o);
            } else {
                orderObjects.add(new OrderObject<>(order.value(), o));
            }
        }
        orderObjects.sort(Comparator.comparingInt(a -> a.order));
        List result = new ArrayList<>();
        for (OrderObject orderObject : orderObjects) {
            result.add(orderObject.object);
        }
        result.addAll(others);
        return result;
    }

    public static boolean isGetMethod(Method method) {
        return Modifier.isPublic(method.getModifiers())
               && !Modifier.isStatic(method.getModifiers())
               && method.getParameters().length == 0
               && method.getName().startsWith("get");
    }


    public static String methodToFieldName(String name) {
        char[] cs = new char[name.length() - 3];
        name.getChars(3, name.length(), cs, 0);
        cs[0] = Character.toLowerCase(cs[0]);
        return new String(cs);
    }

    public static boolean isBasicType(Class type) {
        if (type == null) return false;
        return type.isPrimitive() || type.getName().startsWith("java.");
    }

    @NonNull
    public static Class toClassType(Type type) {
        if (type instanceof Class) {
            return (Class) type;
        }
        if (type instanceof ParameterizedType) {
            Type result = ((ParameterizedType) type).getRawType();
            if (result instanceof Class) {
                return toClassType((Class) result);
            }
        }
        return Object.class;
    }

    @NonNull
    public static Class toClassType(@NonNull Class clazz) {
        if (clazz.isPrimitive()) {
            if (clazz == byte.class) {
                return Byte.class;
            } else if (clazz == char.class) {
                return Byte.class;
            } else if (clazz == short.class) {
                return Short.class;
            } else if (clazz == int.class) {
                return Integer.class;
            } else if (clazz == long.class) {
                return Long.class;
            } else if (clazz == float.class) {
                return Float.class;
            } else if (clazz == double.class) {
                return Double.class;
            } else if (clazz == boolean.class) {
                return Boolean.class;
            }
        }
        return clazz;
    }

    public static Type[] findTypes(Class clazz) {
        Map, Type[]> typesMap = new HashMap<>();
        Type[] types = findTypes(clazz, typesMap);
        if (types == null) {
            throw new IllegalArgumentException(String.format("%s entity class not found!", clazz));
        }
        for (Type type : types) {
            if (!(type instanceof Class)) {
                throw new IllegalArgumentException(String.format("%s %s class not found!", clazz, type));
            }
        }
        return types;
    }

    private static Type[] findTypes(Class clazz, Map, Type[]> typesMap) {
        Type[] types = null;
        for (Type type : clazz.getGenericInterfaces()) {
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                typesMap.put((Class) parameterizedType.getRawType(), parameterizedType.getActualTypeArguments());
                if (parameterizedType.getRawType() == SQLCrudRepository.class) {
                    types = parameterizedType.getActualTypeArguments();
                } else {
                    types = findTypes((Class) parameterizedType.getRawType(), typesMap);
                }
                findTypeVariableToClass(types, clazz, typesMap);
            } else if (type instanceof Class) {
                types = findTypes((Class) type, typesMap);
                findTypeVariableToClass(types, clazz, typesMap);
            }
        }
        return types;
    }

    private static void findTypeVariableToClass(Type[] types, Class clazz, Map, Type[]> typesMap) {
        for (int i = 0; i < types.length; i++) {
            Type type = types[i];
            if (type instanceof TypeVariable) {
                for (int j = 0; j < clazz.getTypeParameters().length; j++) {
                    if (type.getTypeName().equals(clazz.getTypeParameters()[j].getTypeName())) {
                        types[i] = typesMap.get(clazz)[j];
                    }
                }
            }
        }
    }


    @NonNull
    public static Class getValueClass(Type type, int index) {
        Type result = getValueType(type, index);
        if (result instanceof ParameterizedType) {
            return ClassUtil.toClassType(((ParameterizedType) result).getRawType());
        } else {
            return ClassUtil.toClassType(result);
        }
    }

    @NonNull
    public static Type getValueType(Type type, int index) {
        if (type instanceof ParameterizedType) {
            return ((ParameterizedType) type).getActualTypeArguments()[index];
        }
        return Object.class;
    }

    static class OrderObject {
        final int order;
        final T object;

        OrderObject(int order, T object) {
            this.order = order;
            this.object = object;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy