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

com.cedarsoftware.util.ReflectionUtils Maven / Gradle / Ivy

package com.cedarsoftware.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author John DeRegnaucourt ([email protected])
 *         
* Copyright (c) Cedar Software LLC *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ public final class ReflectionUtils { private static final Map> _reflectedFields = new ConcurrentHashMap<>(); private ReflectionUtils() { super(); } /** * Determine if the passed in class (classToCheck) has the annotation (annoClass) on itself, * any of its super classes, any of it's interfaces, or any of it's super interfaces. * This is a exhaustive check throughout the complete inheritance hierarchy. * @return the Annotation if found, null otherwise. */ public static Annotation getClassAnnotation(final Class classToCheck, final Class annoClass) { final Set visited = new HashSet<>(); final LinkedList stack = new LinkedList<>(); stack.add(classToCheck); while (!stack.isEmpty()) { Class classToChk = stack.pop(); if (classToChk == null || visited.contains(classToChk)) { continue; } visited.add(classToChk); Annotation a = classToChk.getAnnotation(annoClass); if (a != null) { return a; } stack.push(classToChk.getSuperclass()); addInterfaces(classToChk, stack); } return null; } private static void addInterfaces(final Class classToCheck, final LinkedList stack) { for (Class interFace : classToCheck.getInterfaces()) { stack.push(interFace); } } public static Annotation getMethodAnnotation(final Method method, final Class annoClass) { final Set visited = new HashSet<>(); final LinkedList stack = new LinkedList<>(); stack.add(method.getDeclaringClass()); while (!stack.isEmpty()) { Class classToChk = stack.pop(); if (classToChk == null || visited.contains(classToChk)) { continue; } visited.add(classToChk); Method m = getMethod(classToChk, method.getName(), method.getParameterTypes()); if (m == null) { continue; } Annotation a = m.getAnnotation(annoClass); if (a != null) { return a; } stack.push(classToChk.getSuperclass()); addInterfaces(method.getDeclaringClass(), stack); } return null; } public static Method getMethod(Class c, String method, Class...types) { try { return c.getMethod(method, types); } catch (Exception nse) { return null; } } /** * Get all non static, non transient, fields of the passed in class, including * private fields. Note, the special this$ field is also not returned. The result * is cached in a static ConcurrentHashMap to benefit execution performance. * @param c Class instance * @return Collection of only the fields in the passed in class * that would need further processing (reference fields). This * makes field traversal on a class faster as it does not need to * continually process known fields like primitives. */ public static Collection getDeepDeclaredFields(Class c) { if (_reflectedFields.containsKey(c)) { return _reflectedFields.get(c); } Collection fields = new ArrayList<>(); Class curr = c; while (curr != null) { getDeclaredFields(curr, fields); curr = curr.getSuperclass(); } _reflectedFields.put(c, fields); return fields; } /** * Get all non static, non transient, fields of the passed in class, including * private fields. Note, the special this$ field is also not returned. The * resulting fields are stored in a Collection. * @param c Class instance * that would need further processing (reference fields). This * makes field traversal on a class faster as it does not need to * continually process known fields like primitives. */ public static void getDeclaredFields(Class c, Collection fields) { try { Field[] local = c.getDeclaredFields(); for (Field field : local) { if (!field.isAccessible()) { try { field.setAccessible(true); } catch (Exception ignored) { } } int modifiers = field.getModifiers(); if (!Modifier.isStatic(modifiers) && !field.getName().startsWith("this$") && !Modifier.isTransient(modifiers)) { // speed up: do not count static fields, do not go back up to enclosing object in nested case, do not consider transients fields.add(field); } } } catch (Throwable ignored) { ExceptionUtilities.safelyIgnoreException(ignored); } } /** * Return all Fields from a class (including inherited), mapped by * String field name to java.lang.reflect.Field. * @param c Class whose fields are being fetched. * @return Map of all fields on the Class, keyed by String field * name to java.lang.reflect.Field. */ public static Map getDeepDeclaredFieldMap(Class c) { Map fieldMap = new HashMap<>(); Collection fields = getDeepDeclaredFields(c); for (Field field : fields) { String fieldName = field.getName(); if (fieldMap.containsKey(fieldName)) { // Can happen when parent and child class both have private field with same name fieldMap.put(field.getDeclaringClass().getName() + '.' + fieldName, field); } else { fieldMap.put(fieldName, field); } } return fieldMap; } /** * Return the name of the class on the object, or "null" if the object is null. * @param o Object to get the class name. * @return String name of the class or "null" */ public static String getClassName(Object o) { return o == null ? "null" : o.getClass().getName(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy