001/* 002 * Syncany, www.syncany.org 003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation, either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package org.syncany.util; 019 020import java.lang.annotation.Annotation; 021import java.lang.reflect.Constructor; 022import java.lang.reflect.Field; 023import java.lang.reflect.Method; 024import java.lang.reflect.Type; 025import java.util.ArrayList; 026import java.util.List; 027 028/** 029 * Utility class to find classes, methods and fields with certain properties - 030 * typically having an annotation or a certain erasure. 031 * 032 * @author Christian Roth (christian.roth@port17.de) 033 */ 034public abstract class ReflectionUtil { 035 public static Field[] getAllFieldsWithAnnotation(Class<?> clazz, Class<? extends Annotation> annotation) { 036 List<Field> matchedAnnotations = new ArrayList<>(); 037 038 while (clazz != null) { 039 for (Field f : clazz.getDeclaredFields()) { 040 if (f.isAnnotationPresent(annotation)) { 041 matchedAnnotations.add(f); 042 } 043 } 044 045 clazz = clazz.getSuperclass(); 046 } 047 048 return matchedAnnotations.toArray(new Field[matchedAnnotations.size()]); 049 } 050 051 public static Method[] getAllMethodsWithAnnotation(Class<?> clazz, Class<? extends Annotation> annotation) { 052 List<Method> matchedAnnotations = new ArrayList<>(); 053 054 while (clazz != null) { 055 for (Method m : clazz.getDeclaredMethods()) { 056 if (m.isAnnotationPresent(annotation)) { 057 matchedAnnotations.add(m); 058 } 059 } 060 061 clazz = clazz.getSuperclass(); 062 } 063 064 return matchedAnnotations.toArray(new Method[matchedAnnotations.size()]); 065 } 066 067 public static Constructor<?> getMatchingConstructorForClass(Class<?> clazz, Class<?>... parameterTypes) { 068 // Try fast matching 069 try { 070 return clazz.getConstructor(parameterTypes); 071 } 072 catch (NoSuchMethodException e) { 073 // ignore 074 } 075 076 // If fast matching fails, check for assignable constructor 077 findConstructor: for (Constructor<?> constructor : clazz.getConstructors()) { 078 if (constructor.getParameterTypes().length == parameterTypes.length) { 079 int i = 0; 080 081 for (Class<?> t : constructor.getParameterTypes()) { 082 // TODO [low] Handle type erasure (see test) 083 if (!parameterTypes[i].isAssignableFrom(t)) { 084 continue findConstructor; 085 } 086 087 ++i; 088 } 089 090 return constructor; 091 } 092 } 093 094 return null; 095 } 096 097 /** 098 * Returns the {@link Class} from a {@link Type}, or 099 * returns null if the class is not found, or the type 100 * is not a class. 101 */ 102 public static Class<?> getClassFromType(Type type) { 103 // Java 7 does not support getTypeName() :( 104 String fullName = type.toString(); 105 106 try { 107 if (fullName.startsWith("class ")) { 108 return Class.forName(fullName.substring("class ".length())); 109 } 110 } 111 catch (ClassNotFoundException e) { 112 return null; 113 } 114 115 return null; 116 } 117 118 public static boolean isAnnotationPresentInHierarchy(Class<?> clazz, Class<? extends Annotation> annotation) { 119 while (clazz != null) { 120 if (clazz.isAnnotationPresent(annotation)) { 121 return true; 122 } 123 124 clazz = clazz.getSuperclass(); 125 } 126 127 return false; 128 } 129 130 public static <T extends Annotation> T getAnnotationInHierarchy(Class<?> clazz, Class<T> annotation) { 131 while (clazz != null) { 132 if (clazz.isAnnotationPresent(annotation)) { 133 return clazz.getAnnotation(annotation); 134 } 135 136 clazz = clazz.getSuperclass(); 137 } 138 139 return null; 140 } 141 142 /** 143 * Returns whether or not the value is a valid value 144 * for the enum given. 145 * 146 * @param checkEnumValue Value to check 147 * @param enumClass Enum class to check the given value against 148 * @return True if given value is valid, false otherwise 149 */ 150 @SuppressWarnings({ "unchecked", "rawtypes" }) 151 public static boolean isValidEnum(String checkEnumValue, Class<?> enumClass) { 152 if (!enumClass.isEnum()) { 153 return false; 154 } 155 156 try { 157 Enum.valueOf((Class<? extends Enum>) enumClass, checkEnumValue); 158 return true; 159 } 160 catch (IllegalArgumentException e) { 161 return false; 162 } 163 } 164}