Here you can find the source of cloneInternally(E source, Map
@SuppressWarnings("unchecked") static private <E> E cloneInternally(E source, Map<Object, Object> visited)
//package com.java2s; //License from project: Apache License import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.MonthDay; import java.time.OffsetDateTime; import java.time.OffsetTime; import java.time.Period; import java.time.Year; import java.time.YearMonth; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class Main { /** Immutable types that are safe to copy by reference */ final static Set<Class<?>> IMMUTABLES = new HashSet<>(Arrays.asList(Integer.class, Long.class, Double.class, Float.class, Byte.class, Character.class, Short.class, Boolean.class, BigDecimal.class, BigInteger.class, String.class, LocalDate.class, LocalTime.class, LocalDateTime.class, Instant.class, ZonedDateTime.class, Duration.class, MonthDay.class, OffsetDateTime.class, OffsetTime.class, Period.class, Year.class, YearMonth.class, ZoneOffset.class, Collections.emptyList().getClass(), Collections.emptySet().getClass(), Collections.emptyMap().getClass())); final static Set<String> SKIPPED_PROPS = new HashSet<>(Arrays.asList("class")); /** Static cache where property descriptors are kept for classes */ final static Map<Class<?>, PropertyDescriptor[]> PDS_CACHE = new ConcurrentHashMap<>(); static final List<Method> PROXY_TESTERS = new ArrayList<>(); static Class<?> SPRING_PROXY = null; static final Set<Class<?>> NOT_PROXY = Collections.newSetFromMap(new ConcurrentHashMap<>()); @SuppressWarnings("unchecked") static private <E> E cloneInternally(E source, Map<Object, Object> visited) { if (source == null) { return null; }/*from w w w . ja v a 2s.co m*/ Class<?> clazz = source.getClass(); if (clazz.isEnum() || IMMUTABLES.contains(clazz)) { return source; } if (clazz == Date.class) { return (E) ((Date) source).clone(); } if (visited.containsKey(source)) { return (E) visited.get(source); } if (clazz.isArray()) { final int size = Array.getLength(source); Object copy = Array.newInstance(clazz.getComponentType(), size); visited.put(source, copy); for (int i = 0; i < size; i++) { Object o = cloneInternally(Array.get(source, i), visited); Array.set(copy, i, o); } return (E) copy; } try { Object copy = tryInstantiate(clazz); clazz = copy.getClass(); visited.put(source, copy); if (Collection.class.isAssignableFrom(clazz)) { Collection<Object> c = (Collection<Object>) copy; ((Collection<?>) source).forEach(e -> c.add(cloneInternally(e, visited))); } else if (Map.class.isAssignableFrom(clazz)) { Map<Object, Object> m = (Map<Object, Object>) copy; ((Map<?, ?>) source) .forEach((k, v) -> m.put(cloneInternally(k, visited), cloneInternally(v, visited))); } else { PropertyDescriptor[] pds = PDS_CACHE.get(clazz); if (pds == null) { pds = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); PDS_CACHE.put(clazz, pds); } for (PropertyDescriptor d : pds) { try { if (SKIPPED_PROPS.contains(d.getName())) { continue; } Object c; Object o = d.getReadMethod().invoke(source); if (o == null || (c = cloneInternally(o, visited)) == null) { continue; } if (d.getWriteMethod() != null) { d.getWriteMethod().invoke(copy, c); } else if (Collection.class.isAssignableFrom(d.getPropertyType())) { Collection<Object> coll = (Collection<Object>) d.getReadMethod().invoke(copy); coll.addAll((Collection<?>) c); } } catch (Exception e) { e.printStackTrace(); } } } return (E) copy; } catch (ReflectiveOperationException | IntrospectionException e) { e.printStackTrace(); return null; } } static Object tryInstantiate(final Class<?> clazz) throws InstantiationException { Class<?> cl = clazz; while (cl != Object.class) { if (!isProxy(cl)) { try { return cl.newInstance(); } catch (ReflectiveOperationException goNext) { } } cl = cl.getSuperclass(); } if (Set.class.isAssignableFrom(clazz)) { return new HashSet<>(); } else if (Map.class.isAssignableFrom(clazz)) { return new HashMap<>(); } else if (Collection.class.isAssignableFrom(clazz)) { return new ArrayList<>(); } throw new InstantiationException(String.format( "Cannot find no-arg constructor in class %s or any its superclasses", clazz.getCanonicalName())); } static boolean isProxy(Class<?> clazz) { if (NOT_PROXY.contains(clazz)) { return false; } for (Method m : PROXY_TESTERS) { try { if ((boolean) m.invoke(null, clazz)) { return true; } } catch (Exception e) { } } if (SPRING_PROXY != null && SPRING_PROXY.isAssignableFrom(clazz)) { return true; } NOT_PROXY.add(clazz); return false; } }