Introduced tags to reader/writers (#1227)

* Introduced tags to reader/writers

* Removed getTags method

* Added type safety to tag methods

* Changed to explicit class comparison

* Removed ? extends for tags

* Switched to LinkedHashMap

* Allowed polymorphism for tag values

* Simplified tags tests
This commit is contained in:
Lachlan McKee
2020-09-22 13:56:51 +01:00
committed by GitHub
parent 53c1bf0cac
commit bf72ce8ade
4 changed files with 90 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckReturnValue;
@@ -197,6 +198,8 @@ public abstract class JsonReader implements Closeable {
/** True to throw a {@link JsonDataException} on any attempt to call {@link #skipValue()}. */
boolean failOnUnknown;
private Map<Class<?>, Object> tags;
/** Returns a new instance that reads UTF-8 encoded JSON from {@code source}. */
@CheckReturnValue
public static JsonReader of(BufferedSource source) {
@@ -569,6 +572,27 @@ public abstract class JsonReader implements Closeable {
return JsonScope.getPath(stackSize, scopes, pathNames, pathIndices);
}
/** Returns the tag value for the given class key. */
@SuppressWarnings("unchecked")
@CheckReturnValue
public final @Nullable <T> T tag(Class<T> clazz) {
if (tags == null) {
return null;
}
return (T) tags.get(clazz);
}
/** Assigns the tag value using the given class key and value. */
public final <T> void setTag(Class<T> clazz, T value) {
if (!clazz.isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Tag value must be of type " + clazz.getName());
}
if (tags == null) {
tags = new LinkedHashMap<>();
}
tags.put(clazz, value);
}
/**
* 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.

View File

@@ -24,6 +24,7 @@ import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckReturnValue;
@@ -171,6 +172,8 @@ public abstract class JsonWriter implements Closeable, Flushable {
*/
int flattenStackSize = -1;
private Map<Class<?>, Object> tags;
/** Returns a new instance that writes UTF-8 encoded JSON to {@code sink}. */
@CheckReturnValue
public static JsonWriter of(BufferedSink sink) {
@@ -561,4 +564,25 @@ public abstract class JsonWriter implements Closeable, Flushable {
public final String getPath() {
return JsonScope.getPath(stackSize, scopes, pathNames, pathIndices);
}
/** Returns the tag value for the given class key. */
@SuppressWarnings("unchecked")
@CheckReturnValue
public final @Nullable <T> T tag(Class<T> clazz) {
if (tags == null) {
return null;
}
return (T) tags.get(clazz);
}
/** Assigns the tag value using the given class key and value. */
public final <T> void setTag(Class<T> clazz, T value) {
if (!clazz.isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Tag value must be of type " + clazz.getName());
}
if (tags == null) {
tags = new LinkedHashMap<>();
}
tags.put(clazz, value);
}
}

View File

@@ -1433,6 +1433,27 @@ public final class JsonReaderTest {
assertThat(reader.nextString()).isEqualTo("d");
}
@SuppressWarnings("rawtypes")
@Test
public void tags() throws IOException {
JsonReader reader = newReader("{}");
assertThat(reader.tag(Integer.class)).isNull();
assertThat(reader.tag(CharSequence.class)).isNull();
reader.setTag(Integer.class, 1);
reader.setTag(CharSequence.class, "Foo");
try {
reader.setTag((Class) CharSequence.class, 1);
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Tag value must be of type java.lang.CharSequence");
}
assertThat(reader.tag(Integer.class)).isEqualTo(1).isInstanceOf(Integer.class);
assertThat(reader.tag(CharSequence.class)).isEqualTo("Foo").isInstanceOf(String.class);
assertThat(reader.tag(String.class)).isNull();
}
/** Peek a value, then read it, recursively. */
private void readValue(JsonReader reader, boolean peekJsonFirst) throws IOException {
JsonReader.Token token = reader.peek();

View File

@@ -953,4 +953,25 @@ public final class JsonWriterTest {
writer.endObject();
assertThat(factory.json()).isEqualTo("{}");
}
@SuppressWarnings("rawtypes")
@Test
public void tags() throws IOException {
JsonWriter writer = factory.newWriter();
assertThat(writer.tag(Integer.class)).isNull();
assertThat(writer.tag(CharSequence.class)).isNull();
writer.setTag(Integer.class, 1);
writer.setTag(CharSequence.class, "Foo");
try {
writer.setTag((Class) CharSequence.class, 1);
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Tag value must be of type java.lang.CharSequence");
}
assertThat(writer.tag(Integer.class)).isEqualTo(1).isInstanceOf(Integer.class);
assertThat(writer.tag(CharSequence.class)).isEqualTo("Foo").isInstanceOf(String.class);
assertThat(writer.tag(String.class)).isNull();
}
}