package ca.uhn.fhir.util;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* 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.
* #L%
*/
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.LinkedHashSet;
import java.util.List;
import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.context.ConfigurationException;
import javassist.Modifier;
public class ReflectionUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReflectionUtil.class);
public static LinkedHashSet<Method> getDeclaredMethods(Class<?> theClazz) {
LinkedHashSet<Method> retVal = new LinkedHashSet<Method>();
for (Method next : theClazz.getDeclaredMethods()) {
try {
Method method = theClazz.getMethod(next.getName(), next.getParameterTypes());
retVal.add(method);
} catch (NoSuchMethodException e) {
retVal.add(next);
} catch (SecurityException e) {
retVal.add(next);
}
}
return retVal;
}
public static Class<?> getGenericCollectionTypeOfField(Field next) {
Class<?> type;
ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
Type firstArg = collectionType.getActualTypeArguments()[0];
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
ParameterizedType pt = ((ParameterizedType) firstArg);
type = (Class<?>) pt.getRawType();
} else {
type = (Class<?>) firstArg;
}
return type;
}
/**
* For a field of type List<Enumeration<Foo>>, returns Foo
*/
public static Class<?> getGenericCollectionTypeOfFieldWithSecondOrderForList(Field next) {
if (!List.class.isAssignableFrom(next.getType())) {
return getGenericCollectionTypeOfField(next);
}
Class<?> type;
ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
Type firstArg = collectionType.getActualTypeArguments()[0];
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
ParameterizedType pt = ((ParameterizedType) firstArg);
Type pt2 = pt.getActualTypeArguments()[0];
return (Class<?>) pt2;
}
type = (Class<?>) firstArg;
return type;
}
public static Class<?> getGenericCollectionTypeOfMethodParameter(Method theMethod, int theParamIndex) {
Class<?> type;
Type genericParameterType = theMethod.getGenericParameterTypes()[theParamIndex];
if (Class.class.equals(genericParameterType)) {
return null;
}
ParameterizedType collectionType = (ParameterizedType) genericParameterType;
Type firstArg = collectionType.getActualTypeArguments()[0];
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
ParameterizedType pt = ((ParameterizedType) firstArg);
type = (Class<?>) pt.getRawType();
} else {
type = (Class<?>) firstArg;
}
return type;
}
@SuppressWarnings({ "rawtypes" })
public static Class<?> getGenericCollectionTypeOfMethodReturnType(Method theMethod) {
Class<?> type;
Type genericReturnType = theMethod.getGenericReturnType();
if (!(genericReturnType instanceof ParameterizedType)) {
return null;
}
ParameterizedType collectionType = (ParameterizedType) genericReturnType;
Type firstArg = collectionType.getActualTypeArguments()[0];
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
ParameterizedType pt = ((ParameterizedType) firstArg);
type = (Class<?>) pt.getRawType();
} else if (firstArg instanceof TypeVariable<?>) {
Type decl = ((TypeVariable) firstArg).getBounds()[0];
return (Class<?>) decl;
} else if (firstArg instanceof WildcardType) {
Type decl = ((WildcardType) firstArg).getUpperBounds()[0];
return (Class<?>) decl;
} else {
type = (Class<?>) firstArg;
}
return type;
}
/**
* Instantiate a class by no-arg constructor, throw {@link ConfigurationException} if we fail to do so
*/
@CoverageIgnore
public static <T> T newInstance(Class<T> theType) {
Validate.notNull(theType, "theType must not be null");
try {
return theType.newInstance();
} catch (Exception e) {
throw new ConfigurationException("Failed to instantiate " + theType.getName(), e);
}
}
@SuppressWarnings("unchecked")
public static <T> T newInstanceOrReturnNull(String theClassName, Class<T> theType) {
try {
Class<?> clazz = Class.forName(theClassName);
if (!theType.isAssignableFrom(clazz)) {
throw new ConfigurationException(theClassName + " is not assignable to " + theType);
}
return (T) clazz.newInstance();
} catch (ConfigurationException e) {
throw e;
} catch (Exception e) {
ourLog.info("Failed to instantiate {}: {}", theClassName, e.toString());
return null;
}
}
public static boolean isInstantiable(Class<?> theType) {
return !theType.isInterface() && !Modifier.isAbstract(theType.getModifiers());
}
}