// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.eclipse.che.ide.collections; import org.eclipse.che.ide.collections.js.JsoArray; import com.google.gwt.core.client.JavaScriptObject; /** * Utility class for JavaScriptObject construction and serialization. We try to * keep all the nasty typesystem cludge with working with JavaScriptObject maps * confined in this class. We rely on identical method body coalescing to keep * the code small. * <p/> * TODO: Using the builder pattern like this for constructing JSOs * on the client will cause a lot of boundary crossings. Revisit this as a * potential perf optimization if we find ourselve spending a lot of time * building objects for serialization. */ public class Jso extends JavaScriptObject implements JsonObject { public static Jso create() { return JavaScriptObject.createObject().cast(); } /** Deserializes a JSON String and returns an overlay type. */ public static native <T extends Jso> T deserialize(String jsonString) /*-{ return JSON.parse(jsonString); }-*/; /** Serializes a JsonObject into a String. */ public static native String serialize(JavaScriptObject jso) /*-{ return JSON.stringify(jso); }-*/; protected Jso() { } @Override public native final JsonObject addField(String key, boolean value) /*-{ this[key] = value; return this; }-*/; @Override public native final JsonObject addField(String key, double value) /*-{ this[key] = value; return this; }-*/; @Override public native final JsonObject addField(String key, int value) /*-{ this[key] = value; return this; }-*/; @Override public final JsonObject addField(String key, Array<?> value) { // Delegate to the JS impl return addField(key, (Object)value); } @Override public final JsonObject addField(String key, JsonObject value) { // Delegate to the JS impl return addField(key, (Object)value); } public native final Jso addField(String key, Object value) /*-{ this[key] = value; return this; }-*/; @Override public native final Jso addField(String key, String value) /*-{ this[key] = value; return this; }-*/; public native final Jso addNullField(String key) /*-{ this[key] = null; return this; }-*/; public native final Jso addUndefinedField(String key) /*-{ this[key] = undefined; return this; }-*/; public native final Jso deleteField(String key) /*-{ delete this[key]; }-*/; @Override public final JsoArray<JsonObject> getArrayField(String key) { return ((Jso)getObjectField(key)).cast(); } @Override public final boolean getBooleanField(String key) { return getBooleanFieldImpl(key); } /** * @return evaluated boolean value (casted to a boolean). This is useful for * "optional" boolean fields to treat {@code undefined} values as * {@code false} */ public final native boolean getFieldCastedToBoolean(String key) /*-{ return !!this[key]; }-*/; @Override public final int getIntField(String key) { return getIntFieldImpl(key); } @Override public final double getDoubleField(String key) { return getFieldCastedToNumber(key); } /** * Evaluates a given property to an integer number. The {@code undefined} and * {@code null} key values will be casted to zero. * * @return evaluated integer value (casted to integer) */ public final int getFieldCastedToInteger(String key) { return (int)getFieldCastedToNumber(key); } /** * Evaluates a given property to a number. The {@code undefined} and * {@code null} key values will be casted to zero. * * @return evaluated number value (casted to number) */ private native double getFieldCastedToNumber(String key) /*-{ return +(this[key] || 0); }-*/; public native final JavaScriptObject getJsObjectField(String key) /*-{ return this[key]; }-*/; /* * GWT dev mode adds a __gwt_ObjectId property to all objects. We have to call * hasOwnProperty (which is overridden by GWT) when using for(in) loops to verify * that the key is actually a property of the object, and not the __gwt_ObjectId * set by Chrome dev mode. */ @Override public native final JsoArray<String> getKeys() /*-{ keys = []; for (key in this) { if (Object.prototype.hasOwnProperty.call(this, key)) { keys.push(key); } } return keys; }-*/; public native final boolean isEmpty() /*-{ for (key in this) { if (Object.prototype.hasOwnProperty.call(this, key)) { return false; } } return true; }-*/; @Override public native final JsonObject getObjectField(String key) /*-{ return this[key]; }-*/; public native final Object getJavaObjectField(String key) /*-{ return this[key]; }-*/; @Override public native final String getStringField(String key) /*-{ return this[key]; }-*/; /** @return evaluated string value (casted to string) */ public final native String getFieldCastedToString(String key) /*-{ return "" + this[key]; }-*/; /** * Checks to see if the specific key is present as a field/property on the * Jso. * <p/> * You should guard calls to primitive type getters with this or else you * might blow up at runtime (attempting to pass null as a return value for a * primitive type). * * @param key * @return whether or not */ public native final boolean hasOwnProperty(String key) /*-{ return this.hasOwnProperty(key); }-*/; public final String serialize() { return Jso.serialize(this); } private native boolean getBooleanFieldImpl(String key) /*-{ return this[key]; }-*/; private native int getIntFieldImpl(String key) /*-{ return this[key]; }-*/; /** Removes the GWT development/hosted mode property "__gwt_ObjectId". */ public final void removeGwtObjectId() { deleteField("__gwt_ObjectId"); } }