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.
org.iworkz.common.helper.CloneHelper Maven / Gradle / Ivy
package org.iworkz.common.helper;
import java.io.Closeable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Date;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.iworkz.common.reflection.PropertyInfo;
@Singleton
public class CloneHelper {
private static final Object PROPERTIES_CACHE_LOCK = new Object();
private static final Map,PropertyInfo[]> PROPERTIES_CACHE = new IdentityHashMap<>();
@Inject
protected ReflectionHelper reflectionHelper;
/**
* Clone the source bean and the properties of the source bean recursively (deep copy).
* Cyclic dependencies are detected and handled correctly.
*
* @param source
* @return
*/
public T cloneBean(T source) {
Map instanceMap = new IdentityHashMap<>();
return cloneBean(source,instanceMap);
}
@SuppressWarnings("unchecked")
public T cloneBean(final T source, final Map instanceMap) {
if (source != null) {
if (instanceMap.containsKey(source)) {
return (T)instanceMap.get(source);
} else {
Class> sourceClass = source.getClass();
T destination;
if (sourceClass.isArray()) {
final Class> componentType = sourceClass.getComponentType();
boolean finalImmutuable = reflectionHelper.isImmutable(componentType);
destination = (T)cloneArray(source,componentType,finalImmutuable,instanceMap);
} else if (Collection.class.isAssignableFrom(sourceClass)) {
destination = (T)cloneCollection((Collection>)source,instanceMap);
} else if (Map.class.isAssignableFrom(sourceClass)) {
destination = (T)cloneMap((Map,?>)source,instanceMap);
} else if (isCloneRequired(sourceClass)) {
destination = clone(source,instanceMap);
} else {
destination = source;
}
return destination;
}
}
return null;
}
protected T clone(final T source, final Map instanceMap) {
T destination = createCustomClone(source,instanceMap);
if (destination != null) {
instanceMap.put(source, destination);
} else {
/* create generic clone */
destination = createClone(source);
instanceMap.put(source, destination);
cloneProperties(source, destination, instanceMap);
}
return destination;
}
@SuppressWarnings("unchecked")
protected T createClone(final T source) {
return (T)reflectionHelper.createObject(source.getClass());
}
@SuppressWarnings("unchecked")
protected T createCustomClone(final T source, final Map instanceMap) {
T destination = null;
Class> sourceClass = source.getClass();
if (Date.class.isAssignableFrom(sourceClass)) {
if (java.sql.Date.class == sourceClass) {
destination = (T)new java.sql.Date(((java.sql.Date)source).getTime());
} else if (java.util.Date.class == sourceClass) {
destination = (T)new java.util.Date(((java.util.Date)source).getTime());
} else if (java.sql.Time.class == sourceClass) {
destination = (T)new java.sql.Time(((java.sql.Time)source).getTime());
} else if (java.sql.Timestamp.class == sourceClass) {
destination = (T)new java.sql.Timestamp(((java.sql.Timestamp)source).getTime());
} else {
destination = null;
}
}
return destination;
}
protected void cloneProperties(final T source, final T destination, final Map instanceMap) {
if (source != null) {
if (destination == null) {
throw new IllegalArgumentException("The destination bean is null");
}
try {
PropertyInfo[] propertyInfos = getPropertyInfos(source.getClass());
for (PropertyInfo propertyInfo : propertyInfos) {
Object value = propertyInfo.getReadMethod().invoke(source);
if (value != null) {
if (propertyInfo.isImmutable()) {
propertyInfo.getWriteMethod().invoke(destination,value);
} else if (propertyInfo.isMap()) {
propertyInfo.getWriteMethod().invoke(destination,cloneMap((Map,?>)value,instanceMap));
} else if (propertyInfo.isCollection()) {
propertyInfo.getWriteMethod().invoke(destination,cloneCollection((Collection>)value,instanceMap));
} else if (propertyInfo.isArray()) {
final Class> componentType = value.getClass().getComponentType();
propertyInfo.getWriteMethod().invoke(destination,cloneArray(value,componentType,propertyInfo.isComponentImmutable(),instanceMap));
} else {
propertyInfo.getWriteMethod().invoke(destination,cloneBean(value,instanceMap));
}
}
}
} catch (Exception e) {
throw new RuntimeException("Can not clone bean '"+source.getClass().getCanonicalName()+"'",e);
}
}
}
@SuppressWarnings("unchecked")
protected Collection createCollection(final Collection sourceCollection) {
return (Collection)reflectionHelper.createObject(sourceCollection.getClass());
}
@SuppressWarnings("unchecked")
protected Map createMap(final Map sourceMap) {
return (Map)reflectionHelper.createObject(sourceMap.getClass());
}
protected boolean isCloneRequired(Class> sourceClass) {
if (reflectionHelper.isImmutable(sourceClass)) {
return false;
}
if (Closeable.class.isAssignableFrom(sourceClass)) {
return false;
}
return true;
}
protected Object cloneArray(Object source, Class> sourceClass, final boolean finalImmutable, final Map instanceMap) {
if (instanceMap.containsKey(source)) {
return instanceMap.get(source);
} else {
int length = Array.getLength(source);
Object destination = Array.newInstance(sourceClass,length);
instanceMap.put(source, destination);
if (finalImmutable) {
System.arraycopy(source,0,destination,0,length);
} else {
for (int i=0;i Collection cloneCollection(final Collection collection, final Map instanceMap) {
if (instanceMap.containsKey(collection)) {
return (Collection)instanceMap.get(collection);
} else {
Collection destination = createCollection(collection);
instanceMap.put(collection, destination);
for (T sourceItem : collection) {
destination.add(cloneBean(sourceItem,instanceMap));
}
return destination;
}
}
protected Map cloneMap(final Map map, final Map instanceMap) {
if (instanceMap.containsKey(map)) {
return (Map)instanceMap.get(map);
} else {
Map destination = createMap(map);
instanceMap.put(map, destination);
for (T sourceKey : map.keySet()) {
R sourceItem = map.get(sourceKey);
destination.put(sourceKey,cloneBean(sourceItem,instanceMap));
}
return destination;
}
}
protected PropertyInfo[] getPropertyInfos(final Class> sourceClass) {
PropertyInfo[] propertyInfos = PROPERTIES_CACHE.get(sourceClass);
if (propertyInfos == null) {
synchronized (PROPERTIES_CACHE_LOCK) {
try {
/* get propertyInfos again but this time synchronized */
propertyInfos = PROPERTIES_CACHE.get(sourceClass);
if (propertyInfos == null) {
List propertyInfoList = reflectionHelper.createPropertyInfos(sourceClass);
propertyInfos = propertyInfoList.toArray(new PropertyInfo[propertyInfoList.size()]);
PROPERTIES_CACHE.put(sourceClass, propertyInfos);
}
} catch (Exception ex) {
throw new RuntimeException("Can not create property infos",ex);
}
}
}
return propertyInfos;
}
}