Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.higgs.core.reflect.ReflectionUtil Maven / Gradle / Ivy
package io.higgs.core.reflect;
import org.joda.time.DateTime;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
public final class ReflectionUtil {
public static int MAX_RECURSION_DEPTH = 10;
static final Map> FIELDS = new ConcurrentHashMap<>();
static final Map> METHODS = new ConcurrentHashMap<>();
static final Map> CLS = new ConcurrentHashMap<>();
private ReflectionUtil() {
}
public static String dotPath(Collection path) {
return dotPath((List) path.stream().filter(Objects::nonNull).map(Object::toString).collect(toList()));
}
public static String dotPath(List path) {
return path.stream().reduce("", (a, b) -> a.concat(".").concat(b)).substring(1);
}
public static Class> classOf(String className) {
return classOf(ReflectionUtil.class.getClassLoader(), className);
}
public static Class> classOf(ClassLoader loader, String className) {
return CLS.computeIfAbsent(className, name -> {
try {
return ClassUtils.forName(name, loader);
} catch (ClassNotFoundException e) {
throw new MissingClassException(e);
}
});
}
public static Field field(String path, Class> root) {
String[] parts = path.split("\\.");
Field field = null;
for (String name : parts) {
Map fields = FIELDS.get(root.getName());
if (fields == null) {
fields = getAllFields(root);
}
field = fields.get(name);
if (field == null) {
return null;
}
root = field.getType();
}
return field;
}
public static Map getAllFields(Class> type) {
return getAllFields(new HashMap<>(), type, 0);
}
public static Map getAllFields(Map fields, Class> type) {
return getAllFields(fields, type, 0);
}
public static Map getAllFields(Map fields, Class> type, int depth) {
String typeName = type.getName();
Map clsFields = FIELDS.get(typeName);
if (clsFields == null) {
FIELDS.put(typeName, fields);
} else {
fields.putAll(clsFields);
return fields;
}
//first get inherited fields
if (type.getSuperclass() != null && depth <= MAX_RECURSION_DEPTH) {
Class> scls = type.getSuperclass();
String clsName = scls.getName();
Map superFields = FIELDS.get(clsName);
if (superFields == null) {
superFields = new HashMap<>();
FIELDS.put(clsName, superFields);
getAllFields(superFields, scls, ++depth); //add fields to super fields only
}
fields.putAll(superFields); //add super fields to sub-class field map
}
//now add all "local" fields
for (Field field : type.getDeclaredFields()) {
//fact we're getting it probably means we'll need this so do it once at point of get instead of on each access/use
field.setAccessible(true);
fields.put(field.getName(), field);
}
return fields;
}
public static Map getAllMethods(Class> klass) {
Map methods = new HashMap<>();
getAllMethods(methods, klass);
return methods;
}
public static void getAllMethods(Map methods, Class> type) {
getAllMethods(methods, type, 0);
}
public static void getAllMethods(Map methods, Class> type, int depth) {
final Map current = METHODS.get(type.getName());
if (current == null) {
METHODS.put(type.getName(), methods);
} else {
methods.putAll(current);
return;
}
if (type.getSuperclass() != null && depth <= MAX_RECURSION_DEPTH) {
Class> scls = type.getSuperclass();
String clsName = scls.getName();
Map superMethods = METHODS.get(clsName);
if (superMethods == null) {
superMethods = new HashMap<>();
METHODS.put(clsName, superMethods);
getAllMethods(superMethods, scls, ++depth); //add methods to super fields only
}
methods.putAll(superMethods); //add super methods to sub-class method map
}
for (Method m : type.getDeclaredMethods()) {
methods.put(m.getName(), m);
}
}
/**
* @param klass the class
* @return true if klass represents a numeric type, including byte. Both boxed and unboxed.
*/
public static boolean isNumeric(Class> klass) {
return isIntLike(klass) ||
isFractionalLike(klass) ||
isShort(klass) ||
isByte(klass);
}
public static boolean isIntLike(Class> klass) {
return isInt(klass) || isLong(klass) || isBigInt(klass);
}
public static boolean isFractionalLike(Class> klass) {
return isDouble(klass) || isFloat(klass) || isBigDecimal(klass);
}
public static boolean isBigInt(Class> klass) {
return BigInteger.class.isAssignableFrom(klass);
}
public static boolean isBigDecimal(Class> klass) {
return BigDecimal.class.isAssignableFrom(klass);
}
public static boolean isByte(Class> klass) {
return Byte.class.isAssignableFrom(klass) ||
byte.class.isAssignableFrom(klass);
}
public static boolean isShort(Class> klass) {
return Short.class.isAssignableFrom(klass) ||
short.class.isAssignableFrom(klass);
}
public static boolean isFractional(Class> klass) {
return isDouble(klass) ||
isFloat(klass);
}
public static boolean isFloat(Class> klass) {
return Float.class.isAssignableFrom(klass) ||
float.class.isAssignableFrom(klass);
}
public static boolean isDouble(Class> klass) {
return Double.class.isAssignableFrom(klass) ||
double.class.isAssignableFrom(klass);
}
public static boolean isLong(Class> klass) {
return Long.class.isAssignableFrom(klass) ||
long.class.isAssignableFrom(klass);
}
public static boolean isInt(Class> klass) {
return Integer.class.isAssignableFrom(klass) ||
int.class.isAssignableFrom(klass);
}
public static boolean isString(Class> cls) {
return String.class.isAssignableFrom(cls);
}
public static boolean isStringLike(Class> cls) {
return isString(cls)
|| isUUID(cls)
|| Duration.class.isAssignableFrom(cls);
}
public static boolean isEnum(Class cls) {
if (cls.isEnum()) {
return true;
}
Class sCls = cls.getSuperclass();
return sCls != null && sCls.isEnum();
}
public static boolean isUUID(Class> cls) {
return UUID.class.isAssignableFrom(cls);
}
public static boolean isDate(Class> cls) {
return Date.class.isAssignableFrom(cls)
|| DateTime.class.isAssignableFrom(cls)
|| Temporal.class.isAssignableFrom(cls)
|| java.sql.Date.class.isAssignableFrom(cls);
}
public static boolean isCollection(Class> cls) {
return Collection.class.isAssignableFrom(cls);
}
public static boolean isList(Class> cls) {
return List.class.isAssignableFrom(cls);
}
public static boolean isSet(Class> cls) {
return Set.class.isAssignableFrom(cls);
}
public static boolean isQueue(Class> cls) {
return Queue.class.isAssignableFrom(cls);
}
public static boolean isMap(Class> cls) {
return Map.class.isAssignableFrom(cls);
}
public static boolean isBool(Class cls) {
return boolean.class.isAssignableFrom(cls) || Boolean.class.isAssignableFrom(cls);
}
public static boolean isScalar(Class cls) {
return isNumeric(cls)
|| isBool(cls)
|| isString(cls)
|| isDate(cls)
|| isEnum(cls);
}
@SuppressWarnings("unchecked")
public static T copy(T o, boolean deep) {
if (o == null) {
return null;
}
Class cls = (Class) o.getClass();
return copy(o, deep, null, cls);
}
public static T copy(T o, boolean deep, T to, Class cls) {
try {
T obj = to == null ? newInstance(cls) : to;
for (Field field : getAllFields(cls).values()) {
field.setAccessible(true);
boolean isStatic = Modifier.isStatic(field.getModifiers());
if (!isStatic) {
Object fieldVal = field.get(o);
if (fieldVal != null) {
if (!deep || isScalar(fieldVal.getClass())) {
field.set(obj, fieldVal);
} else {
if (fieldVal instanceof Set) {
fieldVal = new HashSet<>((Set) fieldVal);
} else if (fieldVal instanceof Queue) {
fieldVal = new LinkedList<>((Queue) fieldVal);
} else if (fieldVal instanceof Collection) {
fieldVal = new ArrayList<>((Collection) fieldVal);
} else if (fieldVal instanceof Map) {
fieldVal = new HashMap<>((Map) fieldVal);
} else {
fieldVal = copy(fieldVal, deep);
}
field.set(obj, fieldVal);
}
}
}
}
return obj;
} catch (Exception e) {
throw new IllegalStateException("Failed to create instance", e);
}
}
public static T newInstance(Class cls) {
Constructor[] ctors = cls.getDeclaredConstructors();
if (ctors.length == 0) {
throw new UnsupportedOperationException("Cannot create object if it is an interface, a primitive type, " +
"an array class, or void");
}
T obj = null;
for (Constructor ctor : ctors) {
if (ctor.getParameterCount() == 0) {
ctor.setAccessible(true);
try {
obj = (T) ctor.newInstance();
} catch (InstantiationException | IllegalAccessException | java.lang.reflect.InvocationTargetException e) {
throw new IllegalStateException(format("Unable to create instance of %s", cls.getName()), e);
}
break;
}
}
if (obj == null) {
throw new UnsupportedOperationException(cls.getName() + "%s cannot be created, no-arg constructor not found");
}
return obj;
}
public static Class> getFieldOrGetterType(String name, Class> cls) {
for (Field field : getAllFields(cls).values()) {
if (field.getName().contentEquals(name)) {
return field.getType();
}
}
String inName = format("get%s", name);
HashMap methods = new HashMap<>();
getAllMethods(methods, cls);
for (Method method : methods.values()) {
String methodName = method.getName();
if (methodName.toLowerCase().contentEquals(inName)) {
return method.getReturnType();
}
}
return null;
}
}