Add JsonWriter.jsonValue API

This is symmetric with JsonReader.readJsonValue in that it writes an Object comprised of maps, lists, and some scalars.
This commit is contained in:
Jake Wharton
2020-02-14 22:58:32 -05:00
parent d64033ed94
commit 0790296cc7
3 changed files with 127 additions and 0 deletions

View File

@@ -429,6 +429,7 @@ public abstract class JsonReader implements Closeable {
*
* @throws JsonDataException if the next token is not a literal value, if a JSON object has a
* duplicate key.
* @see JsonWriter#jsonValue(Object)
*/
public final @Nullable Object readJsonValue() throws IOException {
switch (peek()) {

View File

@@ -19,6 +19,8 @@ import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import okio.BufferedSink;
@@ -386,6 +388,58 @@ public abstract class JsonWriter implements Closeable, Flushable {
@CheckReturnValue
public abstract BufferedSink valueSink() throws IOException;
/**
* Encodes the value which may be a string, number, boolean, null, map, or list.
*
* @return this writer.
* @see JsonReader#readJsonValue()
*/
public final JsonWriter jsonValue(@Nullable Object value) throws IOException {
if (value instanceof Map<?, ?>) {
beginObject();
for (Map.Entry<?, ?> entry : ((Map<?, ?>) value).entrySet()) {
Object key = entry.getKey();
if (!(key instanceof String)) {
throw new IllegalArgumentException(key == null
? "Map keys must be non-null"
: "Map keys must be of type String: " + key.getClass().getName());
}
name(((String) key));
jsonValue(entry.getValue());
}
endObject();
} else if (value instanceof List<?>) {
beginArray();
for (Object element : ((List<?>) value)) {
jsonValue(element);
}
endArray();
} else if (value instanceof String) {
value(((String) value));
} else if (value instanceof Boolean) {
value(((Boolean) value).booleanValue());
} else if (value instanceof Double) {
value(((Double) value).doubleValue());
} else if (value instanceof Long) {
value(((Long) value).longValue());
} else if (value instanceof Number) {
value(((Number) value));
} else if (value == null) {
nullValue();
} else {
throw new IllegalArgumentException("Unsupported type: " + value.getClass().getName());
}
return this;
}
/**
* Changes the writer to treat the next value as a string name. This is useful for map adapters so
* that arbitrary type adapters can use {@link #value} to write a name value.

View File

@@ -18,7 +18,11 @@ package com.squareup.moshi;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import okio.BufferedSink;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -742,4 +746,72 @@ public final class JsonWriterTest {
assertThat(factory.json()).isEqualTo("{\"a\":1.0}");
sink.close();
}
@Test public void jsonValueTypes() throws IOException {
JsonWriter writer = factory.newWriter();
writer.setSerializeNulls(true);
writer.beginArray();
writer.jsonValue(null);
writer.jsonValue(1.1d);
writer.jsonValue(1L);
writer.jsonValue(1);
writer.jsonValue(true);
writer.jsonValue("one");
writer.jsonValue(Collections.emptyList());
writer.jsonValue(Arrays.asList(1, 2, null, 3));
writer.jsonValue(Collections.emptyMap());
Map<String, Object> map = new LinkedHashMap<>();
map.put("one", "uno");
map.put("two", null);
writer.jsonValue(map);
writer.endArray();
assertThat(factory.json()).isEqualTo("["
+ "null,"
+ "1.1,"
+ "1,"
+ "1,"
+ "true,"
+ "\"one\","
+ "[],"
+ "[1,2,null,3],"
+ "{},"
+ "{\"one\":\"uno\",\"two\":null}"
+ "]");
}
@Test public void jsonValueIllegalTypes() throws IOException {
try {
factory.newWriter().jsonValue(new Object());
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Unsupported type: java.lang.Object");
}
try {
factory.newWriter().jsonValue('1');
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Unsupported type: java.lang.Character");
}
Map<Integer, String> mapWrongKey = new LinkedHashMap<>();
mapWrongKey.put(1, "one");
try {
factory.newWriter().jsonValue(mapWrongKey);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Map keys must be of type String: java.lang.Integer");
}
Map<String, String> mapNullKey = new LinkedHashMap<>();
mapNullKey.put(null, "one");
try {
factory.newWriter().jsonValue(mapNullKey);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Map keys must be non-null");
}
}
}