Jave object merger

import com.raybow.model.annotation.Mergeable; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; import java.lang.reflect.Field; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** * Merger. */ public final class Merger { private static final ConcurrentHashMap<Class, Field[]> FIELD_CACHE = new ConcurrentHashMap<>(); private Merger() { // private ctor } public static <T> T merge(T source, T target) { try { if (source == null) return target; if (target == null) return source; // process collection merge if (Collection.class.isAssignableFrom(source.getClass())) return (T) mergeCollection((Collection) source, (Collection) target); // process map merge if (Map.class.isAssignableFrom(source.getClass())) return (T) mergeMap((Map) source, (Map) target); // process array merge if (source.getClass().isArray()) return (T) mergeArray((T[]) source, (T[]) target); // process single object merge if (!(source instanceof Mergeable)) return source; Field[] fields = FIELD_CACHE.get(source.getClass()); if (fields == null) fields = FieldUtils.getAllFields(source.getClass()); for (Field field : fields) { field.setAccessible(true); Object sourceValue = field.get(source); Object targetValue = field.get(target); // TODO: process null value force override case if (sourceValue == null) { continue; } field.set(target, merge(sourceValue, targetValue)); } return target; } catch (Exception e) { throw new RuntimeException(e); } } private static <T> Class<T> getCollectionElementType(Collection<T> list) { if (list == null || list.isEmpty()) { return null; } return (Class<T>) list.iterator().next().getClass(); } private static <T> Collection mergeCollection(Collection<T> source, Collection<T> target) { // source collection override target collection // source collection element merge into target collection element Class elementType = getCollectionElementType(source); if (!(Mergeable.class.isAssignableFrom(elementType))) return source; Map<String, Object> targetMap = new HashMap<>(); Iterator targetIterator = target.iterator(); while (targetIterator.hasNext()) { Object targetElement = targetIterator.next(); if (targetElement != null) { String mergeKey = ((Mergeable) targetElement)._mergeKey(); if (!StringUtils.isEmpty(mergeKey)) targetMap.put(mergeKey, targetElement); } } Iterator sourceIterator = source.iterator(); Set mergedSet = null; if (List.class.isAssignableFrom(source.getClass())) { sourceIterator = ((List) source).listIterator(); } else if (Set.class.isAssignableFrom(source.getClass())) { mergedSet = new HashSet<>(); } while (sourceIterator.hasNext()) { Object sourceElement = sourceIterator.next(); if (sourceElement == null) continue; Object targetElement = targetMap.get(((Mergeable) sourceElement)._mergeKey()); if (targetElement == null) continue; Object merged = merge(sourceElement, targetElement); if (List.class.isAssignableFrom(source.getClass())) { ((ListIterator) sourceIterator).set(merged); } else if (Set.class.isAssignableFrom(source.getClass())) { sourceIterator.remove(); mergedSet.add(merged); } else { throw new RuntimeException("Don't support merge for [" + source.getClass().getCanonicalName() + "] collection"); } } if (mergedSet != null) source.addAll(mergedSet); return source; } private static <K, V> Map mergeMap(Map<K, V> source, Map<K, V> target) { for (Map.Entry<K, V> entry : source.entrySet()) { K key = entry.getKey(); V value = entry.getValue(); source.put(key, merge(value, target.get(key))); } return source; } private static <T> T[] mergeArray(T[] source, T[] target) { // source array override target collection // source array element merge into target array element Class elementType = source.getClass().getComponentType(); if (!(Mergeable.class.isAssignableFrom(elementType))) return source; Map<String, T> targetMap = new HashMap<>(); for (T targetElement : target) { if (targetElement != null) { String mergeKey = ((Mergeable) targetElement)._mergeKey(); if (!StringUtils.isEmpty(mergeKey)) targetMap.put(mergeKey, targetElement); } } for (int i = 0; i < source.length; i++) { T sourceElement = source[i]; if (sourceElement != null) { source[i] = merge(sourceElement, targetMap.get(((Mergeable) source[i])._mergeKey())); } } return source; } }
merge two objects

Be the first to comment

You can use [html][/html], [css][/css], [php][/php] and more to embed the code. Urls are automatically hyperlinked. Line breaks and paragraphs are automatically generated.