While writing tests I came across a requirement to clone an object. found 2 Utill classes by apache-commons then I tried to find which one should I use, I’ve tried to find the diff by reading out both API doc but didn’t find which should I use when
As per doc: Clone a bean based on the available property getters and setters, even if the bean class itself does not implement Cloneable.
Doubt: should i use this on DTO cloning ?
SerializationUtils clone() API doc
As per doc:
Deep clone an Object using serialization.
This is many times slower than writing clone methods by hand on all objects in your object graph. However, for complex object graphs, or for those that don’t support deep cloning this can be a simple alternative implementation. Of course, all the objects must be Serializable.
Doubt: should I use it for both DTO and Entity Object ? or only for Entity
Advertisement
Answer
The SerializationUtils
will always produce a deep-copy. It will create a string of each field (it is called serialization) and parses the string back into a new object (deserialization).
This is quite slow, but you have the guarantee, that your copy is a deep copy.
A deep-copy means: All fields are new objects (and not a reference to a old object).
BeanUtils.cloneBean()
on the other hand, will create a shallow copy of your object. Here is some code to explain what is the difference:
@Data // lombok annotation, will create getters, setters, equals and hashcode public class ObjectA implements Serializeable { private List<String> values = new ArrayList<>(); } public static main() { ObjectA objectA = new ObjectA(); objectA().getValues().add("A"); ObjectA beanClone = (ObjectA) BeanUtils.cloneBean(objectA); ObjectA serialClone = SerializationUtils.clone(objectA); log.info("Reference-Check: Bean is same: {}", objectA == beanClone); // <- false log.info("Reference-Check: Bean-Value is same: {}", objectA.getValues() == beanClone.getValues()); // <- true log.info("Reference-Check: Serial is same: {}", objectA == serialClone); // <- false log.info("Reference-Check: Serial-Value is same: {}", objectA.getValues() == serialClone.getValues()); // <- false serialClone.getValues().add("B"); printValues(serialClone.getValues()); // <- prints "['A', 'B']" printValues(objectA.getValues()); // <- prints "['A']"; beanClone.getValues().add("B"); printValues(beanClone.getValues()); // <- prints "['A', 'B']" printValues(objectA.getValues()); // <- prints "['A', 'B']" }
So to your questions: A deep-copy is “safer”, you can’t modify fields of the original object. This side-effect on shallow copies is often unwanted. Almost always, you need a deep copy.
Serialization is quite slow, so the best way is a copy-method or a copy-constructor.