diff --git a/src/org/mozilla/javascript/ScriptRuntime.java b/src/org/mozilla/javascript/ScriptRuntime.java index f6641cf23a..2a02469156 100644 --- a/src/org/mozilla/javascript/ScriptRuntime.java +++ b/src/org/mozilla/javascript/ScriptRuntime.java @@ -1476,6 +1476,10 @@ static Function getExistingCtor(Context cx, Scriptable scope, String constructor * Return -1L if str is not an index, or the index value as lower 32 bits of the result. Note * that the result needs to be cast to an int in order to produce the actual index, which may be * negative. + * + *

Note that this method on its own does not actually produce an index that is useful for an + * actual Object or Array, because it may be larger than Integer.MAX_VALUE. Most callers should + * instead call toStringOrIndex, which calls this under the covers. */ public static long indexFromString(String str) { // The length of the decimal string representation of diff --git a/src/org/mozilla/javascript/json/JsonParser.java b/src/org/mozilla/javascript/json/JsonParser.java index b07f2ee0f7..e00b0ac7ed 100644 --- a/src/org/mozilla/javascript/json/JsonParser.java +++ b/src/org/mozilla/javascript/json/JsonParser.java @@ -10,6 +10,7 @@ import java.util.List; import org.mozilla.javascript.Context; import org.mozilla.javascript.ScriptRuntime; +import org.mozilla.javascript.ScriptRuntime.StringIdOrIndex; import org.mozilla.javascript.Scriptable; /** @@ -118,13 +119,12 @@ private Object readObject() throws ParseException { consume(':'); value = readValue(); - long index = ScriptRuntime.indexFromString(id); - if (index < 0) { - object.put(id, object, value); + StringIdOrIndex indexObj = ScriptRuntime.toStringIdOrIndex(id); + if (indexObj.getStringId() == null) { + object.put(indexObj.getIndex(), object, value); } else { - object.put((int) index, object, value); + object.put(indexObj.getStringId(), object, value); } - needsComma = true; break; default: diff --git a/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java b/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java index 5ce6a09000..65498905dc 100644 --- a/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java +++ b/testsrc/org/mozilla/javascript/tests/json/JsonParserTest.java @@ -4,6 +4,7 @@ package org.mozilla.javascript.tests.json; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import org.junit.After; @@ -119,7 +120,6 @@ public void shouldParseEmptyJsonArray() throws Exception { } @Test - @SuppressWarnings("unchecked") public void shouldParseHeterogeneousJsonArray() throws Exception { NativeArray actual = (NativeArray) parser.parseValue("[ \"hello\" , 3, null, [false] ]"); assertEquals("hello", actual.get(0, actual)); @@ -138,18 +138,37 @@ public void shouldFailToParseArrayWithInvalidElements() throws Exception { } @Test - @SuppressWarnings({"serial", "unchecked"}) public void shouldParseJsonObject() throws Exception { String json = "{" + "\"bool\" : false, " + "\"str\" : \"xyz\", " + "\"obj\" : {\"a\":1} " + "}"; NativeObject actual = (NativeObject) parser.parseValue(json); assertEquals(false, actual.get("bool", actual)); assertEquals("xyz", actual.get("str", actual)); + assertArrayEquals( + "Property ordering should match", + new Object[] {"bool", "str", "obj"}, + actual.getIds()); NativeObject innerObj = (NativeObject) actual.get("obj", actual); assertEquals(1, innerObj.get("a", innerObj)); } + @Test + public void testECMAKeyOrdering() throws Exception { + try (Context cx = Context.enter()) { + cx.setLanguageVersion(Context.VERSION_ES6); + String json = + "{\"foo\": \"a\", \"bar\": \"b\", \"1\": \"c\", \"-1\": \"d\", \"x\": \"e\"}"; + NativeObject actual = (NativeObject) parser.parseValue(json); + // Ensure that modern ECMAScript property ordering works, which depends on + // valid index values being treated as numbers and not as strings. + assertArrayEquals( + "Property ordering should match", + new Object[] {1, "foo", "bar", "-1", "x"}, + actual.getIds()); + } + } + @Test(expected = ParseException.class) public void shouldFailToParseJsonObjectsWithInvalidFormat() throws Exception { parser.parseValue("{\"only\", \"keys\"}");