001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import java.lang.reflect.AccessibleObject;
005import java.security.AccessController;
006import java.security.PrivilegedAction;
007import java.util.Collection;
008import java.util.function.Function;
009
010import org.openstreetmap.josm.plugins.PluginHandler;
011
012/**
013 * Reflection utilities.
014 * @since 14977
015 */
016public final class ReflectionUtils {
017
018    private ReflectionUtils() {
019        // Hide default constructor for utils classes
020    }
021
022    /**
023     * Sets {@code AccessibleObject}(s) accessible.
024     * @param objects objects
025     * @see AccessibleObject#setAccessible
026     */
027    public static void setObjectsAccessible(final AccessibleObject... objects) {
028        if (objects != null && objects.length > 0) {
029            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
030                for (AccessibleObject o : objects) {
031                    if (o != null) {
032                        o.setAccessible(true);
033                    }
034                }
035                return null;
036            });
037        }
038    }
039
040    /**
041     * To use from a method to know which class called it.
042     * @param exclusions classes to exclude from the search. Can be null
043     * @return the first calling class not present in {@code exclusions}
044     */
045    public static Class<?> findCallerClass(Collection<Class<?>> exclusions) {
046        return findCaller(x -> {
047            try {
048                return Class.forName(x.getClassName());
049            } catch (ClassNotFoundException e) {
050                for (ClassLoader cl : PluginHandler.getPluginClassLoaders()) {
051                    try {
052                        return Class.forName(x.getClassName(), true, cl);
053                    } catch (ClassNotFoundException ex) {
054                        Logging.trace(ex);
055                    }
056                }
057                Logging.error(e);
058                return null;
059            }
060        }, exclusions);
061    }
062
063    private static <T extends Object> T findCaller(Function<StackTraceElement, T> getter, Collection<T> exclusions) {
064        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
065        for (int i = 3; i < stack.length; i++) {
066            T t = getter.apply(stack[i]);
067            if (exclusions == null || !exclusions.contains(t)) {
068                return t;
069            }
070        }
071        return null;
072    }
073}