Switch InternalJsMap to interface and properly type it.
Also removes the JSNI involved.
Change-Id: Id7bda0173a40ada3820bbc650b9487b7a0bab84a
diff --git a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
index 2aa14c2..2f73382 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
@@ -103,8 +103,8 @@
@Override
public Iterator<Entry<K, V>> iterator() {
- return new Iterator<Map.Entry<K,V>>() {
- final InternalJsMap.Iterator<Object> chains = backingMap.entries();
+ return new Iterator<Map.Entry<K, V>>() {
+ final InternalJsMap.Iterator<?> chains = backingMap.entries();
int itemIndex = 0;
Entry<K, V>[] chain = newEntryChain();
Entry<K, V> lastEntry = null;
@@ -114,8 +114,8 @@
if (itemIndex < chain.length) {
return true;
}
- InternalJsMap.IteratorEntry<Object> current = chains.next();
- if (!current.done) {
+ InternalJsMap.IteratorEntry<?> current = chains.next();
+ if (!current.isDone()) {
// Move to the beginning of next chain
chain = unsafeCastToArray(current.getValue());
itemIndex = 0;
diff --git a/user/super/com/google/gwt/emul/java/util/InternalJsMap.java b/user/super/com/google/gwt/emul/java/util/InternalJsMap.java
index 5dfbfe3..8149274 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalJsMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalJsMap.java
@@ -18,40 +18,60 @@
import javaemul.internal.JsUtils;
import jsinterop.annotations.JsOverlay;
import jsinterop.annotations.JsPackage;
+import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
-// TODO(goktug): These classes should be interfaces with defender methods instead.
-@JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL)
-class InternalJsMap<V> {
+@JsType(isNative = true, name = "Map", namespace = JsPackage.GLOBAL)
+interface InternalJsMap<V> {
- @JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL)
- static class Iterator<V> {
- public native IteratorEntry<V> next();
+ @JsType(isNative = true, name = "IteratorIterable", namespace = JsPackage.GLOBAL)
+ interface Iterator<V> {
+ IteratorEntry<V> next();
}
- @JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL)
- static class IteratorEntry<V> {
- private Object[] value;
- public boolean done;
+ // IteratorEntry<V> is the modeling for IIterableResult<Array<String|V>> as IteratorEntry<V> but
+ // java and jsinterop lack expressibility to represent this abstraction (Java does not have
+ // union types and JsInterop does not allow to map type variables). So IteratorEntry<V> ends up
+ // mapping to IIterableResult<V> which is not an accurate mapping.
+ // It is convenient to model in this way so that users of this internal class don't have to deal
+ // with the internal implementation and the mismatch is handled here with overlay methods.
+ @JsType(isNative = true, name = "IIterableResult", namespace = JsPackage.GLOBAL)
+ interface IteratorEntry<V> {
+ @JsProperty
+ boolean isDone();
+ @JsProperty(name = "value")
+ Object[] getValueInternal();
@JsOverlay
- public final String getKey() { return JsUtils.unsafeCastToString(value[0]); }
+ default String getKey() { return JsUtils.uncheckedCast(getValueInternal()[0]); }
@JsOverlay
- public final V getValue() { return (V) value[1]; }
+ default V getValue() { return JsUtils.uncheckedCast(getValueInternal()[1]); }
}
- public native V get(int key);
- public native V get(String key);
- public native void set(int key, V value);
- public native void set(String key, V value);
- @JsOverlay
- public final void delete(int key) { JsHelper.delete(this, key); }
- @JsOverlay
- public final void delete(String key) { JsHelper.delete(this, key); }
- public native Iterator<V> entries();
+ V get(int key);
+ V get(String key);
+ void set(int key, V value);
+ void set(String key, V value);
+ Iterator<V> entries();
- // Calls to delete are via brackets to be compatible with old browsers where delete is keyword.
- private static class JsHelper {
- static native void delete(InternalJsMap obj, int key) /*-{ obj["delete"](key); }-*/;
- static native void delete(InternalJsMap obj, String key) /*-{ obj["delete"](key); }-*/;
+ @JsOverlay
+ default void delete(int key) {
+ // Calls delete without map.delete in order to be compatible with old browsers where delete is a
+ // keyword.
+ DeleteFunction fn = JsUtils.getProperty(this, "delete");
+ fn.call(this, key);
+ }
+
+ @JsOverlay
+ default void delete(String key) {
+ // Calls delete without map.delete in order to be compatible with old browsers where delete is a
+ // keyword.
+ DeleteFunction fn = JsUtils.getProperty(this, "delete");
+ fn.call(this, key);
+ }
+
+ @JsType(isNative = true, name = "Function", namespace = JsPackage.GLOBAL)
+ interface DeleteFunction {
+ void call(InternalJsMap<?> thisArg, String key);
+ void call(InternalJsMap<?> thisArg, int key);
}
}
diff --git a/user/super/com/google/gwt/emul/java/util/InternalStringMap.java b/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
index 3daa2af..8366f6f 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalStringMap.java
@@ -82,21 +82,23 @@
@Override
public Iterator<Entry<K, V>> iterator() {
- return new Iterator<Map.Entry<K,V>>() {
+ return new Iterator<Map.Entry<K, V>>() {
InternalJsMap.Iterator<V> entries = backingMap.entries();
InternalJsMap.IteratorEntry<V> current = entries.next();
InternalJsMap.IteratorEntry<V> last;
@Override
public boolean hasNext() {
- return !current.done;
+ return !current.isDone();
}
+
@Override
public Entry<K, V> next() {
last = current;
current = entries.next();
return newMapEntry(last, valueMod);
}
+
@Override
public void remove() {
InternalStringMap.this.remove(last.getKey());
@@ -104,14 +106,15 @@
};
}
- private Entry<K, V> newMapEntry(final InternalJsMap.IteratorEntry<V> entry,
- final int lastValueMod) {
+ private Entry<K, V> newMapEntry(
+ final InternalJsMap.IteratorEntry<V> entry, final int lastValueMod) {
return new AbstractMapEntry<K, V>() {
@SuppressWarnings("unchecked")
@Override
public K getKey() {
return (K) entry.getKey();
}
+
@Override
public V getValue() {
if (valueMod != lastValueMod) {
@@ -120,6 +123,7 @@
}
return entry.getValue();
}
+
@Override
public V setValue(V object) {
return put(entry.getKey(), object);