in empire-db/src/main/java/org/apache/empire/commons/ClassUtils.java [149:248]
public static <T> T copy(T obj, int flags)
{
if (obj==null)
return null;
// the class
Class<T> clazz = (Class<T>)obj.getClass();
if (isImmutableClass(clazz))
{ // no need to copy
return obj;
}
// class check
if (clazz.isInterface() || clazz.isAnnotation()) {
log.warn("Unable to copy Interface or Annotation {}", clazz.getName());
return (Copy.has(flags, Copy.RET_NULL) ? null : obj); // not supported
}
// try serialize
if ((obj instanceof Serializable) && !Copy.has(flags, Copy.SKIP_SERIAL))
{ try
{ ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Write the object
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
// Read the object
ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
Object copy = oin.readObject();
// return result
return (T)copy;
} catch (IOException | ClassNotFoundException e) {
log.error("Copy through Serialization failed for : "+clazz.getName(), e);
}
}
// array copy
if (clazz.isArray())
{ // check primitive array like int[] or boolean[]
if (!(obj instanceof Object[]))
{ if (Copy.has(flags, Copy.RECURSE_DEEP))
log.warn("Copy.RECURSE_DEEP not supported for primitive arrays of type {}", clazz.getSimpleName());
return (T)invokeSimpleMethod(java.lang.Object.class, obj, "clone", true);
}
// Object-array: cast and clone
T[] cpy = ((T[])obj).clone();
if (Copy.has(flags, Copy.RECURSE_DEEP))
{ // copy array items
for (int i=0; i<cpy.length; i++)
cpy[i] = copy(cpy[i], (flags & ~(Copy.RET_NULL)));
}
return (T)cpy;
}
// try clone
if ((obj instanceof Cloneable) && !Copy.has(flags, Copy.SKIP_CLONE))
{ try {
return (T)invokeSimpleMethod(java.lang.Object.class, obj, "clone", true);
} catch (Exception e) {
log.error("Copy through Cloning failed for : "+clazz.getName(), e);
}
}
// try copy through instantiation
Constructor<T> ctor = (Copy.has(flags, Copy.SKIP_INST) ? null : findMatchingConstructor(clazz, 0, clazz));
if (ctor!=null)
{ try
{ if (ctor.getParameterCount()==1)
{ // try copy constructor
return ctor.newInstance(obj);
}
else
{ // Try default constructor and copy fields
T copy = ctor.newInstance();
// copy fields of this class and all superclasses
for (Class<?> cl = clazz; (cl!=null && cl!=Object.class); cl=cl.getSuperclass())
{
Field[] fields = cl.getDeclaredFields();
for (Field field : fields) {
// ignore static fields
if (Modifier.isStatic(field.getModifiers()))
continue;
// make accessible
boolean accessible = field.isAccessible();
if (!accessible)
field.setAccessible(true);
// copy
Object value = field.get(obj);
if (Copy.has(flags, Copy.RECURSE_FLAT | Copy.RECURSE_DEEP))
value = copy(value, (flags & ~(Copy.RET_NULL | Copy.RECURSE_FLAT)));
field.set(copy, value);
// restore
if (!accessible)
field.setAccessible(false);
}
}
return copy;
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
// ReflectiveOperationException
Throwable cause = (e.getCause()!=null ? e.getCause() : e);
log.error("Copy through Instantiation failed for {}: {}", clazz.getName(), cause);
}
}
// not supported
return (Copy.has(flags, Copy.RET_NULL) ? null : obj);
}