ch.puzzle.itc.mobiliar.business.utils.ReflectionUtil.java Source code

Java tutorial

Introduction

Here is the source code for ch.puzzle.itc.mobiliar.business.utils.ReflectionUtil.java

Source

/*
 * AMW - Automated Middleware allows you to manage the configurations of
 * your Java EE applications on an unlimited number of different environments
 * with various versions, including the automated deployment of those apps.
 * Copyright (C) 2013-2016 by Puzzle ITC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package ch.puzzle.itc.mobiliar.business.utils;

import org.hibernate.proxy.HibernateProxy;

import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Collection;

public final class ReflectionUtil {
    // Ensure non-insatiability.
    private ReflectionUtil() {
    }

    public static <T> Class<T> getActualTypeArguments(Class<?> clazz, int indexOfArgument) {
        Class<T> resolvedType = getActualTypeArguments(clazz.getSuperclass().getGenericSuperclass(),
                indexOfArgument);
        if (resolvedType == null) {
            return getActualTypeArguments(clazz.getGenericSuperclass(), indexOfArgument);
        }
        return resolvedType;
    }

    @SuppressWarnings("unchecked")
    public static <T> Class<T> getActualTypeArguments(Type type, int indexOfArgument) {
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType) type;
            Type typeArgument = paramType.getActualTypeArguments()[indexOfArgument];
            if (typeArgument instanceof Class<?>) {
                return (Class<T>) typeArgument;
            }
        }
        return null;
    }

    public static Class<?> getGenericType(Field field) {
        return getGenericType(field, 0);
    }

    public static Class<?> getGenericType(Field field, int typeIndex) {
        ParameterizedType type = (ParameterizedType) field.getGenericType();
        return (Class<?>) type.getActualTypeArguments()[typeIndex];
    }

    public static <T> Object invokeGetter(Field field, Class<T> clazz, T targetObject)
            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException,
            IntrospectionException {
        PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), clazz);
        if (descriptor.getReadMethod() != null) {
            return descriptor.getReadMethod().invoke(targetObject);
        } else {
            throw new NoSuchMethodException("No getter for " + descriptor.getDisplayName());
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> void invokeSetter(Field field, Class<T> clazz, T targetObject, Object value)
            throws IntrospectionException, InvocationTargetException, IllegalAccessException,
            NoSuchMethodException {
        PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), clazz);
        Method setter = descriptor.getWriteMethod();
        if (setter != null) {
            Class<?> targetClass = setter.getParameterTypes()[0];

            // do we need to convert the number type?
            if (value != null && Number.class.isAssignableFrom(targetClass)) {
                Number numValue = (Number) value;
                numValue = convertNumberType(numValue, (Class<? extends Number>) targetClass);
                setter.invoke(targetObject, numValue);
            } else {
                setter.invoke(targetObject, value);
            }
        } else {
            throw new NoSuchMethodException("No setter for " + descriptor.getDisplayName());
        }
    }

    public static Constructor<?> getConstructor(Class<?> clazz, Object[] parameters) throws NoSuchMethodException {
        Class<?>[] parameterClasses = new Class<?>[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            parameterClasses[i] = parameters[i] == null ? null : parameters[i].getClass();
        }

        return clazz.getConstructor(parameterClasses);
    }

    public static Number convertNumberType(Number number, Class<? extends Number> targetType) {
        if (Byte.class.isAssignableFrom(targetType)) {
            return number.byteValue();
        } else if (Short.class.isAssignableFrom(targetType)) {
            return number.shortValue();
        } else if (Integer.class.isAssignableFrom(targetType)) {
            return number.intValue();
        } else if (Long.class.isAssignableFrom(targetType)) {
            return number.longValue();
        } else if (Float.class.isAssignableFrom(targetType)) {
            return number.floatValue();
        } else {
            return number.longValue();
        }
    }

    public static <T> T initializeEagerAnnotatedFields(T instance) throws NoSuchMethodException,
            InvocationTargetException, IllegalAccessException, IntrospectionException {

        Class<?> clazz = instance.getClass();

        for (Field field : clazz.getDeclaredFields()) {
            if (hasEagerAnnotation(field)) {
                field.setAccessible(true);
                Object object = field.get(instance);
                if (object != null) {
                    if (object instanceof Collection) {
                        Collection collection = (Collection) object;
                        for (Object elem : collection) {
                            initializeEagerAnnotatedFields(elem);
                        }
                    } else {
                        object = unproxyObject(object);
                        if (object != null) {
                            field.set(instance, object);
                            initializeEagerAnnotatedFields(object);
                        }
                    }
                }
            }
        }
        return instance;
    }

    static boolean hasEagerAnnotation(Field field)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        for (Annotation annotation : field.getAnnotations()) {
            if ((annotation instanceof OneToMany && isEagerFetch(annotation)) || annotation instanceof OneToOne) {
                return true;
            }
        }
        return false;
    }

    static boolean isEagerFetch(Annotation annotation)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method fetch = annotation.getClass().getMethod("fetch");
        FetchType fetchType = (FetchType) fetch.invoke(annotation);
        return FetchType.EAGER.equals(fetchType);
    }

    @SuppressWarnings("unchecked")
    static <T> T unproxyObject(T object) {
        if (object instanceof HibernateProxy) {
            HibernateProxy hibernateProxy = (HibernateProxy) object;
            return (T) hibernateProxy.getHibernateLazyInitializer().getImplementation();
        }
        return null;
    }
}