package io.robe.common.utils.reflection; import com.google.common.collect.ImmutableSet; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; /** * A class which helps field operations by reflectasm library. * It also has cache support for class fields. */ public class Fields { private static final ConcurrentHashMap<Class<?>, ImmutableSet<Field>> cache = new ConcurrentHashMap<>(); private Fields() { } private static final ImmutableSet<Field> get(Class<?> clazz) { if (!cache.containsKey(clazz)) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); } cache.put(clazz, ImmutableSet.copyOf(fields)); return cache.get(clazz); } return cache.get(clazz); } public static final <T> void copy(T src, T dest) { ImmutableSet<Field> fa = get(src.getClass()); for (Field field : fa) { try { field.set(dest, field.get(src)); } catch (IllegalAccessException e) { e.printStackTrace(); } } } public static final <T> void mergeRight(T src, T dest) { ImmutableSet<Field> fa = get(src.getClass()); for (Field field : fa) { try { Object value = field.get(src); if (value == null) continue; field.set(dest, value); } catch (IllegalAccessException e) { e.printStackTrace(); } } } public static Map<String, Field> getAllFieldsAsMap(Class<?> type) { Map<String, Field> fieldMap = new LinkedHashMap<>(); getAllFieldsAsMap(fieldMap, type, null); return fieldMap; } public static Map<String, Field> getAllFieldsAsMap(Class<?> type, Predicate<Field> predicate) { Map<String, Field> fieldMap = new LinkedHashMap<>(); getAllFieldsAsMap(fieldMap, type, predicate); return fieldMap; } public static void getAllFieldsAsMap(Map<String, Field> fieldMap, Class<?> type, Predicate<Field> predicate) { if(predicate != null) { for(Field field: type.getDeclaredFields()) { if(!predicate.test(field)) continue; field.setAccessible(true); fieldMap.putIfAbsent(field.getName(), field); } } else { for(Field field: type.getDeclaredFields()) { field.setAccessible(true); fieldMap.putIfAbsent(field.getName(), field); } } if(type.getSuperclass() != null) { getAllFieldsAsMap(fieldMap, type.getSuperclass(), predicate); } } public static Map<String, Field> findFieldsInMapByPredicate(Map<String, Field> fieldMap, Predicate<Field> predicate) { Map<String, Field> foundFieldMap = new LinkedHashMap<>(); for(Map.Entry<String, Field> entry: fieldMap.entrySet()) { if(predicate.test(entry.getValue())) { foundFieldMap.put(entry.getKey(), entry.getValue()); } } return foundFieldMap; } public static Object castValue(Field field, String value) { return castValue(field.getType(), value); } public static Object castValue(Class<?> type, String value) { if(value == null || "null".equals(value) || (!String.class.equals(type) && "".equals(value))) { return null; } switch (type.getName()) { case "java.math.BigDecimal": return new BigDecimal(value); case "java.lang.Boolean": case "boolean": return Boolean.parseBoolean(value); case "java.lang.Double": case "double": return Double.parseDouble(value); case "java.lang.Integer": case "int": return Integer.parseInt(value); case "java.lang.Long": case "long": return Long.parseLong(value); case "java.lang.String": return value; case "java.util.Date": return new Date(Long.parseLong(value)); } if ((type instanceof Class && (type).isEnum())) { return Enum.valueOf((Class<? extends Enum>) type, value); } return null; } public static Class<?> getTypeOfList(Field field) { ParameterizedType stringListType = (ParameterizedType) field.getGenericType(); Class<?> elementClass = (Class<?>) stringListType.getActualTypeArguments()[0]; return elementClass; } }