What is the best way to make a deep copy of a gwt overlay type?
I'm looking for a function or library that inspects a GWT overlay and clones it. It must be able to clone contained arrays or objects.
Thanks
What is the best way to make a deep copy of a gwt overlay type?
I'm looking for a function or library that inspects a GWT overlay and clones it. It must be able to clone contained arrays or objects.
Thanks
There are 2 ways that I would consider. Most of the time overlay objects are used in conjunction with JSON, so you could just stringify the object and parse the results:
public native MyOverlayType deepCopy()/*-{
return JSON.parse(JSON.stringify(this));
}-*/;
OR
public static native MyOverlayType fromJson(String json)/*-{
return JSON.parse(json);
}-*/;
public native String getJson()/*-{
return JSON.stringify(this);
}-*/;
public MyOverlayType deepCopy(){
return fromJson(getJson());
}
The other option is a pure javascript approach which will maintain other stuff such as function pointers and probably be more efficient.
public class JsoUtils
{
@SuppressWarnings("unchecked")
public static <T extends JavaScriptObject> T deepCopy(T obj)
{
return (T) deepCopyImpl(obj);
}
private static native JavaScriptObject deepCopyImpl(JavaScriptObject obj)/*-{
if (typeof obj !== 'object' || obj === null) {
return obj;
}
var c = obj instanceof Array ? [] : {};
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
if (typeof obj[i] !== 'object' || obj[i] === null)
c[i] = obj[i];
else
c[i] = @com.example.gwt.client.JsoUtils::deepCopyImpl(Lcom/google/gwt/core/client/JavaScriptObject;)(obj[i]);
}
}
return c;
}-*/;
}
Based on Lineman78's answer and taking into consideration this other answer from A. Levy I created the following function:
public class JsoUtils {
@SuppressWarnings("unchecked")
public static <T extends JavaScriptObject> T deepCopy(T obj)
{
return (T) deepCopyImpl(obj);
}
private static native JavaScriptObject deepCopyImpl(JavaScriptObject obj) /*-{
if (obj == null) return obj;
var copy;
if (obj instanceof Date) {
// Handle Date
copy = new Date();
copy.setTime(obj.getTime());
} else if (obj instanceof Array) {
// Handle Array
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
if (obj[i] == null || typeof obj[i] != "object") copy[i] = obj[i];
else copy[i] = @com.amindea.noah.client.utils.JsoUtils::deepCopyImpl(Lcom/google/gwt/core/client/JavaScriptObject;)(obj[i]);
}
} else {
// Handle Object
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) {
if (obj[attr] == null || typeof obj[attr] != "object") copy[attr] = obj[attr];
else copy[attr] = @com.amindea.noah.client.utils.JsoUtils::deepCopyImpl(Lcom/google/gwt/core/client/JavaScriptObject;)(obj[attr]);
}
}
}
return copy;
}-*/;
}
It supports deep copy of Object, Array, Date, String, Number, or Boolean. As explained by A. Levy the function will work as long as the data in the objects and arrays form a tree structure.
I found the simplest way to clone a JavaScriptObject is using the JsonUtils class provided by GWT:
import com.google.gwt.core.client.JsonUtils;
final String taskJson = JsonUtils.stringify(selectedTask);
TaskJso task = JsonUtils.safeEval(taskJson).cast();