001package ca.uhn.fhir.util; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2017 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import java.lang.reflect.Field; 024import java.lang.reflect.Method; 025import java.lang.reflect.ParameterizedType; 026import java.lang.reflect.Type; 027import java.lang.reflect.TypeVariable; 028import java.lang.reflect.WildcardType; 029import java.util.LinkedHashSet; 030import java.util.List; 031 032import org.apache.commons.lang3.Validate; 033 034import ca.uhn.fhir.context.ConfigurationException; 035import javassist.Modifier; 036 037public class ReflectionUtil { 038 039 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReflectionUtil.class); 040 041 public static LinkedHashSet<Method> getDeclaredMethods(Class<?> theClazz) { 042 LinkedHashSet<Method> retVal = new LinkedHashSet<Method>(); 043 for (Method next : theClazz.getDeclaredMethods()) { 044 try { 045 Method method = theClazz.getMethod(next.getName(), next.getParameterTypes()); 046 retVal.add(method); 047 } catch (NoSuchMethodException e) { 048 retVal.add(next); 049 } catch (SecurityException e) { 050 retVal.add(next); 051 } 052 } 053 return retVal; 054 } 055 056 public static Class<?> getGenericCollectionTypeOfField(Field next) { 057 Class<?> type; 058 ParameterizedType collectionType = (ParameterizedType) next.getGenericType(); 059 Type firstArg = collectionType.getActualTypeArguments()[0]; 060 if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { 061 ParameterizedType pt = ((ParameterizedType) firstArg); 062 type = (Class<?>) pt.getRawType(); 063 } else { 064 type = (Class<?>) firstArg; 065 } 066 return type; 067 } 068 069 /** 070 * For a field of type List<Enumeration<Foo>>, returns Foo 071 */ 072 public static Class<?> getGenericCollectionTypeOfFieldWithSecondOrderForList(Field next) { 073 if (!List.class.isAssignableFrom(next.getType())) { 074 return getGenericCollectionTypeOfField(next); 075 } 076 077 Class<?> type; 078 ParameterizedType collectionType = (ParameterizedType) next.getGenericType(); 079 Type firstArg = collectionType.getActualTypeArguments()[0]; 080 if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { 081 ParameterizedType pt = ((ParameterizedType) firstArg); 082 Type pt2 = pt.getActualTypeArguments()[0]; 083 return (Class<?>) pt2; 084 } 085 type = (Class<?>) firstArg; 086 return type; 087 } 088 089 public static Class<?> getGenericCollectionTypeOfMethodParameter(Method theMethod, int theParamIndex) { 090 Class<?> type; 091 Type genericParameterType = theMethod.getGenericParameterTypes()[theParamIndex]; 092 if (Class.class.equals(genericParameterType)) { 093 return null; 094 } 095 ParameterizedType collectionType = (ParameterizedType) genericParameterType; 096 Type firstArg = collectionType.getActualTypeArguments()[0]; 097 if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { 098 ParameterizedType pt = ((ParameterizedType) firstArg); 099 type = (Class<?>) pt.getRawType(); 100 } else { 101 type = (Class<?>) firstArg; 102 } 103 return type; 104 } 105 106 @SuppressWarnings({ "rawtypes" }) 107 public static Class<?> getGenericCollectionTypeOfMethodReturnType(Method theMethod) { 108 Class<?> type; 109 Type genericReturnType = theMethod.getGenericReturnType(); 110 if (!(genericReturnType instanceof ParameterizedType)) { 111 return null; 112 } 113 ParameterizedType collectionType = (ParameterizedType) genericReturnType; 114 Type firstArg = collectionType.getActualTypeArguments()[0]; 115 if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { 116 ParameterizedType pt = ((ParameterizedType) firstArg); 117 type = (Class<?>) pt.getRawType(); 118 } else if (firstArg instanceof TypeVariable<?>) { 119 Type decl = ((TypeVariable) firstArg).getBounds()[0]; 120 return (Class<?>) decl; 121 } else if (firstArg instanceof WildcardType) { 122 Type decl = ((WildcardType) firstArg).getUpperBounds()[0]; 123 return (Class<?>) decl; 124 } else { 125 type = (Class<?>) firstArg; 126 } 127 return type; 128 } 129 130 /** 131 * Instantiate a class by no-arg constructor, throw {@link ConfigurationException} if we fail to do so 132 */ 133 @CoverageIgnore 134 public static <T> T newInstance(Class<T> theType) { 135 Validate.notNull(theType, "theType must not be null"); 136 try { 137 return theType.newInstance(); 138 } catch (Exception e) { 139 throw new ConfigurationException("Failed to instantiate " + theType.getName(), e); 140 } 141 } 142 143 @SuppressWarnings("unchecked") 144 public static <T> T newInstanceOrReturnNull(String theClassName, Class<T> theType) { 145 try { 146 Class<?> clazz = Class.forName(theClassName); 147 if (!theType.isAssignableFrom(clazz)) { 148 throw new ConfigurationException(theClassName + " is not assignable to " + theType); 149 } 150 return (T) clazz.newInstance(); 151 } catch (ConfigurationException e) { 152 throw e; 153 } catch (Exception e) { 154 ourLog.info("Failed to instantiate {}: {}", theClassName, e.toString()); 155 return null; 156 } 157 } 158 159 public static boolean isInstantiable(Class<?> theType) { 160 return !theType.isInterface() && !Modifier.isAbstract(theType.getModifiers()); 161 } 162 163}