View Javadoc
1   package ca.uhn.fhir.util;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   * http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  import java.lang.reflect.*;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.concurrent.ConcurrentHashMap;
26  
27  import org.apache.commons.lang3.Validate;
28  
29  import ca.uhn.fhir.context.ConfigurationException;
30  import ca.uhn.fhir.context.support.IContextValidationSupport;
31  
32  public class ReflectionUtil {
33  
34  	private static final ConcurrentHashMap<String, Object> ourFhirServerVersions = new ConcurrentHashMap<String, Object>();
35  
36  	private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReflectionUtil.class);
37  
38  	public static LinkedHashSet<Method> getDeclaredMethods(Class<?> theClazz) {
39  		LinkedHashSet<Method> retVal = new LinkedHashSet<Method>();
40  		for (Method next : theClazz.getDeclaredMethods()) {
41  			try {
42  				Method method = theClazz.getMethod(next.getName(), next.getParameterTypes());
43  				retVal.add(method);
44  			} catch (NoSuchMethodException e) {
45  				retVal.add(next);
46  			} catch (SecurityException e) {
47  				retVal.add(next);
48  			}
49  		}
50  		return retVal;
51  	}
52  
53  	public static Class<?> getGenericCollectionTypeOfField(Field next) {
54  		Class<?> type;
55  		ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
56  		Type firstArg = collectionType.getActualTypeArguments()[0];
57  		if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
58  			ParameterizedType pt = ((ParameterizedType) firstArg);
59  			type = (Class<?>) pt.getRawType();
60  		} else {
61  			type = (Class<?>) firstArg;
62  		}
63  		return type;
64  	}
65  
66  	/**
67  	 * For a field of type List<Enumeration<Foo>>, returns Foo
68  	 */
69  	public static Class<?> getGenericCollectionTypeOfFieldWithSecondOrderForList(Field next) {
70  		if (!List.class.isAssignableFrom(next.getType())) {
71  			return getGenericCollectionTypeOfField(next);
72  		}
73  
74  		Class<?> type;
75  		ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
76  		Type firstArg = collectionType.getActualTypeArguments()[0];
77  		if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
78  			ParameterizedType pt = ((ParameterizedType) firstArg);
79  			Type pt2 = pt.getActualTypeArguments()[0];
80  			return (Class<?>) pt2;
81  		}
82  		type = (Class<?>) firstArg;
83  		return type;
84  	}
85  
86  	public static Class<?> getGenericCollectionTypeOfMethodParameter(Method theMethod, int theParamIndex) {
87  		Class<?> type;
88  		Type genericParameterType = theMethod.getGenericParameterTypes()[theParamIndex];
89  		if (Class.class.equals(genericParameterType) || Class.class.equals(genericParameterType.getClass())) {
90  			return null;
91  		}
92  		ParameterizedType collectionType = (ParameterizedType) genericParameterType;
93  		Type firstArg = collectionType.getActualTypeArguments()[0];
94  		if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
95  			ParameterizedType pt = ((ParameterizedType) firstArg);
96  			type = (Class<?>) pt.getRawType();
97  		} else {
98  			type = (Class<?>) firstArg;
99  		}
100 		return type;
101 	}
102 
103 	@SuppressWarnings({ "rawtypes" })
104 	public static Class<?> getGenericCollectionTypeOfMethodReturnType(Method theMethod) {
105 		Class<?> type;
106 		Type genericReturnType = theMethod.getGenericReturnType();
107 		if (!(genericReturnType instanceof ParameterizedType)) {
108 			return null;
109 		}
110 		ParameterizedType collectionType = (ParameterizedType) genericReturnType;
111 		Type firstArg = collectionType.getActualTypeArguments()[0];
112 		if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
113 			ParameterizedType pt = ((ParameterizedType) firstArg);
114 			type = (Class<?>) pt.getRawType();
115 		} else if (firstArg instanceof TypeVariable<?>) {
116 			Type decl = ((TypeVariable) firstArg).getBounds()[0];
117 			return (Class<?>) decl;
118 		} else if (firstArg instanceof WildcardType) {
119 			Type decl = ((WildcardType) firstArg).getUpperBounds()[0];
120 			return (Class<?>) decl;
121 		} else {
122 			type = (Class<?>) firstArg;
123 		}
124 		return type;
125 	}
126 
127 	public static boolean isInstantiable(Class<?> theType) {
128 		return !theType.isInterface() && !Modifier.isAbstract(theType.getModifiers());
129 	}
130 
131 	/**
132 	 * Instantiate a class by no-arg constructor, throw {@link ConfigurationException} if we fail to do so
133 	 */
134 	@CoverageIgnore
135 	public static <T> T newInstance(Class<T> theType) {
136 		Validate.notNull(theType, "theType must not be null");
137 		try {
138 			return theType.newInstance();
139 		} catch (Exception e) {
140 			throw new ConfigurationException("Failed to instantiate " + theType.getName(), e);
141 		}
142 	}
143 
144 	public static <T> T newInstance(Class<T> theType, Class<?> theArgumentType, Object theArgument) {
145 		Validate.notNull(theType, "theType must not be null");
146 		try {
147 			Constructor<T> constructor = theType.getConstructor(theArgumentType);
148 			return constructor.newInstance(theArgument);
149 		} catch (Exception e) {
150 			throw new ConfigurationException("Failed to instantiate " + theType.getName(), e);
151 		}
152 	}
153 
154 	public static Object newInstanceOfFhirServerType(String theType) {
155 		String errorMessage = "Unable to instantiate server framework. Please make sure that hapi-fhir-server library is on your classpath!";
156 		String wantedType = "ca.uhn.fhir.rest.api.server.IFhirVersionServer";
157 		Object fhirServerVersion = newInstanceOfType(theType, errorMessage, wantedType);
158 		return fhirServerVersion;
159 	}
160 
161 	@SuppressWarnings("unchecked")
162 	public static <EVS_IN, EVS_OUT, SDT, CST, CDCT, IST> ca.uhn.fhir.context.support.IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST> newInstanceOfFhirProfileValidationSupport(
163 			String theType) {
164 		String errorMessage = "Unable to instantiate validation support! Please make sure that hapi-fhir-validation and the appropriate structures JAR are on your classpath!";
165 		String wantedType = "ca.uhn.fhir.context.support.IContextValidationSupport";
166 		Object fhirServerVersion = newInstanceOfType(theType, errorMessage, wantedType);
167 		return (IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST>) fhirServerVersion;
168 	}
169 
170 	private static Object newInstanceOfType(String theType, String errorMessage, String wantedType) {
171 		Object fhirServerVersion = ourFhirServerVersions.get(theType);
172 		if (fhirServerVersion == null) {
173 			try {
174 				Class<?> type = Class.forName(theType);
175 				Class<?> serverType = Class.forName(wantedType);
176 				Validate.isTrue(serverType.isAssignableFrom(type));
177 				fhirServerVersion = type.newInstance();
178 			} catch (Exception e) {
179 				throw new ConfigurationException(errorMessage, e);
180 			}
181 
182 			ourFhirServerVersions.put(theType, fhirServerVersion);
183 		}
184 		return fhirServerVersion;
185 	}
186 
187 	@SuppressWarnings("unchecked")
188 	public static <T> T newInstanceOrReturnNull(String theClassName, Class<T> theType) {
189 		try {
190 			Class<?> clazz = Class.forName(theClassName);
191 			if (!theType.isAssignableFrom(clazz)) {
192 				throw new ConfigurationException(theClassName + " is not assignable to " + theType);
193 			}
194 			return (T) clazz.newInstance();
195 		} catch (ConfigurationException e) {
196 			throw e;
197 		} catch (Exception e) {
198 			ourLog.info("Failed to instantiate {}: {}", theClassName, e.toString());
199 			return null;
200 		}
201 	}
202 
203 }