Don't decode into memory in RuntimeJsonAdapterFactory

Instead use our new flatten API to decode directly to the stream.
This commit is contained in:
Jesse Wilson
2018-10-19 12:03:44 -04:00
parent 01a406eac9
commit 6125d8c7b1
2 changed files with 32 additions and 8 deletions

View File

@@ -26,9 +26,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.CheckReturnValue; import javax.annotation.CheckReturnValue;
@@ -182,12 +180,12 @@ final class RuntimeJsonAdapterFactory<T> implements JsonAdapter.Factory {
+ ". Register this subtype."); + ". Register this subtype.");
} }
JsonAdapter<Object> adapter = jsonAdapters.get(labelIndex); JsonAdapter<Object> adapter = jsonAdapters.get(labelIndex);
Map<String, Object> jsonValue = (Map<String, Object>) adapter.toJsonValue(value); writer.beginObject();
writer.name(labelKey).value(labels.get(labelIndex));
Map<String, Object> valueWithLabel = new LinkedHashMap<>(1 + jsonValue.size()); int flattenToken = writer.beginFlatten();
valueWithLabel.put(labelKey, labels.get(labelIndex)); adapter.toJson(writer, value);
valueWithLabel.putAll(jsonValue); writer.endFlatten(flattenToken);
objectJsonAdapter.toJson(writer, valueWithLabel); writer.endObject();
} }
@Override public String toString() { @Override public String toString() {

View File

@@ -180,6 +180,24 @@ public final class RuntimeJsonAdapterFactoryTest {
} }
} }
/**
* Longs that do not have an exact double representation are problematic for JSON. It is a bad
* idea to use JSON for these values! But Moshi tries to retain long precision where possible.
*/
@Test public void unportableTypes() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(RuntimeJsonAdapterFactory.of(Message.class, "type")
.withSubtype(MessageWithUnportableTypes.class, "unportable"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
assertThat(adapter.toJson(new MessageWithUnportableTypes(9007199254740993L)))
.isEqualTo("{\"type\":\"unportable\",\"long_value\":9007199254740993}");
MessageWithUnportableTypes decoded = (MessageWithUnportableTypes) adapter.fromJson(
"{\"type\":\"unportable\",\"long_value\":9007199254740993}");
assertThat(decoded.long_value).isEqualTo(9007199254740993L);
}
interface Message { interface Message {
} }
@@ -226,4 +244,12 @@ public final class RuntimeJsonAdapterFactoryTest {
return "EmptyMessage"; return "EmptyMessage";
} }
} }
static final class MessageWithUnportableTypes implements Message {
final long long_value;
MessageWithUnportableTypes(long long_value) {
this.long_value = long_value;
}
}
} }