tags:

views:

1297

answers:

6

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

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.

+1  A: 

I'd recommend the DIY way which, combined with a good hashCode() and equals() method should be easy to proof in a unit test.

DaDaDom
well, the lazy me rants a lot when creating such a dummy code. But it is looking like the wiser path...
Guillaume
sorry, but DIY is the way to go _ONLY_ if no other solution is appropriate for you..which is almost never
Bozho
A: 

I'd suggest to override Object.clone(), call super.clone() first and than call ref = ref.clone() on all references that you want to have deep copied. It's more or less Do it yourself approach but needs a bit less coding.

x4u
That's one of the many problems of the (broken) clone method: In a class hierarchy you always have to call super.clone(), which can easily be forgotten, that's why I would prefer using a copy constructor.
Helper Method
A: 

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

Yoni Roit
reflection is not bullet proof: it can lead in some situation where your cloned object has reference to your source... If the source change, the clone will change too !
Guillaume
+5  A: 

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):

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.

Bozho
Thanks Bozho, that's valuable. And I agree with you about the DIY option !Have you ever tried the commons serialzation and/or the deep cloning lib ? What about the perfs ?
Guillaume
yes, I have used all of the above options, for the above reasons :) only the cloning library had some issues when CGLIB proxies were involved, and missed some desired functionality, but I think that should be fixed now.
Bozho
+2  A: 

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);)

LWoodyiii
Agreed. In my project I defined a `Copyable` interface that contains a `getCopy()` method. Just use the prototype pattern manually.
gpampara
Well I was not asking about the cloneable interface, but how to perform a deep clone/copy operation. With a constructor or a factory you still need to create your new instance from your source.
Guillaume
@Guillaume I think you need to be careful in using the words deep clone/copy. Clone and copy in java do NOT mean the same thing. The Java spec has more to say about this.... I think you want a deep copy from what I can tell.
LWoodyiii
@LWoodyiii, OK Java spec is accurate about what a clone is... But we can also speak of the clone in a more common meaning... For example, one of the lib recommended by bohzo is named 'Java Deep Cloning Library'...
Guillaume
+2  A: 

I've made another Generic Deep Copy utility available at http://www.genericdeepcopy.com/.

Aaron