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.