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

de.gsi.serializer.utils.ClassUtils Maven / Gradle / Ivy

package de.gsi.serializer.utils;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.nio.CharBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.gsi.serializer.spi.ClassFieldDescription;

public final class ClassUtils { //NOPMD nomen est omen
    private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtils.class);
    // some helper declarations
    private static final Map, Class> primitiveWrapperMap = new HashMap<>();
    private static final Map, Class> wrapperPrimitiveMap = new HashMap<>();
    private static final Map, Class> primitiveArrayBoxedMap = new HashMap<>();
    private static final Map, Class> boxedArrayPrimitiveMap = new HashMap<>();
    private static final Map CLASS_FIELD_DESCRIPTION_MAP = new ConcurrentHashMap<>();
    private static final Map> CLASS_STRING_MAP = new ConcurrentHashMap<>();
    private static final Map, Map> CLASS_METHOD_MAP = new ConcurrentHashMap<>();
    private static int indentationNumberOfSpace = 4;
    private static int maxRecursionDepth = 10;

    static {
        // primitive types
        add(wrapperPrimitiveMap, primitiveWrapperMap, Boolean.class, boolean.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Byte.class, byte.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Character.class, char.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Short.class, short.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Integer.class, int.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Long.class, long.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Float.class, float.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Double.class, double.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, Void.class, void.class);
        add(wrapperPrimitiveMap, primitiveWrapperMap, String.class, String.class);

        // primitive arrays
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, boolean[].class, Boolean[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, byte[].class, Byte[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, char[].class, Character[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, short[].class, Short[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, int[].class, Integer[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, long[].class, Long[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, float[].class, Float[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, double[].class, Double[].class);
        add(primitiveArrayBoxedMap, boxedArrayPrimitiveMap, String[].class, String[].class);

        // boxed arrays
    }
    private ClassUtils() {
        // utility class
    }

    public static void checkArgument(boolean condition) {
        if (!condition) {
            throw new IllegalArgumentException();
        }
    }

    public static Class getClassByName(final String name) {
        return CLASS_STRING_MAP.computeIfAbsent(name, key -> {
            try {
                return Class.forName(key);
            } catch (ClassNotFoundException | SecurityException e) {
                LOGGER.atError().setCause(e).addArgument(name).log("exception while getting class {}");
                return null;
            }
        });
    }

    public static Class getClassByNameNonVerboseError(final String name) {
        return CLASS_STRING_MAP.computeIfAbsent(name, key -> {
            try {
                return Class.forName(key);
            } catch (ClassNotFoundException | SecurityException e) {
                return Object.class;
            }
        });
    }

    public static Map getClassDescriptions() {
        return CLASS_FIELD_DESCRIPTION_MAP;
    }

    public static ClassFieldDescription getFieldDescription(final Class clazz, final Class... classArguments) {
        if (clazz == null) {
            throw new IllegalArgumentException("object must not be null");
        }
        return CLASS_FIELD_DESCRIPTION_MAP.computeIfAbsent(computeHashCode(clazz, classArguments),
                key -> new ClassFieldDescription(clazz, false));
    }

    public static int getIndentationNumberOfSpace() {
        return indentationNumberOfSpace;
    }

    public static Collection getKnownClasses() {
        return CLASS_FIELD_DESCRIPTION_MAP.values();
    }

    public static Map, Map> getKnownMethods() {
        return CLASS_METHOD_MAP;
    }

    public static int getMaxRecursionDepth() {
        return maxRecursionDepth;
    }

    public static Method getMethod(final Class clazz, final String methodName) {
        return CLASS_METHOD_MAP.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).computeIfAbsent(methodName, name -> {
            try {
                return clazz.getMethod(methodName);
            } catch (NoSuchMethodException | SecurityException e) {
                return null;
            }
        });
    }

    public static Class getRawType(Type type) {
        if (type instanceof Class) {
            // type is a normal class.
            return (Class) type;

        } else if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;

            // unsure why getRawType() returns Type instead of Class.
            // possibly related to pathological case involving nested classes....
            Type rawType = parameterizedType.getRawType();
            checkArgument(rawType instanceof Class);
            return (Class) rawType;

        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            return Array.newInstance(getRawType(componentType), 0).getClass();

        } else if (type instanceof TypeVariable) {
            // we could use the variable's bounds, but that won't work if there are multiple.
            // having a raw type that's more general than necessary is okay
            return Object.class;

        } else if (type instanceof WildcardType) {
            return getRawType(((WildcardType) type).getUpperBounds()[0]);

        } else {
            String className = type == null ? "null" : type.getClass().getName();
            throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
                                               + "GenericArrayType, but <" + type + "> is of type " + className);
        }
    }

    public static Type[] getSecondaryType(final Type type) {
        if (type instanceof ParameterizedType) {
            return ((ParameterizedType) type).getActualTypeArguments();
        }
        return new Type[0];
    }

    public static boolean isBoxedArray(final Class type) {
        return boxedArrayPrimitiveMap.containsKey(type);
    }

    public static boolean isPrimitiveArray(final Class type) {
        return primitiveArrayBoxedMap.containsKey(type);
    }

    public static boolean isPrimitiveOrString(final Class type) {
        if (type == null) {
            return false;
        }
        return type.isPrimitive() || String.class.isAssignableFrom(type);
    }

    public static boolean isPrimitiveOrWrapper(final Class type) {
        if (type == null) {
            return false;
        }
        return type.isPrimitive() || isPrimitiveWrapper(type);
    }

    public static boolean isPrimitiveWrapper(final Class type) {
        return wrapperPrimitiveMap.containsKey(type);
    }

    public static boolean isPrimitiveWrapperOrString(final Class type) {
        if (type == null) {
            return false;
        }
        return wrapperPrimitiveMap.containsKey(type) || String.class.isAssignableFrom(type);
    }

    public static Class primitiveToWrapper(final Class cls) {
        Class convertedClass = cls;
        if (cls != null && cls.isPrimitive()) {
            convertedClass = primitiveWrapperMap.get(cls);
        }
        return convertedClass;
    }

    public static void setIndentationNumberOfSpace(final int indentationNumberOfSpace) {
        ClassUtils.indentationNumberOfSpace = indentationNumberOfSpace;
    }

    public static void setMaxRecursionDepth(final int maxRecursionDepth) {
        ClassUtils.maxRecursionDepth = maxRecursionDepth;
    }

    public static String spaces(final int spaces) {
        return CharBuffer.allocate(spaces).toString().replace('\0', ' ');
    }

    public static String translateClassName(final String name) {
        if (name.startsWith("[Z")) {
            return boolean[].class.getName();
        } else if (name.startsWith("[B")) {
            return byte[].class.getName();
        } else if (name.startsWith("[S")) {
            return short[].class.getName();
        } else if (name.startsWith("[I")) {
            return int[].class.getName();
        } else if (name.startsWith("[J")) {
            return long[].class.getName();
        } else if (name.startsWith("[F")) {
            return float[].class.getName();
        } else if (name.startsWith("[D")) {
            return double[].class.getName();
        } else if (name.startsWith("[L")) {
            return name.substring(2, name.length() - 1) + "[]";
        }

        return name;
    }

    private static void add(Map, Class> map1, Map, Class> map2, Class obj1, Class obj2) {
        map1.put(obj1, obj2);
        map2.put(obj2, obj1);
    }

    private static int computeHashCode(final Class classPrototype, final Class... classArguments) {
        final int prime = 31;
        int result = 1;
        result = (prime * result) + ((classPrototype == null) ? 0 : classPrototype.getName().hashCode());
        if ((classArguments == null) || (classArguments.length <= 0)) {
            return result;
        }

        for (final Class clazz : classArguments) {
            result = (prime * result) + clazz.hashCode();
        }

        return result;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy