diff --git a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java index 4fa074d..5cedfe1 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java @@ -77,6 +77,10 @@ final class JsonUtf8Writer extends JsonWriter { } @Override public JsonWriter beginArray() throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Array cannot be used as a map key in JSON at path " + getPath()); + } writeDeferredName(); return open(EMPTY_ARRAY, "["); } @@ -86,6 +90,10 @@ final class JsonUtf8Writer extends JsonWriter { } @Override public JsonWriter beginObject() throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Object cannot be used as a map key in JSON at path " + getPath()); + } writeDeferredName(); return open(EMPTY_OBJECT, "{"); } @@ -171,6 +179,10 @@ final class JsonUtf8Writer extends JsonWriter { } @Override public JsonWriter nullValue() throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "null cannot be used as a map key in JSON at path " + getPath()); + } if (deferredName != null) { if (serializeNulls) { writeDeferredName(); @@ -186,6 +198,10 @@ final class JsonUtf8Writer extends JsonWriter { } @Override public JsonWriter value(boolean value) throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Boolean cannot be used as a map key in JSON at path " + getPath()); + } writeDeferredName(); beforeValue(); sink.writeUtf8(value ? "true" : "false"); diff --git a/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java b/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java index 9879739..9bc06b3 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java @@ -47,6 +47,10 @@ final class JsonValueWriter extends JsonWriter { } @Override public JsonWriter beginArray() throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Array cannot be used as a map key in JSON at path " + getPath()); + } checkStack(); List list = new ArrayList<>(); add(list); @@ -67,6 +71,10 @@ final class JsonValueWriter extends JsonWriter { } @Override public JsonWriter beginObject() throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Object cannot be used as a map key in JSON at path " + getPath()); + } checkStack(); Map map = new LinkedHashTreeMap<>(); add(map); @@ -116,18 +124,30 @@ final class JsonValueWriter extends JsonWriter { } @Override public JsonWriter nullValue() throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "null cannot be used as a map key in JSON at path " + getPath()); + } add(null); pathIndices[stackSize - 1]++; return this; } @Override public JsonWriter value(boolean value) throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Boolean cannot be used as a map key in JSON at path " + getPath()); + } add(value); pathIndices[stackSize - 1]++; return this; } @Override public JsonWriter value(@Nullable Boolean value) throws IOException { + if (promoteValueToName) { + throw new IllegalStateException( + "Boolean cannot be used as a map key in JSON at path " + getPath()); + } add(value); pathIndices[stackSize - 1]++; return this; diff --git a/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java index dd3e796..c967047 100644 --- a/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java @@ -141,6 +141,65 @@ public final class MapJsonAdapterTest { assertThat(jsonAdapter.fromJsonValue(jsonObject)).isEqualTo(map); } + @Test public void booleanKeyTypeHasCoherentErrorMessage() { + Map map = new LinkedHashMap<>(); + map.put(true, ""); + JsonAdapter> adapter = mapAdapter(Boolean.class, String.class); + try { + adapter.toJson(map); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected).hasMessage("Boolean cannot be used as a map key in JSON at path $."); + } + try { + adapter.toJsonValue(map); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected).hasMessage("Boolean cannot be used as a map key in JSON at path $."); + } + } + + static final class Key { + } + + @Test public void objectKeyTypeHasCoherentErrorMessage() { + Map map = new LinkedHashMap<>(); + map.put(new Key(), ""); + JsonAdapter> adapter = mapAdapter(Key.class, String.class); + try { + adapter.toJson(map); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected).hasMessage("Object cannot be used as a map key in JSON at path $."); + } + try { + adapter.toJsonValue(map); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected).hasMessage("Object cannot be " + + "used as a map key in JSON at path $."); + } + } + + @Test public void arrayKeyTypeHasCoherentErrorMessage() { + Map map = new LinkedHashMap<>(); + map.put(new String[0], ""); + JsonAdapter> adapter = + mapAdapter(Types.arrayOf(String.class), String.class); + try { + adapter.toJson(map); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected).hasMessage("Array cannot be used as a map key in JSON at path $."); + } + try { + adapter.toJsonValue(map); + fail(); + } catch (IllegalStateException expected) { + assertThat(expected).hasMessage("Array cannot be used as a map key in JSON at path $."); + } + } + private String toJson(Type keyType, Type valueType, Map value) throws IOException { JsonAdapter> jsonAdapter = mapAdapter(keyType, valueType); Buffer buffer = new Buffer(); diff --git a/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java b/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java index c50005d..335e9d0 100644 --- a/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java +++ b/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java @@ -252,7 +252,7 @@ public final class PromoteNameToValueTest { writer.value(true); fail(); } catch (IllegalStateException e) { - assertThat(e).hasMessage("Nesting problem."); + assertThat(e).hasMessage("Boolean cannot be used as a map key in JSON at path $."); } writer.value("true"); assertThat(writer.getPath()).isEqualTo("$.true"); @@ -283,7 +283,7 @@ public final class PromoteNameToValueTest { writer.nullValue(); fail(); } catch (IllegalStateException e) { - assertThat(e).hasMessage("Nesting problem."); + assertThat(e).hasMessage("null cannot be used as a map key in JSON at path $."); } writer.value("null"); assertThat(writer.getPath()).isEqualTo("$.null");