jfix.util.Reflections.java Source code

Java tutorial

Introduction

Here is the source code for jfix.util.Reflections.java

Source

/*
Copyright (C) 2016 maik.jablonski@jease.org
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jfix.util;

import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.ArrayUtils;

/**
 * Common utility-methods to handle reflection.
 */
public class Reflections {

    /**
     * Returns all fields of the referring class which might hold references to
     * given reference object. The reference object is used as "template object"
     * (and not as class) to make use of the
     * java.lang.reflect.Type.isInstance()-method.
     */
    public static Set<Field> getReferringFields(Class<?> referringClazz, Object reference) {
        Set<Field> referringFields = new HashSet<Field>();
        for (Field possibleReferringField : getFields(referringClazz)) {
            if (isAssignable(reference.getClass(), possibleReferringField)) {
                referringFields.add(possibleReferringField);
            }
        }
        return referringFields;
    }

    /**
     * Returns true if given possible referrer is referencing given reference
     * object in one or more of the given referring fields.
     */
    public static boolean isReferrer(Object possibleReferrer, Set<Field> referringFields, Object reference) {
        try {
            for (Field field : referringFields) {
                Object fieldValue = field.get(possibleReferrer);
                if (fieldValue != null && (fieldValue == reference
                        || (field.getType().isArray() && ArrayUtils.contains((Object[]) fieldValue, reference)))) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * Returns all interfaces and superclasses implemented by a given class.
     */
    public static Set<Class<?>> getSuperClassesAndInterfaces(Class<?> clazz) {
        Set<Class<?>> result = new HashSet<>();
        if (clazz != null) {
            result.add(clazz);
            for (Class<?> interfaceClass : clazz.getInterfaces()) {
                result.addAll(getSuperClassesAndInterfaces(interfaceClass));
            }
            result.addAll(getSuperClassesAndInterfaces(clazz.getSuperclass()));
        }
        return result;
    }

    /**
     * Returns all fields of a given class (including fields from superclasses).
     */
    public static Set<Field> getFields(Class<?> clazz) {
        Set<Field> result = new HashSet<>();
        for (Class<?> superClass : getSuperClassesAndInterfaces(clazz)) {
            for (Field field : superClass.getDeclaredFields()) {
                field.setAccessible(true);
                result.add(field);
            }
        }
        return result;
    }

    /**
     * Retrieves all objects of given class-type which are referred by all the
     * objects in given collection.
     */
    public static Set<Object> getReferredObjects(Collection<?> objects, Class<?> objectClass) {
        try {
            Set<Object> result = new HashSet<>();
            for (Object object : objects) {
                for (Field field : Reflections.getFields(object.getClass())) {
                    if (isAssignable(objectClass, field)) {
                        Object fieldValue = field.get(object);
                        if (fieldValue != null) {
                            if (field.getType().isArray()) {
                                for (Object arrayElement : (Object[]) fieldValue) {
                                    result.add(arrayElement);
                                }
                            } else {
                                result.add(fieldValue);
                            }
                        }
                    }
                }
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * Returns all instanceable (sub-)classes of given type in given package.
     */
    public static <E> E[] find(Class<E> classType, Package pckage) {
        File directory;
        try {
            String name = "/" + pckage.getName().replace('.', '/');
            directory = new File(classType.getResource(name).toURI());
        } catch (URISyntaxException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        List<E> result = new ArrayList<>();
        if (directory.exists()) {
            String[] files = directory.list();
            for (int i = 0; i < files.length; i++) {
                if (files[i].endsWith(".class")) {
                    String classname = files[i].substring(0, files[i].length() - 6);
                    try {
                        Object o = Class.forName(pckage.getName() + "." + classname).newInstance();
                        if (classType.isInstance(o)) {
                            result.add((E) o);
                        }
                    } catch (ClassNotFoundException cnfex) {
                        System.err.println(cnfex);
                    } catch (InstantiationException iex) {
                    } catch (IllegalAccessException iaex) {
                    }
                }
            }
        }
        result.sort(new Comparator<Object>() {
            public int compare(Object o1, Object o2) {
                return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName());
            }
        });
        return result.toArray((E[]) Array.newInstance(classType, result.size()));
    }

    /**
     * Returns all instanceable (sub-)classes of given type contained in the
     * package of given type.
     */
    public static <E> E[] find(Class<E> classType) {
        return find(classType, classType.getPackage());
    }

    /**
     * Returns a new instance for given clazz.
     */
    public static Object newInstance(Class<?> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * Returns a new instance for given fully qualified classname.
     */
    public static Object newInstance(String classname) {
        try {
            return Class.forName(classname).newInstance();
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * Returns true if given class can be assigned to given field (which might
     * be a simple field or array).
     */
    public static boolean isAssignable(Class<?> clazz, Field field) {
        return clazz.isAssignableFrom(field.getType())
                || (field.getType().isArray() && clazz.isAssignableFrom(field.getType().getComponentType()));
    }

    /**
     * Initializes all declared static string fields in given class with name of
     * fields.
     */
    public static void init(Class<?> clazz) {
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                field.set(null, field.getName());
            } catch (Exception e) {
            }
        }
    }
}