Merge pull request #1185 from square/jwilson.0801.public_promoteNameToValue

Make JsonReader.promoteNameToValue() a public API
This commit is contained in:
Jesse Wilson
2020-08-05 11:10:24 -04:00
committed by GitHub
8 changed files with 203 additions and 10 deletions

View File

@@ -514,8 +514,19 @@ public abstract class JsonReader implements Closeable {
/**
* Changes the reader to treat the next name as a string value. This is useful for map adapters so
* that arbitrary type adapters can use {@link #nextString} to read a name value.
*
* <p>In this example, calling this method allows two sequential calls to {@link #nextString()}:
* <pre> {@code
*
* JsonReader reader = JsonReader.of(new Buffer().writeUtf8("{\"a\":\"b\"}"));
* reader.beginObject();
* reader.promoteNameToValue();
* assertEquals("a", reader.nextString());
* assertEquals("b", reader.nextString());
* reader.endObject();
* }</pre>
*/
abstract void promoteNameToValue() throws IOException;
public abstract void promoteNameToValue() throws IOException;
/**
* A set of strings to be chosen with {@link #selectName} or {@link #selectString}. This prepares

View File

@@ -1158,7 +1158,7 @@ final class JsonUtf8Reader extends JsonReader {
}
}
@Override void promoteNameToValue() throws IOException {
@Override public void promoteNameToValue() throws IOException {
if (hasNext()) {
peekedString = nextName();
peeked = PEEKED_BUFFERED;

View File

@@ -162,12 +162,13 @@ final class JsonUtf8Writer extends JsonWriter {
throw new IllegalStateException("JsonWriter is closed.");
}
int context = peekScope();
if ((context != EMPTY_OBJECT && context != NONEMPTY_OBJECT) || deferredName != null) {
if ((context != EMPTY_OBJECT && context != NONEMPTY_OBJECT)
|| deferredName != null
|| promoteValueToName) {
throw new IllegalStateException("Nesting problem.");
}
deferredName = name;
pathNames[stackSize - 1] = name;
promoteValueToName = false;
return this;
}
@@ -184,6 +185,7 @@ final class JsonUtf8Writer extends JsonWriter {
return nullValue();
}
if (promoteValueToName) {
promoteValueToName = false;
return name(value);
}
writeDeferredName();
@@ -236,6 +238,7 @@ final class JsonUtf8Writer extends JsonWriter {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
}
if (promoteValueToName) {
promoteValueToName = false;
return name(Double.toString(value));
}
writeDeferredName();
@@ -247,6 +250,7 @@ final class JsonUtf8Writer extends JsonWriter {
@Override public JsonWriter value(long value) throws IOException {
if (promoteValueToName) {
promoteValueToName = false;
return name(Long.toString(value));
}
writeDeferredName();
@@ -267,6 +271,7 @@ final class JsonUtf8Writer extends JsonWriter {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
}
if (promoteValueToName) {
promoteValueToName = false;
return name(string);
}
writeDeferredName();

View File

@@ -330,7 +330,7 @@ final class JsonValueReader extends JsonReader {
return new JsonValueReader(this);
}
@Override void promoteNameToValue() throws IOException {
@Override public void promoteNameToValue() throws IOException {
if (hasNext()) {
String name = nextName();
push(name);

View File

@@ -130,17 +130,17 @@ final class JsonValueWriter extends JsonWriter {
if (stackSize == 0) {
throw new IllegalStateException("JsonWriter is closed.");
}
if (peekScope() != EMPTY_OBJECT || deferredName != null) {
if (peekScope() != EMPTY_OBJECT || deferredName != null || promoteValueToName) {
throw new IllegalStateException("Nesting problem.");
}
deferredName = name;
pathNames[stackSize - 1] = name;
promoteValueToName = false;
return this;
}
@Override public JsonWriter value(@Nullable String value) throws IOException {
if (promoteValueToName) {
promoteValueToName = false;
return name(value);
}
add(value);
@@ -184,6 +184,7 @@ final class JsonValueWriter extends JsonWriter {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
}
if (promoteValueToName) {
promoteValueToName = false;
return name(Double.toString(value));
}
add(value);
@@ -193,6 +194,7 @@ final class JsonValueWriter extends JsonWriter {
@Override public JsonWriter value(long value) throws IOException {
if (promoteValueToName) {
promoteValueToName = false;
return name(Long.toString(value));
}
add(value);
@@ -223,6 +225,7 @@ final class JsonValueWriter extends JsonWriter {
? ((BigDecimal) value)
: new BigDecimal(value.toString());
if (promoteValueToName) {
promoteValueToName = false;
return name(bigDecimalValue.toString());
}
add(bigDecimalValue);

View File

@@ -443,8 +443,20 @@ public abstract class JsonWriter implements Closeable, Flushable {
/**
* 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.
*
* <p>In this example, calling this method allows two sequential calls to {@link #value(String)}
* to produce the object, {@code {"a": "b"}}.
* <pre> {@code
*
* JsonWriter writer = JsonWriter.of(...);
* writer.beginObject();
* writer.promoteValueToName();
* writer.value("a");
* writer.value("b");
* writer.endObject();
* }</pre>
*/
final void promoteValueToName() throws IOException {
public final void promoteValueToName() throws IOException {
int context = peekScope();
if (context != NONEMPTY_OBJECT && context != EMPTY_OBJECT) {
throw new IllegalStateException("Nesting problem.");

View File

@@ -20,7 +20,6 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -1158,6 +1157,85 @@ public final class JsonReaderTest {
reader.endObject();
}
@Test public void promoteStringNameToValue() throws IOException {
JsonReader reader = newReader("{\"a\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
assertEquals("a", reader.nextString());
assertEquals("b", reader.nextString());
reader.endObject();
}
@Test public void promoteDoubleNameToValue() throws IOException {
JsonReader reader = newReader("{\"5\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
assertEquals(5.0, reader.nextDouble(), 0.0);
assertEquals("b", reader.nextString());
reader.endObject();
}
@Test public void promoteLongNameToValue() throws IOException {
JsonReader reader = newReader("{\"5\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
assertEquals(5L, reader.nextLong());
assertEquals("b", reader.nextString());
reader.endObject();
}
@Test public void promoteNullNameToValue() throws IOException {
JsonReader reader = newReader("{\"null\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
try {
reader.nextNull();
fail();
} catch (JsonDataException expected) {
}
assertEquals("null", reader.nextString());
}
@Test public void promoteBooleanNameToValue() throws IOException {
JsonReader reader = newReader("{\"true\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
try {
reader.nextBoolean();
fail();
} catch (JsonDataException expected) {
}
assertEquals("true", reader.nextString());
}
@Test public void promoteBooleanNameToValueCannotBeReadAsName() throws IOException {
JsonReader reader = newReader("{\"true\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
try {
reader.nextName();
fail();
} catch (JsonDataException expected) {
}
assertEquals("true", reader.nextString());
}
@Test public void promoteSkippedNameToValue() throws IOException {
JsonReader reader = newReader("{\"true\":\"b\"}");
reader.beginObject();
reader.promoteNameToValue();
reader.skipValue();
assertEquals("b", reader.nextString());
}
@Test public void promoteNameToValueAtEndOfObject() throws IOException {
JsonReader reader = newReader("{}");
reader.beginObject();
reader.promoteNameToValue();
assertThat(reader.hasNext()).isFalse();
reader.endObject();
}
@Test public void optionsStrings() {
String[] options = new String[] { "a", "b", "c" };
JsonReader.Options abc = JsonReader.Options.of("a", "b", "c");

View File

@@ -609,7 +609,7 @@ public final class JsonWriterTest {
assertThat(expected).hasMessage("Nesting problem.");
}
}
@Test public void danglingNameFails() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
@@ -814,4 +814,88 @@ public final class JsonWriterTest {
assertThat(e).hasMessage("Map keys must be non-null");
}
}
@Test public void promoteStringNameToValue() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
writer.value("a");
writer.value("b");
writer.endObject();
assertThat(factory.json()).isEqualTo("{\"a\":\"b\"}");
}
@Test public void promoteDoubleNameToValue() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
writer.value(5.0);
writer.value("b");
writer.endObject();
assertThat(factory.json()).isEqualTo("{\"5.0\":\"b\"}");
}
@Test public void promoteLongNameToValue() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
writer.value(5L);
writer.value("b");
writer.endObject();
assertThat(factory.json()).isEqualTo("{\"5\":\"b\"}");
}
@Test public void promoteNumberNameToValue() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
writer.value(BigInteger.ONE);
writer.value("b");
writer.endObject();
assertThat(factory.json()).isEqualTo("{\"1\":\"b\"}");
}
@Test public void promoteNullNameToValue() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
try {
writer.nullValue();
fail();
} catch (IllegalStateException expected) {
assertThat(expected).hasMessage("null cannot be used as a map key in JSON at path $.");
}
}
@Test public void promoteBooleanNameToValue() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
try {
writer.value(true);
fail();
} catch (IllegalStateException expected) {
assertThat(expected).hasMessage("Boolean cannot be used as a map key in JSON at path $.");
}
}
@Test public void promoteNameToValueCannotBeWrittenAsName() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
try {
writer.name("a");
fail();
} catch (IllegalStateException expected) {
assertThat(expected).hasMessage("Nesting problem.");
}
}
@Test public void promoteNameToValueAtEndOfObject() throws IOException {
JsonWriter writer = factory.newWriter();
writer.beginObject();
writer.promoteValueToName();
writer.endObject();
assertThat(factory.json()).isEqualTo("{}");
}
}