Switch to spotless and format code (#1196)

* Add spotless configuration

* Reformat!

* Add copyright config for build.gradle.kts files

* Add toeholds for headers
This commit is contained in:
Zac Sweers
2020-08-27 23:40:15 -04:00
committed by GitHub
parent 701d6ba968
commit 538890e8c0
109 changed files with 6748 additions and 4972 deletions

View File

@@ -23,14 +23,16 @@ import java.util.Date;
* The new class is {@code com.squareup.moshi.adapters.Rfc3339DateJsonAdapter}.
*/
public final class Rfc3339DateJsonAdapter extends JsonAdapter<Date> {
private final com.squareup.moshi.adapters.Rfc3339DateJsonAdapter delegate
= new com.squareup.moshi.adapters.Rfc3339DateJsonAdapter();
private final com.squareup.moshi.adapters.Rfc3339DateJsonAdapter delegate =
new com.squareup.moshi.adapters.Rfc3339DateJsonAdapter();
@Override public Date fromJson(JsonReader reader) throws IOException {
@Override
public Date fromJson(JsonReader reader) throws IOException {
return delegate.fromJson(reader);
}
@Override public void toJson(JsonWriter writer, Date value) throws IOException {
@Override
public void toJson(JsonWriter writer, Date value) throws IOException {
delegate.toJson(writer, value);
}
}

View File

@@ -29,12 +29,11 @@ import javax.annotation.Nullable;
* not match any enum value. To use, add this as an adapter for your enum type on your {@link
* com.squareup.moshi.Moshi.Builder Moshi.Builder}:
*
* <pre> {@code
*
* Moshi moshi = new Moshi.Builder()
* .add(CurrencyCode.class, EnumJsonAdapter.create(CurrencyCode.class)
* .withUnknownFallback(CurrencyCode.USD))
* .build();
* <pre>{@code
* Moshi moshi = new Moshi.Builder()
* .add(CurrencyCode.class, EnumJsonAdapter.create(CurrencyCode.class)
* .withUnknownFallback(CurrencyCode.USD))
* .build();
* }</pre>
*/
public final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
@@ -78,15 +77,21 @@ public final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
}
}
@Override public @Nullable T fromJson(JsonReader reader) throws IOException {
@Override
public @Nullable T fromJson(JsonReader reader) throws IOException {
int index = reader.selectString(options);
if (index != -1) return constants[index];
String path = reader.getPath();
if (!useFallbackValue) {
String name = reader.nextString();
throw new JsonDataException("Expected one of "
+ Arrays.asList(nameStrings) + " but was " + name + " at path " + path);
throw new JsonDataException(
"Expected one of "
+ Arrays.asList(nameStrings)
+ " but was "
+ name
+ " at path "
+ path);
}
if (reader.peek() != JsonReader.Token.STRING) {
throw new JsonDataException(
@@ -96,7 +101,8 @@ public final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
return fallbackValue;
}
@Override public void toJson(JsonWriter writer, T value) throws IOException {
@Override
public void toJson(JsonWriter writer, T value) throws IOException {
if (value == null) {
throw new NullPointerException(
"value was null! Wrap in .nullSafe() to write nullable values.");
@@ -104,7 +110,8 @@ public final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
writer.value(nameStrings[value.ordinal()]);
}
@Override public String toString() {
@Override
public String toString() {
return "EnumJsonAdapter(" + enumType.getName() + ")";
}
}

View File

@@ -26,11 +26,12 @@ import java.util.TimeZone;
* Jacksons date formatter, pruned to Moshi's needs. Forked from this file:
* https://github.com/FasterXML/jackson-databind/blob/67ebf7305f492285a8f9f4de31545f5f16fc7c3a/src/main/java/com/fasterxml/jackson/databind/util/ISO8601Utils.java
*
* Utilities methods for manipulating dates in iso8601 format. This is much much faster and GC
* <p>Utilities methods for manipulating dates in iso8601 format. This is much much faster and GC
* friendly than using SimpleDateFormat so highly suitable if you (un)serialize lots of date
* objects.
*
* Supported parse format: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:]mm]]
* <p>Supported parse format:
* [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:]mm]]
*
* @see <a href="http://www.w3.org/TR/NOTE-datetime">this specification</a>
*/
@@ -167,8 +168,11 @@ final class Iso8601Utils {
*/
String cleaned = act.replace(":", "");
if (!cleaned.equals(timezoneId)) {
throw new IndexOutOfBoundsException("Mismatching time zone indicator: "
+ timezoneId + " given, resolves to " + timezone.getID());
throw new IndexOutOfBoundsException(
"Mismatching time zone indicator: "
+ timezoneId
+ " given, resolves to "
+ timezone.getID());
}
}
}
@@ -259,8 +263,7 @@ final class Iso8601Utils {
}
/**
* Returns the index of the first character in the string that is not a digit, starting at
* offset.
* Returns the index of the first character in the string that is not a digit, starting at offset.
*/
private static int indexOfNonDigit(String string, int offset) {
for (int i = offset; i < string.length(); i++) {

View File

@@ -38,50 +38,47 @@ import javax.annotation.Nullable;
*
* <p>Suppose we have an interface, its implementations, and a class that uses them:
*
* <pre> {@code
* <pre>{@code
* interface HandOfCards {
* }
*
* interface HandOfCards {
* }
* class BlackjackHand implements HandOfCards {
* Card hidden_card;
* List<Card> visible_cards;
* }
*
* class BlackjackHand implements HandOfCards {
* Card hidden_card;
* List<Card> visible_cards;
* }
* class HoldemHand implements HandOfCards {
* Set<Card> hidden_cards;
* }
*
* class HoldemHand implements HandOfCards {
* Set<Card> hidden_cards;
* }
*
* class Player {
* String name;
* HandOfCards hand;
* }
* class Player {
* String name;
* HandOfCards hand;
* }
* }</pre>
*
* <p>We want to decode the following JSON into the player model above:
*
* <pre> {@code
*
* {
* "name": "Jesse",
* "hand": {
* "hand_type": "blackjack",
* "hidden_card": "9D",
* "visible_cards": ["8H", "4C"]
* }
* <pre>{@code
* {
* "name": "Jesse",
* "hand": {
* "hand_type": "blackjack",
* "hidden_card": "9D",
* "visible_cards": ["8H", "4C"]
* }
* }
* }</pre>
*
* <p>Left unconfigured, Moshi would incorrectly attempt to decode the hand object to the abstract
* {@code HandOfCards} interface. We configure it to use the appropriate subtype instead:
*
* <pre> {@code
*
* Moshi moshi = new Moshi.Builder()
* .add(PolymorphicJsonAdapterFactory.of(HandOfCards.class, "hand_type")
* .withSubtype(BlackjackHand.class, "blackjack")
* .withSubtype(HoldemHand.class, "holdem"))
* .build();
* <pre>{@code
* Moshi moshi = new Moshi.Builder()
* .add(PolymorphicJsonAdapterFactory.of(HandOfCards.class, "hand_type")
* .withSubtype(BlackjackHand.class, "blackjack")
* .withSubtype(HoldemHand.class, "holdem"))
* .build();
* }</pre>
*
* <p>This class imposes strict requirements on its use:
@@ -95,23 +92,25 @@ import javax.annotation.Nullable;
* <li>Each type identifier must be unique.
* </ul>
*
* <p>For best performance type information should be the first field in the object. Otherwise
* Moshi must reprocess the JSON stream once it knows the object's type.
* <p>For best performance type information should be the first field in the object. Otherwise Moshi
* must reprocess the JSON stream once it knows the object's type.
*
* <p>If an unknown subtype is encountered when decoding:
* <ul>
* <li>If {@link #withDefaultValue(Object)} is used, then {@code defaultValue} will be returned.
* <li>If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the
* {@code fallbackJsonAdapter.fromJson(reader)} result will be returned.
* <li>Otherwise a {@link JsonDataException} will be thrown.
* </ul>
*
* <ul>
* <li>If {@link #withDefaultValue(Object)} is used, then {@code defaultValue} will be returned.
* <li>If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the {@code
* fallbackJsonAdapter.fromJson(reader)} result will be returned.
* <li>Otherwise a {@link JsonDataException} will be thrown.
* </ul>
*
* <p>If an unknown type is encountered when encoding:
* <ul>
* <li>If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the
* {@code fallbackJsonAdapter.toJson(writer, value)} result will be returned.
* <li>Otherwise a {@link IllegalArgumentException} will be thrown.
* </ul>
*
* <ul>
* <li>If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the {@code
* fallbackJsonAdapter.toJson(writer, value)} result will be returned.
* <li>Otherwise a {@link IllegalArgumentException} will be thrown.
* </ul>
*
* <p>If the same subtype has multiple labels the first one is used when encoding.
*/
@@ -145,16 +144,10 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
if (baseType == null) throw new NullPointerException("baseType == null");
if (labelKey == null) throw new NullPointerException("labelKey == null");
return new PolymorphicJsonAdapterFactory<>(
baseType,
labelKey,
Collections.<String>emptyList(),
Collections.<Type>emptyList(),
null);
baseType, labelKey, Collections.<String>emptyList(), Collections.<Type>emptyList(), null);
}
/**
* Returns a new factory that decodes instances of {@code subtype}.
*/
/** Returns a new factory that decodes instances of {@code subtype}. */
public PolymorphicJsonAdapterFactory<T> withSubtype(Class<? extends T> subtype, String label) {
if (subtype == null) throw new NullPointerException("subtype == null");
if (label == null) throw new NullPointerException("label == null");
@@ -165,27 +158,21 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
newLabels.add(label);
List<Type> newSubtypes = new ArrayList<>(subtypes);
newSubtypes.add(subtype);
return new PolymorphicJsonAdapterFactory<>(baseType,
labelKey,
newLabels,
newSubtypes,
fallbackJsonAdapter);
return new PolymorphicJsonAdapterFactory<>(
baseType, labelKey, newLabels, newSubtypes, fallbackJsonAdapter);
}
/**
* Returns a new factory that with default to {@code fallbackJsonAdapter.fromJson(reader)}
* upon decoding of unrecognized labels.
* Returns a new factory that with default to {@code fallbackJsonAdapter.fromJson(reader)} upon
* decoding of unrecognized labels.
*
* <p>The {@link JsonReader} instance will not be automatically consumed, so sure to consume it
* within your implementation of {@link JsonAdapter#fromJson(JsonReader)}
*/
public PolymorphicJsonAdapterFactory<T> withFallbackJsonAdapter(
@Nullable JsonAdapter<Object> fallbackJsonAdapter) {
return new PolymorphicJsonAdapterFactory<>(baseType,
labelKey,
labels,
subtypes,
fallbackJsonAdapter);
return new PolymorphicJsonAdapterFactory<>(
baseType, labelKey, labels, subtypes, fallbackJsonAdapter);
}
/**
@@ -198,14 +185,22 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
private JsonAdapter<Object> buildFallbackJsonAdapter(final T defaultValue) {
return new JsonAdapter<Object>() {
@Override public @Nullable Object fromJson(JsonReader reader) throws IOException {
@Override
public @Nullable Object fromJson(JsonReader reader) throws IOException {
reader.skipValue();
return defaultValue;
}
@Override public void toJson(JsonWriter writer, Object value) throws IOException {
throw new IllegalArgumentException("Expected one of " + subtypes + " but found " + value
+ ", a " + value.getClass() + ". Register this subtype.");
@Override
public void toJson(JsonWriter writer, Object value) throws IOException {
throw new IllegalArgumentException(
"Expected one of "
+ subtypes
+ " but found "
+ value
+ ", a "
+ value.getClass()
+ ". Register this subtype.");
}
};
}
@@ -221,12 +216,8 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
jsonAdapters.add(moshi.adapter(subtypes.get(i)));
}
return new PolymorphicJsonAdapter(labelKey,
labels,
subtypes,
jsonAdapters,
fallbackJsonAdapter
).nullSafe();
return new PolymorphicJsonAdapter(labelKey, labels, subtypes, jsonAdapters, fallbackJsonAdapter)
.nullSafe();
}
static final class PolymorphicJsonAdapter extends JsonAdapter<Object> {
@@ -241,7 +232,8 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
/** Corresponds to subtypes. */
final JsonReader.Options labelOptions;
PolymorphicJsonAdapter(String labelKey,
PolymorphicJsonAdapter(
String labelKey,
List<String> labels,
List<Type> subtypes,
List<JsonAdapter<Object>> jsonAdapters,
@@ -256,7 +248,8 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
this.labelOptions = JsonReader.Options.of(labels.toArray(new String[0]));
}
@Override public Object fromJson(JsonReader reader) throws IOException {
@Override
public Object fromJson(JsonReader reader) throws IOException {
JsonReader peeked = reader.peekJson();
peeked.setFailOnUnknown(false);
int labelIndex;
@@ -283,8 +276,14 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
int labelIndex = reader.selectString(labelOptions);
if (labelIndex == -1 && this.fallbackJsonAdapter == null) {
throw new JsonDataException("Expected one of " + labels + " for key '" + labelKey
+ "' but found '" + reader.nextString() + "'. Register a subtype for this label.");
throw new JsonDataException(
"Expected one of "
+ labels
+ " for key '"
+ labelKey
+ "' but found '"
+ reader.nextString()
+ "'. Register a subtype for this label.");
}
return labelIndex;
}
@@ -292,14 +291,21 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
throw new JsonDataException("Missing label for " + labelKey);
}
@Override public void toJson(JsonWriter writer, Object value) throws IOException {
@Override
public void toJson(JsonWriter writer, Object value) throws IOException {
Class<?> type = value.getClass();
int labelIndex = subtypes.indexOf(type);
final JsonAdapter<Object> adapter;
if (labelIndex == -1) {
if (fallbackJsonAdapter == null) {
throw new IllegalArgumentException("Expected one of " + subtypes + " but found " + value
+ ", a " + value.getClass() + ". Register this subtype.");
throw new IllegalArgumentException(
"Expected one of "
+ subtypes
+ " but found "
+ value
+ ", a "
+ value.getClass()
+ ". Register this subtype.");
}
adapter = fallbackJsonAdapter;
} else {
@@ -316,7 +322,8 @@ public final class PolymorphicJsonAdapterFactory<T> implements JsonAdapter.Facto
writer.endObject();
}
@Override public String toString() {
@Override
public String toString() {
return "PolymorphicJsonAdapter(" + labelKey + ")";
}
}

View File

@@ -26,15 +26,15 @@ import java.util.Date;
* formatted like {@code 2015-09-26T18:23:50.250Z}. This adapter is null-safe. To use, add this as
* an adapter for {@code Date.class} on your {@link com.squareup.moshi.Moshi.Builder Moshi.Builder}:
*
* <pre> {@code
*
* Moshi moshi = new Moshi.Builder()
* .add(Date.class, new Rfc3339DateJsonAdapter())
* .build();
* <pre>{@code
* Moshi moshi = new Moshi.Builder()
* .add(Date.class, new Rfc3339DateJsonAdapter())
* .build();
* }</pre>
*/
public final class Rfc3339DateJsonAdapter extends JsonAdapter<Date> {
@Override public synchronized Date fromJson(JsonReader reader) throws IOException {
@Override
public synchronized Date fromJson(JsonReader reader) throws IOException {
if (reader.peek() == JsonReader.Token.NULL) {
return reader.nextNull();
}
@@ -42,7 +42,8 @@ public final class Rfc3339DateJsonAdapter extends JsonAdapter<Date> {
return Iso8601Utils.parse(string);
}
@Override public synchronized void toJson(JsonWriter writer, Date value) throws IOException {
@Override
public synchronized void toJson(JsonWriter writer, Date value) throws IOException {
if (value == null) {
writer.nullValue();
} else {

View File

@@ -15,53 +15,57 @@
*/
package com.squareup.moshi.adapters;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import com.squareup.moshi.Json;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.JsonReader;
import okio.Buffer;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
@SuppressWarnings("CheckReturnValue")
public final class EnumJsonAdapterTest {
@Test public void toAndFromJson() throws Exception {
@Test
public void toAndFromJson() throws Exception {
EnumJsonAdapter<Roshambo> adapter = EnumJsonAdapter.create(Roshambo.class);
assertThat(adapter.fromJson("\"ROCK\"")).isEqualTo(Roshambo.ROCK);
assertThat(adapter.toJson(Roshambo.PAPER)).isEqualTo("\"PAPER\"");
}
@Test public void withJsonName() throws Exception {
@Test
public void withJsonName() throws Exception {
EnumJsonAdapter<Roshambo> adapter = EnumJsonAdapter.create(Roshambo.class);
assertThat(adapter.fromJson("\"scr\"")).isEqualTo(Roshambo.SCISSORS);
assertThat(adapter.toJson(Roshambo.SCISSORS)).isEqualTo("\"scr\"");
}
@Test public void withoutFallbackValue() throws Exception {
@Test
public void withoutFallbackValue() throws Exception {
EnumJsonAdapter<Roshambo> adapter = EnumJsonAdapter.create(Roshambo.class);
JsonReader reader = JsonReader.of(new Buffer().writeUtf8("\"SPOCK\""));
try {
adapter.fromJson(reader);
fail();
} catch (JsonDataException expected) {
assertThat(expected).hasMessage(
"Expected one of [ROCK, PAPER, scr] but was SPOCK at path $");
assertThat(expected).hasMessage("Expected one of [ROCK, PAPER, scr] but was SPOCK at path $");
}
assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
}
@Test public void withFallbackValue() throws Exception {
EnumJsonAdapter<Roshambo> adapter = EnumJsonAdapter.create(Roshambo.class)
.withUnknownFallback(Roshambo.ROCK);
@Test
public void withFallbackValue() throws Exception {
EnumJsonAdapter<Roshambo> adapter =
EnumJsonAdapter.create(Roshambo.class).withUnknownFallback(Roshambo.ROCK);
JsonReader reader = JsonReader.of(new Buffer().writeUtf8("\"SPOCK\""));
assertThat(adapter.fromJson(reader)).isEqualTo(Roshambo.ROCK);
assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
}
@Test public void withNullFallbackValue() throws Exception {
EnumJsonAdapter<Roshambo> adapter = EnumJsonAdapter.create(Roshambo.class)
.withUnknownFallback(null);
@Test
public void withNullFallbackValue() throws Exception {
EnumJsonAdapter<Roshambo> adapter =
EnumJsonAdapter.create(Roshambo.class).withUnknownFallback(null);
JsonReader reader = JsonReader.of(new Buffer().writeUtf8("\"SPOCK\""));
assertThat(adapter.fromJson(reader)).isNull();
assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
@@ -70,6 +74,7 @@ public final class EnumJsonAdapterTest {
enum Roshambo {
ROCK,
PAPER,
@Json(name = "scr") SCISSORS
@Json(name = "scr")
SCISSORS
}
}

View File

@@ -15,6 +15,9 @@
*/
package com.squareup.moshi.adapters;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.JsonReader;
@@ -27,17 +30,17 @@ import javax.annotation.Nullable;
import okio.Buffer;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
@SuppressWarnings("CheckReturnValue")
public final class PolymorphicJsonAdapterFactoryTest {
@Test public void fromJson() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void fromJson() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
assertThat(adapter.fromJson("{\"type\":\"success\",\"value\":\"Okay!\"}"))
@@ -46,12 +49,15 @@ public final class PolymorphicJsonAdapterFactoryTest {
.isEqualTo(new Error(Collections.<String, Object>singletonMap("order", 66d)));
}
@Test public void toJson() {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void toJson() {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
assertThat(adapter.toJson(new Success("Okay!")))
@@ -60,12 +66,15 @@ public final class PolymorphicJsonAdapterFactoryTest {
.isEqualTo("{\"type\":\"error\",\"error_logs\":{\"order\":66}}");
}
@Test public void unregisteredLabelValue() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void unregisteredLabelValue() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
JsonReader reader =
@@ -74,61 +83,74 @@ public final class PolymorphicJsonAdapterFactoryTest {
adapter.fromJson(reader);
fail();
} catch (JsonDataException expected) {
assertThat(expected).hasMessage("Expected one of [success, error] for key 'type' but found"
+ " 'data'. Register a subtype for this label.");
assertThat(expected)
.hasMessage(
"Expected one of [success, error] for key 'type' but found"
+ " 'data'. Register a subtype for this label.");
}
assertThat(reader.peek()).isEqualTo(JsonReader.Token.BEGIN_OBJECT);
}
@Test public void specifiedFallbackSubtype() throws IOException {
@Test
public void specifiedFallbackSubtype() throws IOException {
Error fallbackError = new Error(Collections.<String, Object>emptyMap());
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withDefaultValue(fallbackError))
.build();
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withDefaultValue(fallbackError))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
Message message = adapter.fromJson("{\"type\":\"data\",\"value\":\"Okay!\"}");
assertThat(message).isSameAs(fallbackError);
}
@Test public void specifiedNullFallbackSubtype() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withDefaultValue(null))
.build();
@Test
public void specifiedNullFallbackSubtype() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withDefaultValue(null))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
Message message = adapter.fromJson("{\"type\":\"data\",\"value\":\"Okay!\"}");
assertThat(message).isNull();
}
@Test public void specifiedFallbackJsonAdapter() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withFallbackJsonAdapter(new JsonAdapter<Object>() {
@Override public Object fromJson(JsonReader reader) throws IOException {
reader.beginObject();
assertThat(reader.nextName()).isEqualTo("type");
assertThat(reader.nextString()).isEqualTo("data");
assertThat(reader.nextName()).isEqualTo("value");
assertThat(reader.nextString()).isEqualTo("Okay!");
reader.endObject();
return new EmptyMessage();
}
@Test
public void specifiedFallbackJsonAdapter() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withFallbackJsonAdapter(
new JsonAdapter<Object>() {
@Override
public Object fromJson(JsonReader reader) throws IOException {
reader.beginObject();
assertThat(reader.nextName()).isEqualTo("type");
assertThat(reader.nextString()).isEqualTo("data");
assertThat(reader.nextName()).isEqualTo("value");
assertThat(reader.nextString()).isEqualTo("Okay!");
reader.endObject();
return new EmptyMessage();
}
@Override public void toJson(JsonWriter writer, @Nullable Object value) {
throw new AssertionError();
}
})
)
.build();
@Override
public void toJson(JsonWriter writer, @Nullable Object value) {
throw new AssertionError();
}
}))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
JsonReader reader =
@@ -139,75 +161,95 @@ public final class PolymorphicJsonAdapterFactoryTest {
assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
}
@Test public void unregisteredSubtype() {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void unregisteredSubtype() {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
try {
adapter.toJson(new EmptyMessage());
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Expected one of [class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Success, class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Error] but found"
+ " EmptyMessage, a class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$EmptyMessage. Register"
+ " this subtype.");
assertThat(expected)
.hasMessage(
"Expected one of [class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Success, class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Error] but found"
+ " EmptyMessage, a class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$EmptyMessage. Register"
+ " this subtype.");
}
}
@Test public void unregisteredSubtypeWithDefaultValue() {
@Test
public void unregisteredSubtypeWithDefaultValue() {
Error fallbackError = new Error(Collections.<String, Object>emptyMap());
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withDefaultValue(fallbackError))
.build();
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withDefaultValue(fallbackError))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
try {
adapter.toJson(new EmptyMessage());
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Expected one of [class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Success, class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Error] but found"
+ " EmptyMessage, a class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$EmptyMessage. Register"
+ " this subtype.");
assertThat(expected)
.hasMessage(
"Expected one of [class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Success, class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$Error] but found"
+ " EmptyMessage, a class"
+ " com.squareup.moshi.adapters.PolymorphicJsonAdapterFactoryTest$EmptyMessage. Register"
+ " this subtype.");
}
}
@Test public void unregisteredSubtypeWithFallbackJsonAdapter() {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withFallbackJsonAdapter(new JsonAdapter<Object>() {
@Override public Object fromJson(JsonReader reader) {
throw new RuntimeException("Not implemented as not needed for the test");
}
@Test
public void unregisteredSubtypeWithFallbackJsonAdapter() {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error")
.withFallbackJsonAdapter(
new JsonAdapter<Object>() {
@Override
public Object fromJson(JsonReader reader) {
throw new RuntimeException(
"Not implemented as not needed for the test");
}
@Override public void toJson(JsonWriter writer, Object value) throws IOException {
writer.name("type").value("injected by fallbackJsonAdapter");
}
}))
.build();
@Override
public void toJson(JsonWriter writer, Object value) throws IOException {
writer.name("type").value("injected by fallbackJsonAdapter");
}
}))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
String json = adapter.toJson(new EmptyMessage());
assertThat(json).isEqualTo("{\"type\":\"injected by fallbackJsonAdapter\"}");
}
@Test public void nonStringLabelValue() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void nonStringLabelValue() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
try {
@@ -218,12 +260,15 @@ public final class PolymorphicJsonAdapterFactoryTest {
}
}
@Test public void nonObjectDoesNotConsume() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void nonObjectDoesNotConsume() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
JsonReader reader = JsonReader.of(new Buffer().writeUtf8("\"Failure\""));
@@ -237,13 +282,16 @@ public final class PolymorphicJsonAdapterFactoryTest {
assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
}
@Test public void nonUniqueSubtypes() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Success.class, "data")
.withSubtype(Error.class, "error"))
.build();
@Test
public void nonUniqueSubtypes() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Success.class, "data")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
@@ -257,10 +305,10 @@ public final class PolymorphicJsonAdapterFactoryTest {
.isEqualTo("{\"type\":\"success\",\"value\":\"Data!\"}");
}
@Test public void uniqueLabels() {
@Test
public void uniqueLabels() {
PolymorphicJsonAdapterFactory<Message> factory =
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "data");
PolymorphicJsonAdapterFactory.of(Message.class, "type").withSubtype(Success.class, "data");
try {
factory.withSubtype(Error.class, "data");
fail();
@@ -269,12 +317,15 @@ public final class PolymorphicJsonAdapterFactoryTest {
}
}
@Test public void nullSafe() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
@Test
public void nullSafe() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(Success.class, "success")
.withSubtype(Error.class, "error"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class);
JsonReader reader = JsonReader.of(new Buffer().writeUtf8("null"));
@@ -286,34 +337,40 @@ public final class PolymorphicJsonAdapterFactoryTest {
* 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(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(MessageWithUnportableTypes.class, "unportable"))
.build();
@Test
public void unportableTypes() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.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}");
MessageWithUnportableTypes decoded =
(MessageWithUnportableTypes)
adapter.fromJson("{\"type\":\"unportable\",\"long_value\":9007199254740993}");
assertThat(decoded.long_value).isEqualTo(9007199254740993L);
}
@Test public void failOnUnknownMissingTypeLabel() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(MessageWithType.class, "success"))
.build();
@Test
public void failOnUnknownMissingTypeLabel() throws IOException {
Moshi moshi =
new Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Message.class, "type")
.withSubtype(MessageWithType.class, "success"))
.build();
JsonAdapter<Message> adapter = moshi.adapter(Message.class).failOnUnknown();
MessageWithType decoded = (MessageWithType) adapter.fromJson(
"{\"value\":\"Okay!\",\"type\":\"success\"}");
MessageWithType decoded =
(MessageWithType) adapter.fromJson("{\"value\":\"Okay!\",\"type\":\"success\"}");
assertThat(decoded.value).isEqualTo("Okay!");
}
interface Message {
}
interface Message {}
static final class Success implements Message {
final String value;
@@ -322,14 +379,16 @@ public final class PolymorphicJsonAdapterFactoryTest {
this.value = value;
}
@Override public boolean equals(Object o) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Success)) return false;
Success success = (Success) o;
return value.equals(success.value);
}
@Override public int hashCode() {
@Override
public int hashCode() {
return value.hashCode();
}
}
@@ -341,20 +400,23 @@ public final class PolymorphicJsonAdapterFactoryTest {
this.error_logs = error_logs;
}
@Override public boolean equals(Object o) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Error)) return false;
Error error = (Error) o;
return error_logs.equals(error.error_logs);
}
@Override public int hashCode() {
@Override
public int hashCode() {
return error_logs.hashCode();
}
}
static final class EmptyMessage implements Message {
@Override public String toString() {
@Override
public String toString() {
return "EmptyMessage";
}
}

View File

@@ -15,6 +15,8 @@
*/
package com.squareup.moshi.adapters;
import static org.assertj.core.api.Assertions.assertThat;
import com.squareup.moshi.JsonAdapter;
import java.util.Calendar;
import java.util.Date;
@@ -23,17 +25,17 @@ import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public final class Rfc3339DateJsonAdapterTest {
private final JsonAdapter<Date> adapter = new Rfc3339DateJsonAdapter().lenient();
@Test public void fromJsonWithTwoDigitMillis() throws Exception {
@Test
public void fromJsonWithTwoDigitMillis() throws Exception {
assertThat(adapter.fromJson("\"1985-04-12T23:20:50.52Z\""))
.isEqualTo(newDate(1985, 4, 12, 23, 20, 50, 520, 0));
}
@Test public void fromJson() throws Exception {
@Test
public void fromJson() throws Exception {
assertThat(adapter.fromJson("\"1970-01-01T00:00:00.000Z\""))
.isEqualTo(newDate(1970, 1, 1, 0, 0, 0, 0, 0));
assertThat(adapter.fromJson("\"1985-04-12T23:20:50.520Z\""))
@@ -48,7 +50,8 @@ public final class Rfc3339DateJsonAdapterTest {
.isEqualTo(newDate(1937, 1, 1, 12, 0, 27, 870, 20));
}
@Test public void toJson() throws Exception {
@Test
public void toJson() throws Exception {
assertThat(adapter.toJson(newDate(1970, 1, 1, 0, 0, 0, 0, 0)))
.isEqualTo("\"1970-01-01T00:00:00.000Z\"");
assertThat(adapter.toJson(newDate(1985, 4, 12, 23, 20, 50, 520, 0)))
@@ -63,7 +66,8 @@ public final class Rfc3339DateJsonAdapterTest {
.isEqualTo("\"1937-01-01T11:40:27.870Z\"");
}
@Test public void nullSafety() throws Exception {
@Test
public void nullSafety() throws Exception {
assertThat(adapter.toJson(null)).isEqualTo("null");
assertThat(adapter.fromJson("null")).isNull();
}