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

sirius.kernel.commons.Reflection Maven / Gradle / Ivy

/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.kernel.commons;

import sirius.kernel.health.Exceptions;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * Helper class for generic reflection tasks.
 */
public class Reflection {

    private Reflection() {
    }

    /**
     * Converts the first character of a given string to upper case.
     * 

* Comes in handy when translating properties to getter/setter names. * * @param string the name of the property to convert * @return the given string, with an upper-case letter at the start or null if the input was null */ @Nullable public static String toFirstUpper(@Nullable String string) { if (Strings.isEmpty(string)) { return string; } if (string.length() == 1) { return string.toUpperCase(); } return string.substring(0, 1).toUpperCase() + string.substring(1); } /** * Returns the getter method according to the java beans specification for a * given property. * * @param clazz the class in which the method should be searched * @param property the name of the property for which the getter is requested * @return the Method which is used to get the value * @throws IllegalArgumentException if the getter cannot be obtained */ @Nonnull @SuppressWarnings("squid:S1141") @Explain("A nested catch block seems to be the most readable solution here") public static Method getter(@Nonnull Class clazz, @Nonnull String property) { try { try { return clazz.getMethod("get" + toFirstUpper(property)); } catch (NoSuchMethodException e) { Exceptions.ignore(e); return getterAsIs(clazz, property); } } catch (Exception e) { throw new IllegalArgumentException(Strings.apply("get-Method for Field %s not found: %s", property, e.getMessage()), e); } } private static Method getterAsIs(@Nonnull Class clazz, @Nonnull String property) throws NoSuchMethodException { try { return clazz.getMethod("is" + toFirstUpper(property)); } catch (NoSuchMethodException ex) { Exceptions.ignore(ex); return clazz.getMethod(property); } } /** * Returns the setter method according to the java beans specification for a * given property. * * @param clazz the class in which the method should be searched * @param property the name of the property for which the setter is requested * @param fieldType determines the type of the field (which is accepted as parameter of the setter) * @return the Method which is used to get the value * @throws IllegalArgumentException if the setter cannot be obtained */ public static Method setter(Class clazz, String property, Class fieldType) { try { return clazz.getMethod("set" + toFirstUpper(property), fieldType); } catch (Exception e) { throw new IllegalArgumentException(Strings.apply("set-Method for Field %s not found: %s", property, e.getMessage()), e); } } /** * Evaluates the given access path (dot separated getters) and returns the result. *

* An access path can look like foo.bar.baz and represents: {@code root.getFoo().getBar().getBaz()}. * If any of the getters returns null, null will also be the result of the evaluation. * * @param path the access path to evaluate * @param root the root object on which the first getter is called * @return the result of the last getter */ public static Object evalAccessPath(String path, Object root) { if (root == null) { return null; } if (Strings.isEmpty(path)) { return root; } Tuple pair = Strings.split(path, "."); Method m = getter(root.getClass(), pair.getFirst()); try { return evalAccessPath(pair.getSecond(), m.invoke(root)); } catch (IllegalAccessException e) { throw new IllegalArgumentException(Strings.apply("Cannot invoke %s on %s (%s)", m.getName(), root, m.getDeclaringClass().getName()), e); } catch (InvocationTargetException e) { throw new IllegalArgumentException(Strings.apply("Error invoking %s on %s (%s): %s (%s)", m.getName(), root, m.getDeclaringClass().getName(), e.getCause().getMessage(), e.getCause().getClass().getName()), e); } } /** * Calls the given handler for each superclass of the given one. *

* Calls the handler for the given class and each of its superclasses until {@code Object} is reached. * * @param clazz the class to start from * @param handler the handler to call for each superclass * @throws Exception thrown if the handler throws an exception */ public static void walkHierarchy(@Nonnull Class clazz, @Nonnull Callback> handler) throws Exception { Class current = clazz; while (current != null && !Object.class.equals(current)) { handler.invoke(current); current = current.getSuperclass(); } } /** * Returns all fields defined by this class or one of its superclasses. This includes public, protected and * private fields. * * @param clazz the class to collect the fields for * @return a list of all defined fields of the given class and its superclasses (excluding {@code Object}) */ @Nonnull public static List getAllFields(@Nonnull Class clazz) { DataCollector collector = new DataCollector<>(); try { walkHierarchy(clazz, value -> collector.addAll(Arrays.asList(value.getDeclaredFields()))); } catch (Exception e) { Exceptions.handle(e); } return collector.getData(); } /** * Determines if the given superclass is the same or a superclass or superinterface of the given * classInQuestion. *

* This is essentially a shortcut for {@code superclass.isAssignableFrom(classInQuestion)} which seems * to be more natural. * * @param superclass the designated superclass or superinterface * @param classInQuestion the class in question * @return true if the class in question is the same, a subclass or subinterface of the given * superclass. */ public static boolean isSubclassOf(@Nonnull Class superclass, @Nonnull Class classInQuestion) { return superclass.isAssignableFrom(classInQuestion); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy