Add coherent error message for unencoded map keys.

This commit is contained in:
Eric Cochran
2018-04-25 11:36:47 -07:00
parent 1c68437f3c
commit 44e6fbd067
4 changed files with 97 additions and 2 deletions

View File

@@ -77,6 +77,10 @@ final class JsonUtf8Writer extends JsonWriter {
} }
@Override public JsonWriter beginArray() throws IOException { @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(); writeDeferredName();
return open(EMPTY_ARRAY, "["); return open(EMPTY_ARRAY, "[");
} }
@@ -86,6 +90,10 @@ final class JsonUtf8Writer extends JsonWriter {
} }
@Override public JsonWriter beginObject() throws IOException { @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(); writeDeferredName();
return open(EMPTY_OBJECT, "{"); return open(EMPTY_OBJECT, "{");
} }
@@ -171,6 +179,10 @@ final class JsonUtf8Writer extends JsonWriter {
} }
@Override public JsonWriter nullValue() throws IOException { @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 (deferredName != null) {
if (serializeNulls) { if (serializeNulls) {
writeDeferredName(); writeDeferredName();
@@ -186,6 +198,10 @@ final class JsonUtf8Writer extends JsonWriter {
} }
@Override public JsonWriter value(boolean value) throws IOException { @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(); writeDeferredName();
beforeValue(); beforeValue();
sink.writeUtf8(value ? "true" : "false"); sink.writeUtf8(value ? "true" : "false");

View File

@@ -47,6 +47,10 @@ final class JsonValueWriter extends JsonWriter {
} }
@Override public JsonWriter beginArray() throws IOException { @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(); checkStack();
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
add(list); add(list);
@@ -67,6 +71,10 @@ final class JsonValueWriter extends JsonWriter {
} }
@Override public JsonWriter beginObject() throws IOException { @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(); checkStack();
Map<String, Object> map = new LinkedHashTreeMap<>(); Map<String, Object> map = new LinkedHashTreeMap<>();
add(map); add(map);
@@ -116,18 +124,30 @@ final class JsonValueWriter extends JsonWriter {
} }
@Override public JsonWriter nullValue() throws IOException { @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); add(null);
pathIndices[stackSize - 1]++; pathIndices[stackSize - 1]++;
return this; return this;
} }
@Override public JsonWriter value(boolean value) throws IOException { @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); add(value);
pathIndices[stackSize - 1]++; pathIndices[stackSize - 1]++;
return this; return this;
} }
@Override public JsonWriter value(@Nullable Boolean value) throws IOException { @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); add(value);
pathIndices[stackSize - 1]++; pathIndices[stackSize - 1]++;
return this; return this;

View File

@@ -141,6 +141,65 @@ public final class MapJsonAdapterTest {
assertThat(jsonAdapter.fromJsonValue(jsonObject)).isEqualTo(map); assertThat(jsonAdapter.fromJsonValue(jsonObject)).isEqualTo(map);
} }
@Test public void booleanKeyTypeHasCoherentErrorMessage() {
Map<Boolean, String> map = new LinkedHashMap<>();
map.put(true, "");
JsonAdapter<Map<Boolean, String>> 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<Key, String> map = new LinkedHashMap<>();
map.put(new Key(), "");
JsonAdapter<Map<Key, String>> 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<String[], String> map = new LinkedHashMap<>();
map.put(new String[0], "");
JsonAdapter<Map<String[], String>> 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 <K, V> String toJson(Type keyType, Type valueType, Map<K, V> value) throws IOException { private <K, V> String toJson(Type keyType, Type valueType, Map<K, V> value) throws IOException {
JsonAdapter<Map<K, V>> jsonAdapter = mapAdapter(keyType, valueType); JsonAdapter<Map<K, V>> jsonAdapter = mapAdapter(keyType, valueType);
Buffer buffer = new Buffer(); Buffer buffer = new Buffer();

View File

@@ -252,7 +252,7 @@ public final class PromoteNameToValueTest {
writer.value(true); writer.value(true);
fail(); fail();
} catch (IllegalStateException e) { } 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"); writer.value("true");
assertThat(writer.getPath()).isEqualTo("$.true"); assertThat(writer.getPath()).isEqualTo("$.true");
@@ -283,7 +283,7 @@ public final class PromoteNameToValueTest {
writer.nullValue(); writer.nullValue();
fail(); fail();
} catch (IllegalStateException e) { } 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"); writer.value("null");
assertThat(writer.getPath()).isEqualTo("$.null"); assertThat(writer.getPath()).isEqualTo("$.null");