Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: recommended solution for deep cloning/copying an instance

Tags:

java

clone

I'm wondering if there is a recommended way of doing deep clone/copy of instance in java.

I have 3 solutions in mind, but I can have miss some, and I'd like to have your opinion

edit: include Bohzo propositon and refine question: it's more about deep cloning than shallow cloning.

Do it yourself:

code the clone by hand properties after properties and check that mutable instances are cloned too.
pro:
- control of what will be performed
- quick execution
cons:
- tedious to write and maintain
- bug prone (copy/paste failure, missing property, reassigned mutable property)

Use reflection:

With your own reflection tools or with an external helper (like jakarta common-beans) it is easy to write a generic copy method that will do the job in one line.
pro:
- easy to write
- no maintenance
cons:
- less control of what happens
- bug prone with mutable object if the reflection tool does not clone sub objects too
- slower execution

Use clone framework:

Use a framework that do it for you, like :
commons-lang SerializationUtils
Java Deep Cloning Library
Dozer
Kryo

pro:
- same as reflection
- more control over what will be exactly be cloned.
cons:
- every mutable instance is fully cloned, even at the end of the hierarchy
- could be very slow to execute

Use bytecode instrumentation to write clone at runtime

javassit, BCEL or cglib might be use to generate a dedicated cloner as fast as one hand writed. Someone knows a lib using one of these tools for this purpose ?

What I have missed here ?
Which one would you recommend ?

Thanks.

like image 321
Guillaume Avatar asked Jan 28 '10 16:01

Guillaume


People also ask

What is the most efficient way to deep clone an object in Javascript?

According to the benchmark test, the fastest way to deep clone an object in javascript is to use lodash deep clone function since Object. assign supports only shallow copy.

Where do we prefer deep and shallow copying while copying objects in Java?

To create the deep copy of an object, you have to override clone method. Shallow copy is preferred if an object has only primitive fields. Deep copy is preferred if an object has references to other objects as fields. Shallow copy is fast and also less expensive.

Does clone make a deep copy in Java?

clone() is indeed a shallow copy. However, it's designed to throw a CloneNotSupportedException unless your object implements Cloneable . And when you implement Cloneable , you should override clone() to make it do a deep copy, by calling clone() on all fields that are themselves cloneable.


6 Answers

For deep cloning (clones the entire object hierarchy):

  • commons-lang SerializationUtils - using serialization - if all classes are in your control and you can force implementing Serializable.

  • Java Deep Cloning Library - using reflection - in cases when the classes or the objects you want to clone are out of your control (a 3rd party library) and you can't make them implement Serializable, or in cases you don't want to implement Serializable.

For shallow cloning (clones only the first level properties):

  • commons-beanutils BeanUtils - in most cases.

  • Spring BeanUtils - if you are already using spring and hence have this utility on the classpath.

I deliberately omitted the "do-it-yourself" option - the API's above provide a good control over what to and what not to clone (for example using transient, or String[] ignoreProperties), so reinventing the wheel isn't preferred.

like image 53
Bozho Avatar answered Oct 24 '22 19:10

Bozho


Joshua Bloch's book has a whole chapter entitled "Item 10: Override Clone Judiciously" in which he goes into why overriding clone for the most part is a bad idea because the Java spec for it creates many problems.

He provides a few alternatives:

  • Use a factory pattern in place of a constructor:

         public static Yum newInstance(Yum yum);
    
  • Use a copy constructor:

         public Yum(Yum yum);
    

All of the collection classes in Java support the copy constructor (e.g. new ArrayList(l);)

like image 32
LeWoody Avatar answered Oct 24 '22 18:10

LeWoody


Since version 2.07 Kryo supports shallow/deep cloning:

Kryo kryo = new Kryo();
SomeClass someObject = ...
SomeClass copy1 = kryo.copy(someObject);
SomeClass copy2 = kryo.copyShallow(someObject);

Kryo is fast, at the and of their page you may find a list of companies which use it in production.

like image 32
Andrey Chaschev Avatar answered Oct 24 '22 19:10

Andrey Chaschev


Use XStream toXML/fromXML in memory. Extremely fast and has been around for a long time and is going strong. Objects don't need to be Serializable and you don't have use reflection (although XStream does). XStream can discern variables that point to the same object and not accidentally make two full copies of the instance. A lot of details like that have been hammered out over the years. I've used it for a number of years and it is a go to. It's about as easy to use as you can imagine.

new XStream().toXML(myObj)

or

new XStream().fromXML(myXML)

To clone,

new XStream().fromXML(new XStream().toXML(myObj))

More succinctly:

XStream x = new XStream();
Object myClone = x.fromXML(x.toXML(myObj));
like image 41
Ranx Avatar answered Oct 24 '22 17:10

Ranx


For complicated objects and when performance is not significant i use gson to serialize the object to json text, then deserialize the text to get new object.

gson which based on reflection will works in most cases, except that transient fields will not be copied and objects with circular reference with cause StackOverflowError.

public static <ObjectType> ObjectType Copy(ObjectType AnObject, Class<ObjectType> ClassInfo)
{
    Gson gson = new GsonBuilder().create();
    String text = gson.toJson(AnObject);
    ObjectType newObject = gson.fromJson(text, ClassInfo);
    return newObject;
}
public static void main(String[] args)
{
    MyObject anObject ...
    MyObject copyObject = Copy(o, MyObject.class);

}
like image 25
tiboo Avatar answered Oct 24 '22 18:10

tiboo


Depends.

For speed, use DIY. For bulletproof, use reflection.

BTW, serialization is not the same as refl, as some objects may provide overridden serialization methods (readObject/writeObject) and they can be buggy

like image 35
Yoni Roit Avatar answered Oct 24 '22 17:10

Yoni Roit