Deep Clone Utility Recommendation

Deep clone utility recommendation

I think the previous green answer was bad , why you might ask?

  • It adds a lot of code
  • It requires you to list all fields to be copied and do this
  • This will not work for Lists when using clone()
    (This is what clone() for HashMap says: Returns a shallow copy of this HashMap instance: the keys and valuesthemselves are not cloned.) so you end up doing it manually (this makes me cry)

Oh and by the way serialization is also bad, you might have to add Serializable all over the place (this also makes me cry).

So what is the solution:

Java Deep-Cloning library
The cloning library is a small, open source (apache licence) java library which deep-clones objects. The objects don't have to implement the Cloneable interface. Effectivelly, this library can clone ANY java objects. It can be used i.e. in cache implementations if you don't want the cached object to be modified or whenever you want to create a deep copy of objects.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Check it out at https://github.com/kostaskougios/cloning

Java: recommended solution for deep cloning/copying an instance

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.

Deep cloning objects

Whereas one approach is to implement the ICloneable interface (described here, so I won't regurgitate), here's a nice deep clone object copier I found on The Code Project a while ago and incorporated it into our code.
As mentioned elsewhere, it requires your objects to be serializable.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
/// <summary>
/// Perform a deep copy of the object via serialization.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>A deep copy of the object.</returns>
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", nameof(source));
}

// Don't serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null)) return default;

using var Stream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}

The idea is that it serializes your object and then deserializes it into a fresh object. The benefit is that you don't have to concern yourself about cloning everything when an object gets too complex.

In case of you prefer to use the new extension methods of C# 3.0, change the method to have the following signature:

public static T Clone<T>(this T source)
{
// ...
}

Now the method call simply becomes objectBeingCloned.Clone();.

EDIT (January 10 2015) Thought I'd revisit this, to mention I recently started using (Newtonsoft) Json to do this, it should be lighter, and avoids the overhead of [Serializable] tags. (NB @atconway has pointed out in the comments that private members are not cloned using the JSON method)

/// <summary>
/// Perform a deep Copy of the object, using Json as a serialization method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null)) return default;

// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

Java: How to deeply clone a complex hierarchy of objects easily?

You have a couple of options:

  1. Implement the clone method on all of the classes which deep copy the class and all of its instance variables (this is sometimes important to do if you do not want to rely on 3rd party frameworks)
  2. Serialize the object (it could be to a text file or a string). You can do this by using the Oracle framework Serializable that has one instance var which decodes information about the object. More info here: http://docs.oracle.com/javase/tutorial/jndi/objects/serial.html
  3. Here is a 3rd Party Library that can do a deep copy of an object: https://github.com/DozerMapper/dozer

More information on Deep Copy libraries: Java deep copy library

clone utility for HashMap in java

What about other objects referred to in the elements? How deep do you want your clone?

If your map elements don't have any deep references and/or everything is Serializable, you can serialize the map via ObjectOutputStream into a ByteArrayOutputStream and then deserialize it right away.

The only other alternative is to do it manually.

How do you make a deep copy of an object?

A safe way is to serialize the object, then deserialize. This ensures everything is a brand new reference.

Here's an article about how to do this efficiently.

Caveats: It's possible for classes to override serialization such that new instances are not created, e.g. for singletons. Also this of course doesn't work if your classes aren't Serializable.

how does java deep copy utility reserve objects' inner relationships?

Let's consider two references as having 'the same identity' if they are pointing to the same object. That is, given:

Object a = ...;
Object b = ...;

Then a and b are 'identical' if this holds: a == b, which will only hold if they point at the same object.

Note that a.equals(b) is different; any two references for which that holds can be considered 'equal', but 2 objects may be involved. Trivial example:

String a = new String("Hello");
String b = new String("Hello");
a == b; // this is false
a.equals(b); // this is true

It is possible to figure out if 2 references are identical and not just equal.

One easy check is literally what I just showed you: ==, which checks identical and not equal.

Most likely, the code in SerializationUnits uses WeakHashMap which is a map that maps on identity (more or less, 'the pointer'). WHM is mostly an internal implementation, but note that you can always get the identity hashcode via System.identityHashCode which returns the same value for the same object, even if that object is mutated. In theory, a.hashCode() can return a different value (and for mutable objects, it tends to), but System.identityHashCode(a) is the same value for any given instance for the lifetime of a VM.

Plain jane HashMap uses a.hashCode() to know which bucket to look at, and then a.equals(b) to scan for equality.

A WeakHashMap uses System.identityHashCode(a) to know which bucket to look at, and then a == b to scan for equality.

Armed with that, writing a serializer that preserves hierarchy and relationship is then trivial.

Note also that without such a mechanism, solid serialization is impossible. After all, imagine this structure:

List<Object> list = new ArrayList<Object>();
list.add(list); // ooooh, recursion!

without tools like WeakHashMap, any attempt to serialize this construct will result in a StackOverflowError, for obvious reasons.

Creating a deep copy of cache in mulithreaded Java application

For Your use case, returning a new cache from database.getData(); is much better choice. Because If You choose this way, You would only have to create new cache object once in 15 second. If You choose to clone cache in each task, You would have to create 4501 cache object in 15 second. Obviously returning new cache object is the right choice.

If the code You provided is the same code as in Your project, I believe database.getData(); method changing the content of a single cache object instead of returning a new one. If You return a new cache object from this method Your problem will be solved.



Related Topics



Leave a reply



Submit