diff --git a/CHANGELOG.md b/CHANGELOG.md index dbb40e46f..377f7a328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,22 +52,22 @@ _2019-10-30_ _2019-10-29_ - * **This release requires kotlin-reflect or moshi-kotlin-codegen for all Kotlin classes.** - + * **This release requires kotlin-reflect or moshi-kotlin-codegen for all Kotlin classes.** + Previously Moshi wouldn't differentiate between Kotlin classes and Java classes if Kotlin was not configured. This caused bad runtime behavior such as putting null into non-nullable fields! If you attempt to create an adapter for a Kotlin type, Moshi will throw an `IllegalArgumentException`. - + Fix this with either the reflection adapter: - + ```kotlin val moshi = Moshi.Builder() // ... add your own JsonAdapters and factories ... .add(KotlinJsonAdapterFactory()) .build() ``` - + Or the codegen annotation processor: ```kotlin @@ -77,12 +77,12 @@ _2019-10-29_ val visible_cards: List ) ``` - + The [Kotlin documentation][moshi_kotlin_docs] explains the required build configuration changes. - * New: Change how Moshi's generated adapters call constructors. Previous generated code used a + * New: Change how Moshi's generated adapters call constructors. Previous generated code used a combination of the constructor and `copy()` method to set properties that have default values. - With this update we call the same synthetic constructor that Kotlin uses. This is less surprising + With this update we call the same synthetic constructor that Kotlin uses. This is less surprising though it requires us to generate some tricky code. * New: Make `Rfc3339DateJsonAdapter` null-safe. Previously Moshi would refuse to decode null dates. Restore that behavior by explicitly forbidding nulls with `Rfc3339DateJsonAdapter().nonNull()`. diff --git a/README.md b/README.md index 8b86260a0..4072d42e2 100644 --- a/README.md +++ b/README.md @@ -280,7 +280,7 @@ reflection, Moshi is designed to help you out when things go wrong. JsonDataException: Expected one of [CLUBS, DIAMONDS, HEARTS, SPADES] but was ANCHOR at path $.visible_cards[2].suit at com.squareup.moshi.JsonAdapters$11.fromJson(JsonAdapters.java:188) at com.squareup.moshi.JsonAdapters$11.fromJson(JsonAdapters.java:180) - ... + ... ``` Moshi always throws a standard `java.io.IOException` if there is an error reading the JSON document, diff --git a/adapters/src/main/java/com/squareup/moshi/Rfc3339DateJsonAdapter.java b/adapters/src/main/java/com/squareup/moshi/Rfc3339DateJsonAdapter.java index 6b0086e67..41115a0ce 100644 --- a/adapters/src/main/java/com/squareup/moshi/Rfc3339DateJsonAdapter.java +++ b/adapters/src/main/java/com/squareup/moshi/Rfc3339DateJsonAdapter.java @@ -23,14 +23,16 @@ * The new class is {@code com.squareup.moshi.adapters.Rfc3339DateJsonAdapter}. */ public final class Rfc3339DateJsonAdapter extends JsonAdapter { - 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); } } diff --git a/adapters/src/main/java/com/squareup/moshi/adapters/EnumJsonAdapter.java b/adapters/src/main/java/com/squareup/moshi/adapters/EnumJsonAdapter.java index 59f05d374..0e42925a7 100644 --- a/adapters/src/main/java/com/squareup/moshi/adapters/EnumJsonAdapter.java +++ b/adapters/src/main/java/com/squareup/moshi/adapters/EnumJsonAdapter.java @@ -29,12 +29,11 @@ * 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}: * - *
 {@code
- *
- *   Moshi moshi = new Moshi.Builder()
- *       .add(CurrencyCode.class, EnumJsonAdapter.create(CurrencyCode.class)
- *           .withUnknownFallback(CurrencyCode.USD))
- *       .build();
+ * 
{@code
+ * Moshi moshi = new Moshi.Builder()
+ *     .add(CurrencyCode.class, EnumJsonAdapter.create(CurrencyCode.class)
+ *         .withUnknownFallback(CurrencyCode.USD))
+ *     .build();
  * }
*/ public final class EnumJsonAdapter> extends JsonAdapter { @@ -78,15 +77,21 @@ public EnumJsonAdapter withUnknownFallback(@Nullable T fallbackValue) { } } - @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 EnumJsonAdapter withUnknownFallback(@Nullable T fallbackValue) { 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 EnumJsonAdapter withUnknownFallback(@Nullable T fallbackValue) { writer.value(nameStrings[value.ordinal()]); } - @Override public String toString() { + @Override + public String toString() { return "EnumJsonAdapter(" + enumType.getName() + ")"; } } diff --git a/adapters/src/main/java/com/squareup/moshi/adapters/Iso8601Utils.java b/adapters/src/main/java/com/squareup/moshi/adapters/Iso8601Utils.java index b7d395266..43ee6a1ff 100644 --- a/adapters/src/main/java/com/squareup/moshi/adapters/Iso8601Utils.java +++ b/adapters/src/main/java/com/squareup/moshi/adapters/Iso8601Utils.java @@ -26,11 +26,12 @@ * Jackson’s 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 + *

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]] + *

Supported parse format: + * [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:]mm]] * * @see this specification */ @@ -167,8 +168,11 @@ public static Date parse(String date) { */ 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 @@ private static void padInt(StringBuilder buffer, int value, int length) { } /** - * 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++) { diff --git a/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java b/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java index 712d09189..adc4d232f 100644 --- a/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java +++ b/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java @@ -38,50 +38,47 @@ * *

Suppose we have an interface, its implementations, and a class that uses them: * - *

 {@code
+ * 
{@code
+ * interface HandOfCards {
+ * }
  *
- *   interface HandOfCards {
- *   }
+ * class BlackjackHand implements HandOfCards {
+ *   Card hidden_card;
+ *   List visible_cards;
+ * }
  *
- *   class BlackjackHand implements HandOfCards {
- *     Card hidden_card;
- *     List visible_cards;
- *   }
+ * class HoldemHand implements HandOfCards {
+ *   Set hidden_cards;
+ * }
  *
- *   class HoldemHand implements HandOfCards {
- *     Set hidden_cards;
- *   }
- *
- *   class Player {
- *     String name;
- *     HandOfCards hand;
- *   }
+ * class Player {
+ *   String name;
+ *   HandOfCards hand;
+ * }
  * }
* *

We want to decode the following JSON into the player model above: * - *

 {@code
- *
- *   {
- *     "name": "Jesse",
- *     "hand": {
- *       "hand_type": "blackjack",
- *       "hidden_card": "9D",
- *       "visible_cards": ["8H", "4C"]
- *     }
+ * 
{@code
+ * {
+ *   "name": "Jesse",
+ *   "hand": {
+ *     "hand_type": "blackjack",
+ *     "hidden_card": "9D",
+ *     "visible_cards": ["8H", "4C"]
  *   }
+ * }
  * }
* *

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: * - *

 {@code
- *
- *   Moshi moshi = new Moshi.Builder()
- *       .add(PolymorphicJsonAdapterFactory.of(HandOfCards.class, "hand_type")
- *           .withSubtype(BlackjackHand.class, "blackjack")
- *           .withSubtype(HoldemHand.class, "holdem"))
- *       .build();
+ * 
{@code
+ * Moshi moshi = new Moshi.Builder()
+ *     .add(PolymorphicJsonAdapterFactory.of(HandOfCards.class, "hand_type")
+ *         .withSubtype(BlackjackHand.class, "blackjack")
+ *         .withSubtype(HoldemHand.class, "holdem"))
+ *     .build();
  * }
* *

This class imposes strict requirements on its use: @@ -95,23 +92,25 @@ *

  • Each type identifier must be unique. * * - *

    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. + *

    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. * *

    If an unknown subtype is encountered when decoding: - *

      - *
    • If {@link #withDefaultValue(Object)} is used, then {@code defaultValue} will be returned. - *
    • If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the - * {@code fallbackJsonAdapter.fromJson(reader)} result will be returned. - *
    • Otherwise a {@link JsonDataException} will be thrown. - *
    + * + *
      + *
    • If {@link #withDefaultValue(Object)} is used, then {@code defaultValue} will be returned. + *
    • If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the {@code + * fallbackJsonAdapter.fromJson(reader)} result will be returned. + *
    • Otherwise a {@link JsonDataException} will be thrown. + *
    * *

    If an unknown type is encountered when encoding: - *

      - *
    • If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the - * {@code fallbackJsonAdapter.toJson(writer, value)} result will be returned. - *
    • Otherwise a {@link IllegalArgumentException} will be thrown. - *
    + * + *
      + *
    • If {@link #withFallbackJsonAdapter(JsonAdapter)} is used, then the {@code + * fallbackJsonAdapter.toJson(writer, value)} result will be returned. + *
    • Otherwise a {@link IllegalArgumentException} will be thrown. + *
    * *

    If the same subtype has multiple labels the first one is used when encoding. */ @@ -145,16 +144,10 @@ public static PolymorphicJsonAdapterFactory of(Class baseType, String if (baseType == null) throw new NullPointerException("baseType == null"); if (labelKey == null) throw new NullPointerException("labelKey == null"); return new PolymorphicJsonAdapterFactory<>( - baseType, - labelKey, - Collections.emptyList(), - Collections.emptyList(), - null); + baseType, labelKey, Collections.emptyList(), Collections.emptyList(), null); } - /** - * Returns a new factory that decodes instances of {@code subtype}. - */ + /** Returns a new factory that decodes instances of {@code subtype}. */ public PolymorphicJsonAdapterFactory withSubtype(Class subtype, String label) { if (subtype == null) throw new NullPointerException("subtype == null"); if (label == null) throw new NullPointerException("label == null"); @@ -165,27 +158,21 @@ public PolymorphicJsonAdapterFactory withSubtype(Class subtype, newLabels.add(label); List 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. * *

    The {@link JsonReader} instance will not be automatically consumed, so sure to consume it * within your implementation of {@link JsonAdapter#fromJson(JsonReader)} */ public PolymorphicJsonAdapterFactory withFallbackJsonAdapter( @Nullable JsonAdapter fallbackJsonAdapter) { - return new PolymorphicJsonAdapterFactory<>(baseType, - labelKey, - labels, - subtypes, - fallbackJsonAdapter); + return new PolymorphicJsonAdapterFactory<>( + baseType, labelKey, labels, subtypes, fallbackJsonAdapter); } /** @@ -198,14 +185,22 @@ public PolymorphicJsonAdapterFactory withDefaultValue(@Nullable T defaultValu private JsonAdapter buildFallbackJsonAdapter(final T defaultValue) { return new JsonAdapter() { - @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 JsonAdapter create(Type type, Set annotations, M 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 { @@ -241,7 +232,8 @@ static final class PolymorphicJsonAdapter extends JsonAdapter { /** Corresponds to subtypes. */ final JsonReader.Options labelOptions; - PolymorphicJsonAdapter(String labelKey, + PolymorphicJsonAdapter( + String labelKey, List labels, List subtypes, List> jsonAdapters, @@ -256,7 +248,8 @@ static final class PolymorphicJsonAdapter extends JsonAdapter { 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 @@ private int labelIndex(JsonReader reader) throws IOException { 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 @@ private int labelIndex(JsonReader reader) throws IOException { 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 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 @@ private int labelIndex(JsonReader reader) throws IOException { writer.endObject(); } - @Override public String toString() { + @Override + public String toString() { return "PolymorphicJsonAdapter(" + labelKey + ")"; } } diff --git a/adapters/src/main/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapter.java b/adapters/src/main/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapter.java index b09662775..1030bdf13 100644 --- a/adapters/src/main/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapter.java +++ b/adapters/src/main/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapter.java @@ -26,15 +26,15 @@ * 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}: * - *
     {@code
    - *
    - *   Moshi moshi = new Moshi.Builder()
    - *       .add(Date.class, new Rfc3339DateJsonAdapter())
    - *       .build();
    + * 
    {@code
    + * Moshi moshi = new Moshi.Builder()
    + *     .add(Date.class, new Rfc3339DateJsonAdapter())
    + *     .build();
      * }
    */ public final class Rfc3339DateJsonAdapter extends JsonAdapter { - @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 { 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 { diff --git a/adapters/src/test/java/com/squareup/moshi/adapters/EnumJsonAdapterTest.java b/adapters/src/test/java/com/squareup/moshi/adapters/EnumJsonAdapterTest.java index 99b0b6d57..cb69167ab 100644 --- a/adapters/src/test/java/com/squareup/moshi/adapters/EnumJsonAdapterTest.java +++ b/adapters/src/test/java/com/squareup/moshi/adapters/EnumJsonAdapterTest.java @@ -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 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 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 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 adapter = EnumJsonAdapter.create(Roshambo.class) - .withUnknownFallback(Roshambo.ROCK); + @Test + public void withFallbackValue() throws Exception { + EnumJsonAdapter 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 adapter = EnumJsonAdapter.create(Roshambo.class) - .withUnknownFallback(null); + @Test + public void withNullFallbackValue() throws Exception { + EnumJsonAdapter 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 } } diff --git a/adapters/src/test/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactoryTest.java b/adapters/src/test/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactoryTest.java index e8745bb03..b949d7255 100644 --- a/adapters/src/test/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactoryTest.java +++ b/adapters/src/test/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactoryTest.java @@ -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 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 adapter = moshi.adapter(Message.class); assertThat(adapter.fromJson("{\"type\":\"success\",\"value\":\"Okay!\"}")) @@ -46,12 +49,15 @@ public final class PolymorphicJsonAdapterFactoryTest { .isEqualTo(new Error(Collections.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 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 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.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 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 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() { - @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(); + @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() { + @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(); JsonAdapter 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 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.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 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() { - @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(); + @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() { + @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(); JsonAdapter 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 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 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 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 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 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 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 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 @@ static final class Success implements Message { 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 @@ static final class Error implements Message { 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"; } } diff --git a/adapters/src/test/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapterTest.java b/adapters/src/test/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapterTest.java index 5961a088a..ae225fc26 100644 --- a/adapters/src/test/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapterTest.java +++ b/adapters/src/test/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapterTest.java @@ -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.concurrent.TimeUnit; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; - public final class Rfc3339DateJsonAdapterTest { private final JsonAdapter 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(); } diff --git a/build.gradle.kts b/build.gradle.kts index 62bdffbba..b45ba4ff3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import com.vanniktech.maven.publish.MavenPublishPluginExtension import org.gradle.jvm.tasks.Jar @@ -25,6 +26,40 @@ buildscript { plugins { id("com.vanniktech.maven.publish") version "0.11.1" apply false id("org.jetbrains.dokka") version "0.10.1" apply false + id("com.diffplug.spotless") version "5.2.0" +} + +spotless { + format("misc") { + target("*.md", ".gitignore") + trimTrailingWhitespace() + indentWithSpaces(2) + endWithNewline() + } + java { + googleJavaFormat("1.7") + target("**/*.java") + targetExclude("**/spotless.java") + // https://github.com/diffplug/spotless/issues/677 +// licenseHeaderFile("spotless/spotless.java") + } + kotlin { + ktlint(Dependencies.ktlintVersion).userData(mapOf("indent_size" to "2")) + target("**/*.kt") + trimTrailingWhitespace() + endWithNewline() + // https://github.com/diffplug/spotless/issues/677 +// licenseHeaderFile("spotless/spotless.kt") +// .updateYearWithLatest(false) +// targetExclude("**/Dependencies.kt", "**/spotless.kt") + } + kotlinGradle { + ktlint(Dependencies.ktlintVersion).userData(mapOf("indent_size" to "2")) + target("**/*.gradle.kts") + trimTrailingWhitespace() + endWithNewline() + licenseHeaderFile("spotless/spotless.kts", "(import|plugins|buildscript|dependencies|pluginManagement)") + } } subprojects { @@ -44,15 +79,6 @@ subprojects { } } -// apply(plugin = "checkstyle") -// configure { -// toolVersion = "8.28" -// configFile = rootProject.file("checkstyle.xml") -// } -// tasks.withType().configureEach { -// exclude("**/Iso8601Utils.java") -// } - pluginManager.withPlugin("java-library") { configure { sourceCompatibility = JavaVersion.VERSION_1_7 @@ -72,7 +98,7 @@ subprojects { // Configure automatic-module-name, but only for published modules @Suppress("UnstableApiUsage") val automaticModuleName = providers.gradleProperty("AUTOMATIC_MODULE_NAME") - .forUseAtConfigurationTime() + .forUseAtConfigurationTime() if (automaticModuleName.isPresent) { val name = automaticModuleName.get() tasks.withType().configureEach { diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 2b065d0fe..60c4d0edb 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -18,6 +18,7 @@ object Dependencies { const val asm = "org.ow2.asm:asm:7.1" const val jsr305 = "com.google.code.findbugs:jsr305:3.0.2" + const val ktlintVersion = "0.38.0" const val okio = "com.squareup.okio:okio:1.16.0" const val okio2 = "com.squareup.okio:okio:2.1.0" @@ -52,4 +53,4 @@ object Dependencies { const val junit = "junit:junit:4.12" const val truth = "com.google.truth:truth:1.0" } -} \ No newline at end of file +} diff --git a/examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java b/examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java index 895d9fe8e..6ef500124 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java @@ -26,9 +26,7 @@ public final class ByteStrings { public void run() throws Exception { String json = "\"TW9zaGksIE9saXZlLCBXaGl0ZSBDaGluPw\""; - Moshi moshi = new Moshi.Builder() - .add(ByteString.class, new Base64ByteStringAdapter()) - .build(); + Moshi moshi = new Moshi.Builder().add(ByteString.class, new Base64ByteStringAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(ByteString.class); ByteString byteString = jsonAdapter.fromJson(json); @@ -40,12 +38,14 @@ public void run() throws Exception { * breaks or whitespace is included in the encoded form. */ public final class Base64ByteStringAdapter extends JsonAdapter { - @Override public ByteString fromJson(JsonReader reader) throws IOException { + @Override + public ByteString fromJson(JsonReader reader) throws IOException { String base64 = reader.nextString(); return ByteString.decodeBase64(base64); } - @Override public void toJson(JsonWriter writer, ByteString value) throws IOException { + @Override + public void toJson(JsonWriter writer, ByteString value) throws IOException { String string = value.base64(); writer.value(string); } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java b/examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java index ff8a573d6..307a9d224 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java @@ -22,20 +22,27 @@ import com.squareup.moshi.recipes.models.Suit; public final class CardAdapter { - @ToJson String toJson(Card card) { + @ToJson + String toJson(Card card) { return card.rank + card.suit.name().substring(0, 1); } - @FromJson Card fromJson(String card) { + @FromJson + Card fromJson(String card) { if (card.length() != 2) throw new JsonDataException("Unknown card: " + card); char rank = card.charAt(0); switch (card.charAt(1)) { - case 'C': return new Card(rank, Suit.CLUBS); - case 'D': return new Card(rank, Suit.DIAMONDS); - case 'H': return new Card(rank, Suit.HEARTS); - case 'S': return new Card(rank, Suit.SPADES); - default: throw new JsonDataException("unknown suit: " + card); + case 'C': + return new Card(rank, Suit.CLUBS); + case 'D': + return new Card(rank, Suit.DIAMONDS); + case 'H': + return new Card(rank, Suit.HEARTS); + case 'S': + return new Card(rank, Suit.SPADES); + default: + throw new JsonDataException("unknown suit: " + card); } } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java b/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java index 69bb77717..145d41505 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java @@ -31,11 +31,9 @@ public final class CustomAdapterFactory { public void run() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new SortedSetAdapterFactory()) - .build(); - JsonAdapter> jsonAdapter = moshi.adapter( - Types.newParameterizedType(SortedSet.class, String.class)); + Moshi moshi = new Moshi.Builder().add(new SortedSetAdapterFactory()).build(); + JsonAdapter> jsonAdapter = + moshi.adapter(Types.newParameterizedType(SortedSet.class, String.class)); TreeSet model = new TreeSet<>(); model.add("a"); @@ -48,9 +46,9 @@ public void run() throws Exception { /** * This class composes an adapter for any element type into an adapter for a sorted set of those - * elements. For example, given a {@code JsonAdapter}, use this to get a - * {@code JsonAdapter>}. It works by looping over the input elements when - * both reading and writing. + * elements. For example, given a {@code JsonAdapter}, use this to get a {@code + * JsonAdapter>}. It works by looping over the input elements when both + * reading and writing. */ static final class SortedSetAdapter extends JsonAdapter> { private final JsonAdapter elementAdapter; @@ -59,7 +57,8 @@ static final class SortedSetAdapter extends JsonAdapter> { this.elementAdapter = elementAdapter; } - @Override public SortedSet fromJson(JsonReader reader) throws IOException { + @Override + public SortedSet fromJson(JsonReader reader) throws IOException { TreeSet result = new TreeSet<>(); reader.beginArray(); while (reader.hasNext()) { @@ -69,7 +68,8 @@ static final class SortedSetAdapter extends JsonAdapter> { return result; } - @Override public void toJson(JsonWriter writer, SortedSet set) throws IOException { + @Override + public void toJson(JsonWriter writer, SortedSet set) throws IOException { writer.beginArray(); for (T element : set) { elementAdapter.toJson(writer, element); @@ -85,7 +85,8 @@ static final class SortedSetAdapter extends JsonAdapter> { * uses that to create an adapter for the set. */ static class SortedSetAdapterFactory implements JsonAdapter.Factory { - @Override public @Nullable JsonAdapter create( + @Override + public @Nullable JsonAdapter create( Type type, Set annotations, Moshi moshi) { if (!annotations.isEmpty()) { return null; // Annotations? This factory doesn't apply. diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java b/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java index 2ab904686..dbd2143ec 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java @@ -15,15 +15,13 @@ */ package com.squareup.moshi.recipes; - import com.squareup.moshi.FromJson; import com.squareup.moshi.Json; import com.squareup.moshi.JsonAdapter; -import com.squareup.moshi.Moshi; import com.squareup.moshi.JsonReader; - -import javax.annotation.Nullable; +import com.squareup.moshi.Moshi; import java.io.IOException; +import javax.annotation.Nullable; public final class CustomAdapterWithDelegate { public void run() throws Exception { @@ -42,10 +40,14 @@ public static void main(String[] args) throws Exception { } private enum Stage { - @Json(name = "not-started") NOT_STARTED, - @Json(name = "in-progress") IN_PROGRESS, - @Json(name = "rejected") REJECTED, - @Json(name = "completed") COMPLETED + @Json(name = "not-started") + NOT_STARTED, + @Json(name = "in-progress") + IN_PROGRESS, + @Json(name = "rejected") + REJECTED, + @Json(name = "completed") + COMPLETED } private static final class StageAdapter { diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java b/examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java index d6ea8cd84..510693f5e 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java @@ -21,11 +21,7 @@ public final class CustomFieldName { public void run() throws Exception { - String json = "" - + "{" - + " \"username\": \"jesse\"," - + " \"lucky number\": 32" - + "}\n"; + String json = "" + "{" + " \"username\": \"jesse\"," + " \"lucky number\": 32" + "}\n"; Moshi moshi = new Moshi.Builder().build(); JsonAdapter jsonAdapter = moshi.adapter(Player.class); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java b/examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java index 20e79a7a4..cd9a076cd 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi.recipes; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import com.squareup.moshi.FromJson; import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.JsonQualifier; @@ -22,20 +24,17 @@ import com.squareup.moshi.ToJson; import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - public final class CustomQualifier { public void run() throws Exception { - String json = "" - + "{\n" - + " \"color\": \"#ff0000\",\n" - + " \"height\": 768,\n" - + " \"width\": 1024\n" - + "}\n"; + String json = + "" + + "{\n" + + " \"color\": \"#ff0000\",\n" + + " \"height\": 768,\n" + + " \"width\": 1024\n" + + "}\n"; - Moshi moshi = new Moshi.Builder() - .add(new ColorAdapter()) - .build(); + Moshi moshi = new Moshi.Builder().add(new ColorAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(Rectangle.class); Rectangle rectangle = jsonAdapter.fromJson(json); @@ -51,22 +50,25 @@ static class Rectangle { int height; @HexColor int color; - @Override public String toString() { + @Override + public String toString() { return String.format("%dx%d #%06x", width, height, color); } } @Retention(RUNTIME) @JsonQualifier - public @interface HexColor { - } + public @interface HexColor {} static class ColorAdapter { - @ToJson String toJson(@HexColor int rgb) { + @ToJson + String toJson(@HexColor int rgb) { return String.format("#%06x", rgb); } - @FromJson @HexColor int fromJson(String rgb) { + @FromJson + @HexColor + int fromJson(String rgb) { return Integer.parseInt(rgb.substring(1), 16); } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java b/examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java index 3424d2257..410e03f26 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java @@ -21,18 +21,17 @@ public final class CustomTypeAdapter { public void run() throws Exception { - String json = "" - + "{\n" - + " \"hidden_card\": \"6S\",\n" - + " \"visible_cards\": [\n" - + " \"4C\",\n" - + " \"AH\"\n" - + " ]\n" - + "}\n"; + String json = + "" + + "{\n" + + " \"hidden_card\": \"6S\",\n" + + " \"visible_cards\": [\n" + + " \"4C\",\n" + + " \"AH\"\n" + + " ]\n" + + "}\n"; - Moshi moshi = new Moshi.Builder() - .add(new CardAdapter()) - .build(); + Moshi moshi = new Moshi.Builder().add(new CardAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(BlackjackHand.class); BlackjackHand blackjackHand = jsonAdapter.fromJson(json); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java b/examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java index 9a2e9fbae..28e2d3f10 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java @@ -35,7 +35,8 @@ private DefaultOnDataMismatchAdapter(JsonAdapter delegate, T defaultValue) { this.defaultValue = defaultValue; } - @Override public T fromJson(JsonReader reader) throws IOException { + @Override + public T fromJson(JsonReader reader) throws IOException { // Use a peeked reader to leave the reader in a known state even if there's an exception. JsonReader peeked = reader.peekJson(); T result; @@ -52,13 +53,15 @@ private DefaultOnDataMismatchAdapter(JsonAdapter delegate, T defaultValue) { return result; } - @Override public void toJson(JsonWriter writer, T value) throws IOException { + @Override + public void toJson(JsonWriter writer, T value) throws IOException { delegate.toJson(writer, value); } public static Factory newFactory(final Class type, final T defaultValue) { return new Factory() { - @Override public @Nullable JsonAdapter create( + @Override + public @Nullable JsonAdapter create( Type requestedType, Set annotations, Moshi moshi) { if (type != requestedType) return null; JsonAdapter delegate = moshi.nextAdapter(this, type, annotations); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java b/examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java index 3ff435e49..f7c74c7f7 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi.recipes; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import com.squareup.moshi.Json; import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.JsonQualifier; @@ -29,38 +31,38 @@ import java.util.Set; import javax.annotation.Nullable; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - final class FallbackEnum { @Retention(RUNTIME) @JsonQualifier public @interface Fallback { - /** - * The enum name. - */ + /** The enum name. */ String value(); } public static final class FallbackEnumJsonAdapter> extends JsonAdapter { - public static final Factory FACTORY = new Factory() { - @Nullable @Override @SuppressWarnings("unchecked") - public JsonAdapter create(Type type, Set annotations, Moshi moshi) { - Class rawType = Types.getRawType(type); - if (!rawType.isEnum()) { - return null; - } - if (annotations.size() != 1) { - return null; - } - Annotation annotation = annotations.iterator().next(); - if (!(annotation instanceof Fallback)) { - return null; - } - Class enumType = (Class) rawType; - Enum fallback = Enum.valueOf(enumType, ((Fallback) annotation).value()); - return new FallbackEnumJsonAdapter<>(enumType, fallback); - } - }; + public static final Factory FACTORY = + new Factory() { + @Nullable + @Override + @SuppressWarnings("unchecked") + public JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + Class rawType = Types.getRawType(type); + if (!rawType.isEnum()) { + return null; + } + if (annotations.size() != 1) { + return null; + } + Annotation annotation = annotations.iterator().next(); + if (!(annotation instanceof Fallback)) { + return null; + } + Class enumType = (Class) rawType; + Enum fallback = Enum.valueOf(enumType, ((Fallback) annotation).value()); + return new FallbackEnumJsonAdapter<>(enumType, fallback); + } + }; final Class enumType; final String[] nameStrings; @@ -86,46 +88,51 @@ public JsonAdapter create(Type type, Set annotations, M } } - @Override public T fromJson(JsonReader reader) throws IOException { + @Override + public T fromJson(JsonReader reader) throws IOException { int index = reader.selectString(options); if (index != -1) return constants[index]; reader.nextString(); return defaultValue; } - @Override public void toJson(JsonWriter writer, T value) throws IOException { + @Override + public void toJson(JsonWriter writer, T value) throws IOException { writer.value(nameStrings[value.ordinal()]); } - @Override public String toString() { + @Override + public String toString() { return "JsonAdapter(" + enumType.getName() + ").defaultValue( " + defaultValue + ")"; } } static final class Example { enum Transportation { - WALKING, BIKING, TRAINS, PLANES + WALKING, + BIKING, + TRAINS, + PLANES } - @Fallback("WALKING") final Transportation transportation; + @Fallback("WALKING") + final Transportation transportation; Example(Transportation transportation) { this.transportation = transportation; } - @Override public String toString() { + @Override + public String toString() { return transportation.toString(); } } public static void main(String[] args) throws Exception { - Moshi moshi = new Moshi.Builder() - .add(FallbackEnumJsonAdapter.FACTORY) - .build(); + Moshi moshi = new Moshi.Builder().add(FallbackEnumJsonAdapter.FACTORY).build(); JsonAdapter adapter = moshi.adapter(Example.class); System.out.println(adapter.fromJson("{\"transportation\":\"CARS\"}")); } - private FallbackEnum() { - } + private FallbackEnum() {} } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java b/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java index cdb6f56ab..1241477f5 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java @@ -25,12 +25,13 @@ public void run() throws Exception { // For some reason our JSON has date and time as separate fields. We will clean that up during // parsing: Moshi will first parse the JSON directly to an EventJson and from that the // EventJsonAdapter will create the actual Event. - String json = "" - + "{\n" - + " \"title\": \"Blackjack tournament\",\n" - + " \"begin_date\": \"20151010\",\n" - + " \"begin_time\": \"17:04\"\n" - + "}\n"; + String json = + "" + + "{\n" + + " \"title\": \"Blackjack tournament\",\n" + + " \"begin_date\": \"20151010\",\n" + + " \"begin_time\": \"17:04\"\n" + + "}\n"; Moshi moshi = new Moshi.Builder().add(new EventJsonAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(Event.class); @@ -55,23 +56,30 @@ public static final class Event { String title; String beginDateAndTime; - @Override public String toString() { + @Override + public String toString() { return "Event{" - + "title='" + title + '\'' - + ", beginDateAndTime='" + beginDateAndTime + '\'' + + "title='" + + title + + '\'' + + ", beginDateAndTime='" + + beginDateAndTime + + '\'' + '}'; } } private static final class EventJsonAdapter { - @FromJson Event eventFromJson(EventJson eventJson) { + @FromJson + Event eventFromJson(EventJson eventJson) { Event event = new Event(); event.title = eventJson.title; event.beginDateAndTime = eventJson.begin_date + " " + eventJson.begin_time; return event; } - @ToJson EventJson eventToJson(Event event) { + @ToJson + EventJson eventToJson(Event event) { EventJson json = new EventJson(); json.title = event.title; json.begin_date = event.beginDateAndTime.substring(0, 8); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java b/examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java index 9162620af..2e5035d11 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java @@ -31,10 +31,11 @@ public final class MultipleFormats { public void run() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new MultipleFormatsCardAdapter()) - .add(new CardStringAdapter()) - .build(); + Moshi moshi = + new Moshi.Builder() + .add(new MultipleFormatsCardAdapter()) + .add(new CardStringAdapter()) + .build(); JsonAdapter cardAdapter = moshi.adapter(Card.class); @@ -48,13 +49,18 @@ public void run() throws Exception { /** Handles cards either as strings "5D" or as objects {"suit": "SPADES", "rank": 5}. */ public final class MultipleFormatsCardAdapter { - @ToJson void toJson(JsonWriter writer, Card value, - @CardString JsonAdapter stringAdapter) throws IOException { + @ToJson + void toJson(JsonWriter writer, Card value, @CardString JsonAdapter stringAdapter) + throws IOException { stringAdapter.toJson(writer, value); } - @FromJson Card fromJson(JsonReader reader, @CardString JsonAdapter stringAdapter, - JsonAdapter defaultAdapter) throws IOException { + @FromJson + Card fromJson( + JsonReader reader, + @CardString JsonAdapter stringAdapter, + JsonAdapter defaultAdapter) + throws IOException { if (reader.peek() == JsonReader.Token.STRING) { return stringAdapter.fromJson(reader); } else { @@ -65,28 +71,35 @@ public final class MultipleFormatsCardAdapter { /** Handles cards as strings only. */ public final class CardStringAdapter { - @ToJson String toJson(@CardString Card card) { + @ToJson + String toJson(@CardString Card card) { return card.rank + card.suit.name().substring(0, 1); } - @FromJson @CardString Card fromJson(String card) { + @FromJson + @CardString + Card fromJson(String card) { if (card.length() != 2) throw new JsonDataException("Unknown card: " + card); char rank = card.charAt(0); switch (card.charAt(1)) { - case 'C': return new Card(rank, Suit.CLUBS); - case 'D': return new Card(rank, Suit.DIAMONDS); - case 'H': return new Card(rank, Suit.HEARTS); - case 'S': return new Card(rank, Suit.SPADES); - default: throw new JsonDataException("unknown suit: " + card); + case 'C': + return new Card(rank, Suit.CLUBS); + case 'D': + return new Card(rank, Suit.DIAMONDS); + case 'H': + return new Card(rank, Suit.HEARTS); + case 'S': + return new Card(rank, Suit.SPADES); + default: + throw new JsonDataException("unknown suit: " + card); } } } @Retention(RetentionPolicy.RUNTIME) @JsonQualifier - @interface CardString { - } + @interface CardString {} public static void main(String[] args) throws Exception { new MultipleFormats().run(); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java b/examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java index 101a00ead..a6ae27135 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java @@ -27,23 +27,22 @@ public final class ReadAndWriteRfc3339Dates { public void run() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(Date.class, new Rfc3339DateJsonAdapter()) - .build(); + Moshi moshi = new Moshi.Builder().add(Date.class, new Rfc3339DateJsonAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(Tournament.class); // The RFC3339 JSON adapter can read dates with a timezone offset like '-05:00'. - String lastTournament = "" - + "{" - + " \"location\":\"Chainsaw\"," - + " \"name\":\"21 for 21\"," - + " \"start\":\"2015-09-01T20:00:00-05:00\"" - + "}"; + String lastTournament = + "" + + "{" + + " \"location\":\"Chainsaw\"," + + " \"name\":\"21 for 21\"," + + " \"start\":\"2015-09-01T20:00:00-05:00\"" + + "}"; System.out.println("Last tournament: " + jsonAdapter.fromJson(lastTournament)); // The RFC3339 JSON adapter always writes dates with UTC, using a 'Z' suffix. - Tournament nextTournament = new Tournament( - "Waterloo Classic", "Bauer Kitchen", newDate(2015, 10, 1, 20, -5)); + Tournament nextTournament = + new Tournament("Waterloo Classic", "Bauer Kitchen", newDate(2015, 10, 1, 20, -5)); System.out.println("Next tournament JSON: " + jsonAdapter.toJson(nextTournament)); } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java b/examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java index 047d7d8d2..c81a60653 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java @@ -21,23 +21,24 @@ public final class ReadJson { public void run() throws Exception { - String json = "" - + "{\n" - + " \"hidden_card\": {\n" - + " \"rank\": \"6\",\n" - + " \"suit\": \"SPADES\"\n" - + " },\n" - + " \"visible_cards\": [\n" - + " {\n" - + " \"rank\": \"4\",\n" - + " \"suit\": \"CLUBS\"\n" - + " },\n" - + " {\n" - + " \"rank\": \"A\",\n" - + " \"suit\": \"HEARTS\"\n" - + " }\n" - + " ]\n" - + "}\n"; + String json = + "" + + "{\n" + + " \"hidden_card\": {\n" + + " \"rank\": \"6\",\n" + + " \"suit\": \"SPADES\"\n" + + " },\n" + + " \"visible_cards\": [\n" + + " {\n" + + " \"rank\": \"4\",\n" + + " \"suit\": \"CLUBS\"\n" + + " },\n" + + " {\n" + + " \"rank\": \"A\",\n" + + " \"suit\": \"HEARTS\"\n" + + " }\n" + + " ]\n" + + "}\n"; Moshi moshi = new Moshi.Builder().build(); JsonAdapter jsonAdapter = moshi.adapter(BlackjackHand.class); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java b/examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java index 0919f8c1a..4d3717e50 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java @@ -24,21 +24,22 @@ public final class ReadJsonList { public void run() throws Exception { - String json = "" - + "[\n" - + " {\n" - + " \"rank\": \"4\",\n" - + " \"suit\": \"CLUBS\"\n" - + " },\n" - + " {\n" - + " \"rank\": \"A\",\n" - + " \"suit\": \"HEARTS\"\n" - + " },\n" - + " {\n" - + " \"rank\": \"J\",\n" - + " \"suit\": \"SPADES\"\n" - + " }\n" - + "]"; + String json = + "" + + "[\n" + + " {\n" + + " \"rank\": \"4\",\n" + + " \"suit\": \"CLUBS\"\n" + + " },\n" + + " {\n" + + " \"rank\": \"A\",\n" + + " \"suit\": \"HEARTS\"\n" + + " },\n" + + " {\n" + + " \"rank\": \"J\",\n" + + " \"suit\": \"SPADES\"\n" + + " }\n" + + "]"; Moshi moshi = new Moshi.Builder().build(); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java b/examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java index ad5d805b8..9d4bc390b 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java @@ -25,11 +25,12 @@ public final class RecoverFromTypeMismatch { public void run() throws Exception { String json = "[\"DIAMONDS\", \"STARS\", \"HEARTS\"]"; - Moshi moshi = new Moshi.Builder() - .add(DefaultOnDataMismatchAdapter.newFactory(Suit.class, Suit.CLUBS)) - .build(); - JsonAdapter> jsonAdapter = moshi.adapter( - Types.newParameterizedType(List.class, Suit.class)); + Moshi moshi = + new Moshi.Builder() + .add(DefaultOnDataMismatchAdapter.newFactory(Suit.class, Suit.CLUBS)) + .build(); + JsonAdapter> jsonAdapter = + moshi.adapter(Types.newParameterizedType(List.class, Suit.class)); List suits = jsonAdapter.fromJson(json); System.out.println(suits); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java b/examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java index 6f1f108a1..71da11272 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi.recipes; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.JsonQualifier; import com.squareup.moshi.JsonReader; @@ -30,20 +32,18 @@ import java.util.Set; import javax.annotation.Nullable; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - final class Unwrap { - private Unwrap() { - } + private Unwrap() {} public static void main(String[] args) throws Exception { - String json = "" - + "{\"data\":" - + " {\n" - + " \"rank\": \"4\",\n" - + " \"suit\": \"CLUBS\"\n" - + " }" - + "}"; + String json = + "" + + "{\"data\":" + + " {\n" + + " \"rank\": \"4\",\n" + + " \"suit\": \"CLUBS\"\n" + + " }" + + "}"; Moshi moshi = new Moshi.Builder().add(EnvelopeJsonAdapter.FACTORY).build(); JsonAdapter adapter = moshi.adapter(Card.class, Enveloped.class); Card out = adapter.fromJson(json); @@ -51,23 +51,28 @@ public static void main(String[] args) throws Exception { } public static final class EnvelopeJsonAdapter extends JsonAdapter { - public static final JsonAdapter.Factory FACTORY = new Factory() { - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - Set delegateAnnotations = - Types.nextAnnotations(annotations, Enveloped.class); - if (delegateAnnotations == null) { - return null; - } - Type envelope = - Types.newParameterizedTypeWithOwner(EnvelopeJsonAdapter.class, Envelope.class, type); - JsonAdapter> delegate = moshi.nextAdapter(this, envelope, delegateAnnotations); - return new EnvelopeJsonAdapter(delegate); - } - }; + public static final JsonAdapter.Factory FACTORY = + new Factory() { + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + Set delegateAnnotations = + Types.nextAnnotations(annotations, Enveloped.class); + if (delegateAnnotations == null) { + return null; + } + Type envelope = + Types.newParameterizedTypeWithOwner( + EnvelopeJsonAdapter.class, Envelope.class, type); + JsonAdapter> delegate = + moshi.nextAdapter(this, envelope, delegateAnnotations); + return new EnvelopeJsonAdapter(delegate); + } + }; - @Retention(RUNTIME) @JsonQualifier public @interface Enveloped { - } + @Retention(RUNTIME) + @JsonQualifier + public @interface Enveloped {} private static final class Envelope { final T data; @@ -83,11 +88,13 @@ private static final class Envelope { this.delegate = delegate; } - @Override public Object fromJson(JsonReader reader) throws IOException { + @Override + public Object fromJson(JsonReader reader) throws IOException { return delegate.fromJson(reader).data; } - @Override public void toJson(JsonWriter writer, Object value) throws IOException { + @Override + public void toJson(JsonWriter writer, Object value) throws IOException { delegate.toJson(writer, new Envelope<>(value)); } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java b/examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java index f182d0c7e..5eee17db8 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java @@ -15,21 +15,21 @@ */ package com.squareup.moshi.recipes; +import static com.squareup.moshi.recipes.models.Suit.CLUBS; +import static com.squareup.moshi.recipes.models.Suit.HEARTS; +import static com.squareup.moshi.recipes.models.Suit.SPADES; + import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; import com.squareup.moshi.recipes.models.BlackjackHand; import com.squareup.moshi.recipes.models.Card; import java.util.Arrays; -import static com.squareup.moshi.recipes.models.Suit.CLUBS; -import static com.squareup.moshi.recipes.models.Suit.HEARTS; -import static com.squareup.moshi.recipes.models.Suit.SPADES; - public final class WriteJson { public void run() throws Exception { - BlackjackHand blackjackHand = new BlackjackHand( - new Card('6', SPADES), - Arrays.asList(new Card('4', CLUBS), new Card('A', HEARTS))); + BlackjackHand blackjackHand = + new BlackjackHand( + new Card('6', SPADES), Arrays.asList(new Card('4', CLUBS), new Card('A', HEARTS))); Moshi moshi = new Moshi.Builder().build(); JsonAdapter jsonAdapter = moshi.adapter(BlackjackHand.class); diff --git a/examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java b/examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java index b8a9be0d4..a21d1227c 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java @@ -27,7 +27,8 @@ public BlackjackHand(Card hiddenCard, List visibleCards) { this.visible_cards = visibleCards; } - @Override public String toString() { + @Override + public String toString() { return "hidden=" + hidden_card + ",visible=" + visible_cards; } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/models/Card.java b/examples/src/main/java/com/squareup/moshi/recipes/models/Card.java index 33980e5f0..b72b2b137 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/models/Card.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/models/Card.java @@ -24,7 +24,8 @@ public Card(char rank, Suit suit) { this.suit = suit; } - @Override public String toString() { + @Override + public String toString() { return String.format("%s%s", rank, suit); } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/models/Player.java b/examples/src/main/java/com/squareup/moshi/recipes/models/Player.java index 0fa4d1b42..700ec9ae6 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/models/Player.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/models/Player.java @@ -26,7 +26,8 @@ public Player(String username, int luckyNumber) { this.luckyNumber = luckyNumber; } - @Override public String toString() { + @Override + public String toString() { return username + " gets lucky with " + luckyNumber; } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java b/examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java index 86cb5c3fd..0952e457e 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java @@ -16,9 +16,13 @@ package com.squareup.moshi.recipes.models; public enum Suit { - CLUBS, DIAMONDS, HEARTS, SPADES; + CLUBS, + DIAMONDS, + HEARTS, + SPADES; - @Override public String toString() { + @Override + public String toString() { return name().substring(0, 1); } } diff --git a/examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java b/examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java index 38c7f0518..78be74976 100644 --- a/examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java +++ b/examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java @@ -28,7 +28,8 @@ public Tournament(String name, String location, Date start) { this.start = start; } - @Override public String toString() { + @Override + public String toString() { return name + " at " + location + " on " + start; } } diff --git a/kotlin/codegen/build.gradle.kts b/kotlin/codegen/build.gradle.kts index 8939bbee6..1522dc0aa 100644 --- a/kotlin/codegen/build.gradle.kts +++ b/kotlin/codegen/build.gradle.kts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer import org.jetbrains.kotlin.gradle.tasks.KotlinCompile @@ -28,8 +29,8 @@ tasks.withType().configureEach { kotlinOptions { jvmTarget = "1.8" freeCompilerArgs = listOf( - "-progressive", - "-Xopt-in=com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview" + "-progressive", + "-Xopt-in=com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview" ) } } @@ -80,8 +81,10 @@ val shadowJar = tasks.shadowJar.apply { archiveClassifier.set("") configurations = listOf(shade) relocate("com.squareup.kotlinpoet.metadata", "com.squareup.moshi.kotlinpoet.metadata") - relocate("com.squareup.kotlinpoet.classinspector", - "com.squareup.moshi.kotlinpoet.classinspector") + relocate( + "com.squareup.kotlinpoet.classinspector", + "com.squareup.moshi.kotlinpoet.classinspector" + ) relocate("kotlinx.metadata", "com.squareup.moshi.kotlinx.metadata") transformers.add(ServiceFileTransformer()) } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessor.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessor.kt index 330d97a36..eef7de968 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessor.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessor.kt @@ -60,8 +60,8 @@ class JsonClassCodegenProcessor : AbstractProcessor() { */ const val OPTION_GENERATED = "moshi.generated" private val POSSIBLE_GENERATED_NAMES = setOf( - "javax.annotation.processing.Generated", - "javax.annotation.Generated" + "javax.annotation.processing.Generated", + "javax.annotation.Generated" ) } @@ -84,7 +84,7 @@ class JsonClassCodegenProcessor : AbstractProcessor() { generatedType = processingEnv.options[OPTION_GENERATED]?.let { require(it in POSSIBLE_GENERATED_NAMES) { "Invalid option value for $OPTION_GENERATED. Found $it, " + - "allowable values are $POSSIBLE_GENERATED_NAMES." + "allowable values are $POSSIBLE_GENERATED_NAMES." } processingEnv.elementUtils.getTypeElement(it) } @@ -104,30 +104,34 @@ class JsonClassCodegenProcessor : AbstractProcessor() { for (type in roundEnv.getElementsAnnotatedWith(annotation)) { if (type !is TypeElement) { messager.printMessage( - Diagnostic.Kind.ERROR, "@JsonClass can't be applied to $type: must be a Kotlin class", - type) + Diagnostic.Kind.ERROR, + "@JsonClass can't be applied to $type: must be a Kotlin class", + type + ) continue } val jsonClass = type.getAnnotation(annotation) if (jsonClass.generateAdapter && jsonClass.generator.isEmpty()) { val generator = adapterGenerator(type, cachedClassInspector) ?: continue val preparedAdapter = generator - .prepare { spec -> - spec.toBuilder() - .apply { - generatedType?.asClassName()?.let { generatedClassName -> - addAnnotation( - AnnotationSpec.builder(generatedClassName) - .addMember("value = [%S]", - JsonClassCodegenProcessor::class.java.canonicalName) - .addMember("comments = %S", "https://github.com/square/moshi") - .build() + .prepare { spec -> + spec.toBuilder() + .apply { + generatedType?.asClassName()?.let { generatedClassName -> + addAnnotation( + AnnotationSpec.builder(generatedClassName) + .addMember( + "value = [%S]", + JsonClassCodegenProcessor::class.java.canonicalName ) - } - } - .addOriginatingElement(type) - .build() - } + .addMember("comments = %S", "https://github.com/square/moshi") + .build() + ) + } + } + .addOriginatingElement(type) + .build() + } preparedAdapter.spec.writeTo(filer) preparedAdapter.proguardConfig?.writeTo(filer, type) @@ -138,8 +142,8 @@ class JsonClassCodegenProcessor : AbstractProcessor() { } private fun adapterGenerator( - element: TypeElement, - cachedClassInspector: MoshiCachedClassInspector + element: TypeElement, + cachedClassInspector: MoshiCachedClassInspector ): AdapterGenerator? { val type = targetType(messager, elements, types, element, cachedClassInspector) ?: return null @@ -154,9 +158,10 @@ class JsonClassCodegenProcessor : AbstractProcessor() { for ((name, parameter) in type.constructor.parameters) { if (type.properties[parameter.name] == null && !parameter.hasDefault) { messager.printMessage( - Diagnostic.Kind.ERROR, - "No property for required constructor parameter $name", - element) + Diagnostic.Kind.ERROR, + "No property for required constructor parameter $name", + element + ) return null } } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/MoshiCachedClassInspector.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/MoshiCachedClassInspector.kt index 2a8b4465c..086c4ae49 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/MoshiCachedClassInspector.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/MoshiCachedClassInspector.kt @@ -34,4 +34,4 @@ internal class MoshiCachedClassInspector(private val classInspector: ClassInspec toTypeSpec(toImmutableKmClass(element.metadata)) } } -} \ No newline at end of file +} diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/AdapterGenerator.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/AdapterGenerator.kt index d6be4370d..773d7aeac 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/AdapterGenerator.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/AdapterGenerator.kt @@ -52,40 +52,42 @@ private const val TO_STRING_SIZE_BASE = TO_STRING_PREFIX.length + 1 // 1 is the /** Generates a JSON adapter for a target type. */ internal class AdapterGenerator( - private val target: TargetType, - private val propertyList: List + private val target: TargetType, + private val propertyList: List ) { companion object { private val INT_TYPE_BLOCK = CodeBlock.of("%T::class.javaPrimitiveType", INT) private val DEFAULT_CONSTRUCTOR_MARKER_TYPE_BLOCK = CodeBlock.of( - "%T.DEFAULT_CONSTRUCTOR_MARKER", Util::class) + "%T.DEFAULT_CONSTRUCTOR_MARKER", + Util::class + ) private val CN_MOSHI = Moshi::class.asClassName() private val CN_TYPE = Type::class.asClassName() private val COMMON_SUPPRESS = arrayOf( - // https://github.com/square/moshi/issues/1023 - "DEPRECATION", - // Because we look it up reflectively - "unused", - // Because we include underscores - "ClassName", - // Because we generate redundant `out` variance for some generics and there's no way - // for us to know when it's redundant. - "REDUNDANT_PROJECTION", - // Because we may generate redundant explicit types for local vars with default values. - // Example: 'var fooSet: Boolean = false' - "RedundantExplicitType", - // NameAllocator will just add underscores to differentiate names, which Kotlin doesn't - // like for stylistic reasons. - "LocalVariableName" + // https://github.com/square/moshi/issues/1023 + "DEPRECATION", + // Because we look it up reflectively + "unused", + // Because we include underscores + "ClassName", + // Because we generate redundant `out` variance for some generics and there's no way + // for us to know when it's redundant. + "REDUNDANT_PROJECTION", + // Because we may generate redundant explicit types for local vars with default values. + // Example: 'var fooSet: Boolean = false' + "RedundantExplicitType", + // NameAllocator will just add underscores to differentiate names, which Kotlin doesn't + // like for stylistic reasons. + "LocalVariableName" ).let { suppressions -> AnnotationSpec.builder(Suppress::class) - .addMember( - suppressions.indices.joinToString { "%S" }, - *suppressions - ) - .build() + .addMember( + suppressions.indices.joinToString { "%S" }, + *suppressions + ) + .build() } } @@ -94,7 +96,7 @@ internal class AdapterGenerator( private val visibility = target.visibility private val typeVariables = target.typeVariables private val targetConstructorParams = target.constructor.parameters - .mapKeys { (_, param) -> param.index } + .mapKeys { (_, param) -> param.index } private val nameAllocator = NameAllocator() private val adapterName = "${className.simpleNames.joinToString(separator = "_")}JsonAdapter" @@ -102,48 +104,57 @@ internal class AdapterGenerator( private val originalRawTypeName = originalTypeName.rawType() private val moshiParam = ParameterSpec.builder( - nameAllocator.newName("moshi"), - CN_MOSHI).build() + nameAllocator.newName("moshi"), + CN_MOSHI + ).build() private val typesParam = ParameterSpec.builder( - nameAllocator.newName("types"), - ARRAY.parameterizedBy(CN_TYPE)) - .build() + nameAllocator.newName("types"), + ARRAY.parameterizedBy(CN_TYPE) + ) + .build() private val readerParam = ParameterSpec.builder( - nameAllocator.newName("reader"), - JsonReader::class) - .build() + nameAllocator.newName("reader"), + JsonReader::class + ) + .build() private val writerParam = ParameterSpec.builder( - nameAllocator.newName("writer"), - JsonWriter::class) - .build() + nameAllocator.newName("writer"), + JsonWriter::class + ) + .build() private val valueParam = ParameterSpec.builder( - nameAllocator.newName("value"), - originalTypeName.copy(nullable = true)) - .build() + nameAllocator.newName("value"), + originalTypeName.copy(nullable = true) + ) + .build() private val jsonAdapterTypeName = JsonAdapter::class.asClassName().parameterizedBy( - originalTypeName) + originalTypeName + ) // selectName() API setup private val optionsProperty = PropertySpec.builder( - nameAllocator.newName("options"), JsonReader.Options::class.asTypeName(), - KModifier.PRIVATE) - .initializer( - "%T.of(%L)", - JsonReader.Options::class.asTypeName(), - nonTransientProperties - .map { CodeBlock.of("%S", it.jsonName) } - .joinToCode(", ") - ) - .build() + nameAllocator.newName("options"), + JsonReader.Options::class.asTypeName(), + KModifier.PRIVATE + ) + .initializer( + "%T.of(%L)", + JsonReader.Options::class.asTypeName(), + nonTransientProperties + .map { CodeBlock.of("%S", it.jsonName) } + .joinToCode(", ") + ) + .build() private val constructorProperty = PropertySpec.builder( - nameAllocator.newName("constructorRef"), - Constructor::class.asClassName().parameterizedBy(originalTypeName).copy(nullable = true), - KModifier.PRIVATE) - .addAnnotation(Volatile::class) - .mutable(true) - .initializer("null") - .build() + nameAllocator.newName("constructorRef"), + Constructor::class.asClassName().parameterizedBy(originalTypeName).copy(nullable = true), + KModifier.PRIVATE + ) + .addAnnotation(Volatile::class) + .mutable(true) + .initializer("null") + .build() fun prepare(typeHook: (TypeSpec) -> TypeSpec = { it }): PreparedAdapter { for (property in nonTransientProperties) { @@ -159,17 +170,17 @@ internal class AdapterGenerator( private fun TypeSpec.createProguardRule(): ProguardConfig { val adapterProperties = propertySpecs - .asSequence() - .filter { prop -> - prop.type.rawType() == JsonAdapter::class.asClassName() - } - .filter { prop -> prop.annotations.isNotEmpty() } - .mapTo(mutableSetOf()) { prop -> - QualifierAdapterProperty( - name = prop.name, - qualifiers = prop.annotations.mapTo(mutableSetOf()) { it.className } - ) - } + .asSequence() + .filter { prop -> + prop.type.rawType() == JsonAdapter::class.asClassName() + } + .filter { prop -> prop.annotations.isNotEmpty() } + .mapTo(mutableSetOf()) { prop -> + QualifierAdapterProperty( + name = prop.name, + qualifiers = prop.annotations.mapTo(mutableSetOf()) { it.className } + ) + } val adapterConstructorParams = when (requireNotNull(primaryConstructor).parameters.size) { 1 -> listOf(CN_MOSHI.reflectionName()) @@ -188,21 +199,21 @@ internal class AdapterGenerator( } hasDefaultProperties = propertyList.any { it.hasDefault } parameterTypes = AsmType.getArgumentTypes(constructorSignature.removePrefix("")) - .map { it.toReflectionString() } + .map { it.toReflectionString() } } return ProguardConfig( - targetClass = className, - adapterName = adapterName, - adapterConstructorParams = adapterConstructorParams, - targetConstructorHasDefaults = hasDefaultProperties, - targetConstructorParams = parameterTypes, - qualifierProperties = adapterProperties + targetClass = className, + adapterName = adapterName, + adapterConstructorParams = adapterConstructorParams, + targetConstructorHasDefaults = hasDefaultProperties, + targetConstructorParams = parameterTypes, + qualifierProperties = adapterProperties ) } private fun generateType(): TypeSpec { val result = TypeSpec.classBuilder(adapterName) - .addAnnotation(COMMON_SUPPRESS) + .addAnnotation(COMMON_SUPPRESS) result.superclass(jsonAdapterTypeName) @@ -211,19 +222,21 @@ internal class AdapterGenerator( // require(types.size == 1) { // "TypeVariable mismatch: Expecting 1 type(s) for generic type variables [T], but received ${types.size} with values $types" // } - result.addInitializerBlock(CodeBlock.builder() + result.addInitializerBlock( + CodeBlock.builder() .beginControlFlow("require(types.size == %L)", typeVariables.size) .addStatement( - "buildString·{·append(%S).append(%L).append(%S).append(%S).append(%S).append(%L)·}", - "TypeVariable mismatch: Expecting ", - typeVariables.size, - " ${if (typeVariables.size == 1) "type" else "types"} for generic type variables [", - typeVariables.joinToString(", ") { it.name }, - "], but received ", - "${typesParam.name}.size" + "buildString·{·append(%S).append(%L).append(%S).append(%S).append(%S).append(%L)·}", + "TypeVariable mismatch: Expecting ", + typeVariables.size, + " ${if (typeVariables.size == 1) "type" else "types"} for generic type variables [", + typeVariables.joinToString(", ") { it.name }, + "], but received ", + "${typesParam.name}.size" ) .endControlFlow() - .build()) + .build() + ) } // TODO make this configurable. Right now it just matches the source model @@ -243,8 +256,14 @@ internal class AdapterGenerator( result.addProperty(optionsProperty) for (uniqueAdapter in nonTransientProperties.distinctBy { it.delegateKey }) { - result.addProperty(uniqueAdapter.delegateKey.generateProperty( - nameAllocator, typeRenderer, moshiParam, uniqueAdapter.name)) + result.addProperty( + uniqueAdapter.delegateKey.generateProperty( + nameAllocator, + typeRenderer, + moshiParam, + uniqueAdapter.name + ) + ) } result.addFunction(generateToStringFun()) @@ -269,24 +288,24 @@ internal class AdapterGenerator( val name = originalRawTypeName.simpleNames.joinToString(".") val size = TO_STRING_SIZE_BASE + name.length return FunSpec.builder("toString") - .addModifiers(KModifier.OVERRIDE) - .returns(String::class) - .addStatement( - "return %M(%L)·{ append(%S).append(%S).append('%L') }", - MemberName("kotlin.text", "buildString"), - size, - TO_STRING_PREFIX, - name, - ")" - ) - .build() + .addModifiers(KModifier.OVERRIDE) + .returns(String::class) + .addStatement( + "return %M(%L)·{ append(%S).append(%S).append('%L') }", + MemberName("kotlin.text", "buildString"), + size, + TO_STRING_PREFIX, + name, + ")" + ) + .build() } private fun generateFromJsonFun(classBuilder: TypeSpec.Builder): FunSpec { val result = FunSpec.builder("fromJson") - .addModifiers(KModifier.OVERRIDE) - .addParameter(readerParam) - .returns(originalTypeName) + .addModifiers(KModifier.OVERRIDE) + .addParameter(readerParam) + .returns(originalTypeName) for (property in nonTransientProperties) { result.addCode("%L", property.generateLocalProperty()) @@ -296,8 +315,8 @@ internal class AdapterGenerator( } val propertiesByIndex = propertyList.asSequence() - .filter { it.hasConstructorParameter } - .associateBy { it.target.parameterIndex } + .filter { it.hasConstructorParameter } + .associateBy { it.target.parameterIndex } val components = mutableListOf() // Add parameters (± properties) first, their index matters @@ -333,7 +352,7 @@ internal class AdapterGenerator( nameAllocator.newName("mask$index") } val useDefaultsConstructor = components.filterIsInstance() - .any { it.parameter.hasDefault } + .any { it.parameter.hasDefault } if (useDefaultsConstructor) { // Initialize all our masks, defaulting to fully unset (-1) for (maskName in maskNames) { @@ -372,7 +391,8 @@ internal class AdapterGenerator( for (input in components) { if (input is ParameterOnly || - (input is ParameterProperty && input.property.isTransient)) { + (input is ParameterProperty && input.property.isTransient) + ) { updateMaskIndexes() constructorPropertyTypes += input.type.asTypeBlock() continue @@ -387,18 +407,30 @@ internal class AdapterGenerator( if (property.hasLocalIsPresentName || property.hasConstructorDefault) { result.beginControlFlow("%L ->", propertyIndex) if (property.delegateKey.nullable) { - result.addStatement("%N = %N.fromJson(%N)", - property.localName, nameAllocator[property.delegateKey], readerParam) + result.addStatement( + "%N = %N.fromJson(%N)", + property.localName, + nameAllocator[property.delegateKey], + readerParam + ) } else { val exception = unexpectedNull(property, readerParam) - result.addStatement("%N = %N.fromJson(%N) ?: throw·%L", - property.localName, nameAllocator[property.delegateKey], readerParam, exception) + result.addStatement( + "%N = %N.fromJson(%N) ?: throw·%L", + property.localName, + nameAllocator[property.delegateKey], + readerParam, + exception + ) } if (property.hasConstructorDefault) { val inverted = (1 shl maskIndex).inv() result.addComment("\$mask = \$mask and (1 shl %L).inv()", maskIndex) - result.addStatement("%1L = %1L and 0x%2L.toInt()", maskNames[maskNameIndex], - Integer.toHexString(inverted)) + result.addStatement( + "%1L = %1L and 0x%2L.toInt()", + maskNames[maskNameIndex], + Integer.toHexString(inverted) + ) } else { // Presence tracker for a mutable property result.addStatement("%N = true", property.localIsPresentName) @@ -406,13 +438,23 @@ internal class AdapterGenerator( result.endControlFlow() } else { if (property.delegateKey.nullable) { - result.addStatement("%L -> %N = %N.fromJson(%N)", - propertyIndex, property.localName, nameAllocator[property.delegateKey], readerParam) + result.addStatement( + "%L -> %N = %N.fromJson(%N)", + propertyIndex, + property.localName, + nameAllocator[property.delegateKey], + readerParam + ) } else { val exception = unexpectedNull(property, readerParam) - result.addStatement("%L -> %N = %N.fromJson(%N) ?: throw·%L", - propertyIndex, property.localName, nameAllocator[property.delegateKey], readerParam, - exception) + result.addStatement( + "%L -> %N = %N.fromJson(%N) ?: throw·%L", + propertyIndex, + property.localName, + nameAllocator[property.delegateKey], + readerParam, + exception + ) } } if (property.hasConstructorParameter) { @@ -447,13 +489,13 @@ internal class AdapterGenerator( // Dynamic default constructor call val nonNullConstructorType = constructorProperty.type.copy(nullable = false) val args = constructorPropertyTypes - .plus(0.until(maskCount).map { INT_TYPE_BLOCK }) // Masks, one every 32 params - .plus(DEFAULT_CONSTRUCTOR_MARKER_TYPE_BLOCK) // Default constructor marker is always last - .joinToCode(", ") + .plus(0.until(maskCount).map { INT_TYPE_BLOCK }) // Masks, one every 32 params + .plus(DEFAULT_CONSTRUCTOR_MARKER_TYPE_BLOCK) // Default constructor marker is always last + .joinToCode(", ") val coreLookupBlock = CodeBlock.of( - "%T::class.java.getDeclaredConstructor(%L)", - originalRawTypeName, - args + "%T::class.java.getDeclaredConstructor(%L)", + originalRawTypeName, + args ) val lookupBlock = if (originalTypeName is ParameterizedTypeName) { CodeBlock.of("(%L·as·%T)", coreLookupBlock, nonNullConstructorType) @@ -461,23 +503,26 @@ internal class AdapterGenerator( coreLookupBlock } val initializerBlock = CodeBlock.of( - "this.%1N·?: %2L.also·{ this.%1N·= it }", - constructorProperty, - lookupBlock + "this.%1N·?: %2L.also·{ this.%1N·= it }", + constructorProperty, + lookupBlock ) val localConstructorProperty = PropertySpec.builder( - nameAllocator.newName("localConstructor"), - nonNullConstructorType) - .addAnnotation(AnnotationSpec.builder(Suppress::class) - .addMember("%S", "UNCHECKED_CAST") - .build()) - .initializer(initializerBlock) - .build() + nameAllocator.newName("localConstructor"), + nonNullConstructorType + ) + .addAnnotation( + AnnotationSpec.builder(Suppress::class) + .addMember("%S", "UNCHECKED_CAST") + .build() + ) + .initializer(initializerBlock) + .build() result.addCode("%L", localConstructorProperty) result.addCode( - "«%L%N.newInstance(", - returnOrResultAssignment, - localConstructorProperty + "«%L%N.newInstance(", + returnOrResultAssignment, + localConstructorProperty ) } else { // Standard constructor call. Don't omit generics for parameterized types even if they can be @@ -505,8 +550,13 @@ internal class AdapterGenerator( val property = input.property if (!property.isTransient && property.isRequired) { val missingPropertyBlock = - CodeBlock.of("%T.missingProperty(%S, %S, %N)", - MOSHI_UTIL, property.localName, property.jsonName, readerParam) + CodeBlock.of( + "%T.missingProperty(%S, %S, %N)", + MOSHI_UTIL, + property.localName, + property.jsonName, + readerParam + ) result.addCode(" ?: throw·%L", missingPropertyBlock) } } @@ -526,11 +576,20 @@ internal class AdapterGenerator( continue // Property already handled. } if (property.hasLocalIsPresentName) { - result.addStatement("%1N.%2N = if (%3N) %4N else %1N.%2N", - resultName, property.name, property.localIsPresentName, property.localName) + result.addStatement( + "%1N.%2N = if (%3N) %4N else %1N.%2N", + resultName, + property.name, + property.localIsPresentName, + property.localName + ) } else { - result.addStatement("%1N.%2N = %3N ?: %1N.%2N", - resultName, property.name, property.localName) + result.addStatement( + "%1N.%2N = %3N ?: %1N.%2N", + resultName, + property.name, + property.localName + ) } } @@ -541,27 +600,40 @@ internal class AdapterGenerator( } private fun unexpectedNull(property: PropertyGenerator, reader: ParameterSpec): CodeBlock { - return CodeBlock.of("%T.unexpectedNull(%S, %S, %N)", - MOSHI_UTIL, property.localName, property.jsonName, reader) + return CodeBlock.of( + "%T.unexpectedNull(%S, %S, %N)", + MOSHI_UTIL, + property.localName, + property.jsonName, + reader + ) } private fun generateToJsonFun(): FunSpec { val result = FunSpec.builder("toJson") - .addModifiers(KModifier.OVERRIDE) - .addParameter(writerParam) - .addParameter(valueParam) + .addModifiers(KModifier.OVERRIDE) + .addParameter(writerParam) + .addParameter(valueParam) result.beginControlFlow("if (%N == null)", valueParam) - result.addStatement("throw·%T(%S)", NullPointerException::class, - "${valueParam.name} was null! Wrap in .nullSafe() to write nullable values.") + result.addStatement( + "throw·%T(%S)", + NullPointerException::class, + "${valueParam.name} was null! Wrap in .nullSafe() to write nullable values." + ) result.endControlFlow() result.addStatement("%N.beginObject()", writerParam) nonTransientProperties.forEach { property -> // We manually put in quotes because we know the jsonName is already escaped result.addStatement("%N.name(%S)", writerParam, property.jsonName) - result.addStatement("%N.toJson(%N, %N.%N)", - nameAllocator[property.delegateKey], writerParam, valueParam, property.name) + result.addStatement( + "%N.toJson(%N, %N.%N)", + nameAllocator[property.delegateKey], + writerParam, + valueParam, + property.name + ) } result.addStatement("%N.endObject()", writerParam) @@ -610,20 +682,20 @@ private sealed class FromJsonComponent { abstract val type: TypeName data class ParameterOnly( - override val parameter: TargetParameter + override val parameter: TargetParameter ) : FromJsonComponent(), ParameterComponent { override val type: TypeName = parameter.type } data class PropertyOnly( - override val property: PropertyGenerator + override val property: PropertyGenerator ) : FromJsonComponent(), PropertyComponent { override val type: TypeName = property.target.type } data class ParameterProperty( - override val parameter: TargetParameter, - override val property: PropertyGenerator + override val parameter: TargetParameter, + override val property: PropertyGenerator ) : FromJsonComponent(), ParameterComponent, PropertyComponent { override val type: TypeName = parameter.type } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/DelegateKey.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/DelegateKey.kt index bbbe69765..8fa625cfb 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/DelegateKey.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/DelegateKey.kt @@ -50,24 +50,28 @@ internal data class DelegateKey( "At${it.className.simpleName}" } val adapterName = nameAllocator.newName( - "${type.toVariableName().decapitalize()}${qualifierNames}Adapter", this) + "${type.toVariableName().decapitalize()}${qualifierNames}Adapter", + this + ) val adapterTypeName = JsonAdapter::class.asClassName().parameterizedBy(type) - val standardArgs = arrayOf(moshiParameter, - typeRenderer.render(type)) + val standardArgs = arrayOf( + moshiParameter, + typeRenderer.render(type) + ) val (initializerString, args) = when { jsonQualifiers.isEmpty() -> ", %M()" to arrayOf(MemberName("kotlin.collections", "emptySet")) else -> { ", %T.getFieldJsonQualifierAnnotations(javaClass, " + - "%S)" to arrayOf(Types::class.asTypeName(), adapterName) + "%S)" to arrayOf(Types::class.asTypeName(), adapterName) } } val finalArgs = arrayOf(*standardArgs, *args, propertyName) return PropertySpec.builder(adapterName, adapterTypeName, KModifier.PRIVATE) - .addAnnotations(jsonQualifiers) - .initializer("%N.adapter(%L$initializerString, %S)", *finalArgs) - .build() + .addAnnotations(jsonQualifiers) + .initializer("%N.adapter(%L$initializerString, %S)", *finalArgs) + .build() } } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/ProguardRules.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/ProguardRules.kt index 5088d35f3..b819f44da 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/ProguardRules.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/ProguardRules.kt @@ -20,20 +20,20 @@ import javax.tools.StandardLocation * class with a deterministic name (see [outputFile]) with an appropriate originating element. */ internal data class ProguardConfig( - val targetClass: ClassName, - val adapterName: String, - val adapterConstructorParams: List, - val targetConstructorHasDefaults: Boolean, - val targetConstructorParams: List, - val qualifierProperties: Set + val targetClass: ClassName, + val adapterName: String, + val adapterConstructorParams: List, + val targetConstructorHasDefaults: Boolean, + val targetConstructorParams: List, + val qualifierProperties: Set ) { private val outputFile = "META-INF/proguard/moshi-${targetClass.canonicalName}.pro" /** Writes this to `filer`. */ fun writeTo(filer: Filer, vararg originatingElements: Element) { filer.createResource(StandardLocation.CLASS_OUTPUT, "", outputFile, *originatingElements) - .openWriter() - .use(::writeTo) + .openWriter() + .use(::writeTo) } private fun writeTo(out: Appendable): Unit = out.run { @@ -64,13 +64,13 @@ internal data class ProguardConfig( appendln("}") qualifierProperties.asSequence() - .flatMap { it.qualifiers.asSequence() } - .map(ClassName::reflectionName) - .sorted() - .forEach { qualifier -> - appendln("-if class $targetName") - appendln("-keep @interface $qualifier") - } + .flatMap { it.qualifiers.asSequence() } + .map(ClassName::reflectionName) + .sorted() + .forEach { qualifier -> + appendln("-if class $targetName") + appendln("-keep @interface $qualifier") + } if (targetConstructorHasDefaults) { // If the target class has default parameter values, keep its synthetic constructor diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/PropertyGenerator.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/PropertyGenerator.kt index 07bf1bf3f..e9ddefd91 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/PropertyGenerator.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/PropertyGenerator.kt @@ -56,24 +56,24 @@ internal class PropertyGenerator( fun generateLocalProperty(): PropertySpec { return PropertySpec.builder(localName, target.type.copy(nullable = true)) - .mutable(true) - .apply { - if (hasConstructorDefault) { - // We default to the primitive default type, as reflectively invoking the constructor - // without this (even though it's a throwaway) will fail argument type resolution in - // the reflective invocation. - initializer(target.type.defaultPrimitiveValue()) - } else { - initializer("null") - } + .mutable(true) + .apply { + if (hasConstructorDefault) { + // We default to the primitive default type, as reflectively invoking the constructor + // without this (even though it's a throwaway) will fail argument type resolution in + // the reflective invocation. + initializer(target.type.defaultPrimitiveValue()) + } else { + initializer("null") } - .build() + } + .build() } fun generateLocalIsPresentProperty(): PropertySpec { return PropertySpec.builder(localIsPresentName, BOOLEAN) - .mutable(true) - .initializer("false") - .build() + .mutable(true) + .initializer("false") + .build() } } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TypeRenderer.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TypeRenderer.kt index f4602868d..98e0efa82 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TypeRenderer.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TypeRenderer.kt @@ -60,9 +60,11 @@ abstract class TypeRenderer { is ParameterizedTypeName -> { // If it's an Array type, we shortcut this to return Types.arrayOf() if (typeName.rawType == ARRAY) { - CodeBlock.of("%T.arrayOf(%L)", - Types::class, - renderObjectType(typeName.typeArguments[0])) + CodeBlock.of( + "%T.arrayOf(%L)", + Types::class, + renderObjectType(typeName.typeArguments[0]) + ) } else { val builder = CodeBlock.builder().apply { add("%T.", Types::class) @@ -95,7 +97,8 @@ abstract class TypeRenderer { method = "subtypeOf" } else -> throw IllegalArgumentException( - "Unrepresentable wildcard type. Cannot have more than one bound: $typeName") + "Unrepresentable wildcard type. Cannot have more than one bound: $typeName" + ) } CodeBlock.of("%T.%L(%L)", Types::class, method, render(target, forceBox = true)) } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/kotlintypes.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/kotlintypes.kt index 1b678d2f2..e73a884ed 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/kotlintypes.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/kotlintypes.kt @@ -48,18 +48,18 @@ internal fun TypeName.rawType(): ClassName { } internal fun TypeName.defaultPrimitiveValue(): CodeBlock = - when (this) { - BOOLEAN -> CodeBlock.of("false") - CHAR -> CodeBlock.of("0.toChar()") - BYTE -> CodeBlock.of("0.toByte()") - SHORT -> CodeBlock.of("0.toShort()") - INT -> CodeBlock.of("0") - FLOAT -> CodeBlock.of("0f") - LONG -> CodeBlock.of("0L") - DOUBLE -> CodeBlock.of("0.0") - UNIT, Void::class.asTypeName(), NOTHING -> throw IllegalStateException("Parameter with void, Unit, or Nothing type is illegal") - else -> CodeBlock.of("null") - } + when (this) { + BOOLEAN -> CodeBlock.of("false") + CHAR -> CodeBlock.of("0.toChar()") + BYTE -> CodeBlock.of("0.toByte()") + SHORT -> CodeBlock.of("0.toShort()") + INT -> CodeBlock.of("0") + FLOAT -> CodeBlock.of("0f") + LONG -> CodeBlock.of("0L") + DOUBLE -> CodeBlock.of("0.0") + UNIT, Void::class.asTypeName(), NOTHING -> throw IllegalStateException("Parameter with void, Unit, or Nothing type is illegal") + else -> CodeBlock.of("null") + } internal fun TypeName.asTypeBlock(): CodeBlock { if (annotations.isNotEmpty()) { @@ -103,12 +103,12 @@ internal fun KModifier.checkIsVisibility() { } } -internal inline fun TypeName.mapTypes(noinline transform: T.() -> TypeName?): TypeName { +internal inline fun TypeName.mapTypes(noinline transform: T.() -> TypeName?): TypeName { return mapTypes(T::class, transform) } @Suppress("UNCHECKED_CAST") -internal fun TypeName.mapTypes(target: KClass, transform: T.() -> TypeName?): TypeName { +internal fun TypeName.mapTypes(target: KClass, transform: T.() -> TypeName?): TypeName { if (target.java == javaClass) { return (this as T).transform() ?: return this } @@ -116,7 +116,7 @@ internal fun TypeName.mapTypes(target: KClass, transform: T.() is ClassName -> this is ParameterizedTypeName -> { (rawType.mapTypes(target, transform) as ClassName).parameterizedBy(typeArguments.map { it.mapTypes(target, transform) }) - .copy(nullable = isNullable, annotations = annotations) + .copy(nullable = isNullable, annotations = annotations) } is TypeVariableName -> { copy(bounds = bounds.map { it.mapTypes(target, transform) }) @@ -129,11 +129,11 @@ internal fun TypeName.mapTypes(target: KClass, transform: T.() this == STAR -> this outTypes.isNotEmpty() && inTypes.isEmpty() -> { WildcardTypeName.producerOf(outTypes[0].mapTypes(target, transform)) - .copy(nullable = isNullable, annotations = annotations) + .copy(nullable = isNullable, annotations = annotations) } inTypes.isNotEmpty() -> { WildcardTypeName.consumerOf(inTypes[0].mapTypes(target, transform)) - .copy(nullable = isNullable, annotations = annotations) + .copy(nullable = isNullable, annotations = annotations) } else -> throw UnsupportedOperationException("Not possible.") } diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/metadata.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/metadata.kt index cc69f4da1..4908c737b 100644 --- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/metadata.kt +++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/metadata.kt @@ -65,10 +65,10 @@ private val JSON_QUALIFIER = JsonQualifier::class.java private val JSON = Json::class.asClassName() private val OBJECT_CLASS = ClassName("java.lang", "Object") private val VISIBILITY_MODIFIERS = setOf( - KModifier.INTERNAL, - KModifier.PRIVATE, - KModifier.PROTECTED, - KModifier.PUBLIC + KModifier.INTERNAL, + KModifier.PRIVATE, + KModifier.PROTECTED, + KModifier.PUBLIC ) private fun Collection.visibility(): KModifier { @@ -77,10 +77,10 @@ private fun Collection.visibility(): KModifier { @KotlinPoetMetadataPreview internal fun primaryConstructor( - targetElement: TypeElement, - kotlinApi: TypeSpec, - elements: Elements, - messager: Messager + targetElement: TypeElement, + kotlinApi: TypeSpec, + elements: Elements, + messager: Messager ): TargetConstructor? { val primaryConstructor = kotlinApi.primaryConstructor ?: return null @@ -88,38 +88,47 @@ internal fun primaryConstructor( for ((index, parameter) in primaryConstructor.parameters.withIndex()) { val name = parameter.name parameters[name] = TargetParameter( - name = name, - index = index, - type = parameter.type, - hasDefault = parameter.defaultValue != null, - qualifiers = parameter.annotations.qualifiers(elements), - jsonName = parameter.annotations.jsonName() + name = name, + index = index, + type = parameter.type, + hasDefault = parameter.defaultValue != null, + qualifiers = parameter.annotations.qualifiers(elements), + jsonName = parameter.annotations.jsonName() ) } val kmConstructorSignature = primaryConstructor.tag()?.signature?.toString() - ?: run { - messager.printMessage(ERROR, "No KmConstructor found for primary constructor.", - targetElement) - null - } - return TargetConstructor(parameters, primaryConstructor.modifiers.visibility(), - kmConstructorSignature) + ?: run { + messager.printMessage( + ERROR, + "No KmConstructor found for primary constructor.", + targetElement + ) + null + } + return TargetConstructor( + parameters, + primaryConstructor.modifiers.visibility(), + kmConstructorSignature + ) } /** Returns a target type for `element`, or null if it cannot be used with code gen. */ @KotlinPoetMetadataPreview -internal fun targetType(messager: Messager, - elements: Elements, - types: Types, - element: TypeElement, - cachedClassInspector: MoshiCachedClassInspector +internal fun targetType( + messager: Messager, + elements: Elements, + types: Types, + element: TypeElement, + cachedClassInspector: MoshiCachedClassInspector ): TargetType? { val typeMetadata = element.getAnnotation(Metadata::class.java) if (typeMetadata == null) { messager.printMessage( - ERROR, "@JsonClass can't be applied to $element: must be a Kotlin class", - element) + ERROR, + "@JsonClass can't be applied to $element: must be a Kotlin class", + element + ) return null } @@ -127,54 +136,68 @@ internal fun targetType(messager: Messager, cachedClassInspector.toImmutableKmClass(typeMetadata) } catch (e: UnsupportedOperationException) { messager.printMessage( - ERROR, "@JsonClass can't be applied to $element: must be a Class type", - element) + ERROR, + "@JsonClass can't be applied to $element: must be a Class type", + element + ) return null } when { kmClass.isEnum -> { messager.printMessage( - ERROR, - "@JsonClass with 'generateAdapter = \"true\"' can't be applied to $element: code gen for enums is not supported or necessary", - element) + ERROR, + "@JsonClass with 'generateAdapter = \"true\"' can't be applied to $element: code gen for enums is not supported or necessary", + element + ) return null } !kmClass.isClass -> { messager.printMessage( - ERROR, "@JsonClass can't be applied to $element: must be a Kotlin class", - element) + ERROR, + "@JsonClass can't be applied to $element: must be a Kotlin class", + element + ) return null } kmClass.isInner -> { messager.printMessage( - ERROR, - "@JsonClass can't be applied to $element: must not be an inner class", element) + ERROR, + "@JsonClass can't be applied to $element: must not be an inner class", + element + ) return null } kmClass.isSealed -> { messager.printMessage( - ERROR, "@JsonClass can't be applied to $element: must not be sealed", - element) + ERROR, + "@JsonClass can't be applied to $element: must not be sealed", + element + ) return null } kmClass.isAbstract -> { messager.printMessage( - ERROR, "@JsonClass can't be applied to $element: must not be abstract", - element) + ERROR, + "@JsonClass can't be applied to $element: must not be abstract", + element + ) return null } kmClass.isLocal -> { messager.printMessage( - ERROR, "@JsonClass can't be applied to $element: must not be local", - element) + ERROR, + "@JsonClass can't be applied to $element: must not be local", + element + ) return null } !kmClass.isPublic && !kmClass.isInternal -> { messager.printMessage( - ERROR, - "@JsonClass can't be applied to $element: must be internal or public", - element) + ERROR, + "@JsonClass can't be applied to $element: must be internal or public", + element + ) return null } } @@ -185,13 +208,20 @@ internal fun targetType(messager: Messager, val constructor = primaryConstructor(element, kotlinApi, elements, messager) if (constructor == null) { - messager.printMessage(ERROR, "No primary constructor found on $element", - element) + messager.printMessage( + ERROR, + "No primary constructor found on $element", + element + ) return null } if (constructor.visibility != KModifier.INTERNAL && constructor.visibility != KModifier.PUBLIC) { - messager.printMessage(ERROR, "@JsonClass can't be applied to $element: " + - "primary constructor is not internal or public", element) + messager.printMessage( + ERROR, + "@JsonClass can't be applied to $element: " + + "primary constructor is not internal or public", + element + ) return null } @@ -199,66 +229,68 @@ internal fun targetType(messager: Messager, val resolvedTypes = mutableListOf() val superTypes = appliedType.supertypes(types) - .filterNot { supertype -> - supertype.element.asClassName() == OBJECT_CLASS || // Don't load properties for java.lang.Object. - supertype.element.kind != ElementKind.CLASS // Don't load properties for interface types. + .filterNot { supertype -> + supertype.element.asClassName() == OBJECT_CLASS || // Don't load properties for java.lang.Object. + supertype.element.kind != ElementKind.CLASS // Don't load properties for interface types. + } + .onEach { supertype -> + if (supertype.element.getAnnotation(Metadata::class.java) == null) { + messager.printMessage( + ERROR, + "@JsonClass can't be applied to $element: supertype $supertype is not a Kotlin type", + element + ) + return null } - .onEach { supertype -> - if (supertype.element.getAnnotation(Metadata::class.java) == null) { - messager.printMessage(ERROR, - "@JsonClass can't be applied to $element: supertype $supertype is not a Kotlin type", - element) - return null - } + } + .associateWithTo(LinkedHashMap()) { supertype -> + // Load the kotlin API cache into memory eagerly so we can reuse the parsed APIs + val api = if (supertype.element == element) { + // We've already parsed this api above, reuse it + kotlinApi + } else { + cachedClassInspector.toTypeSpec(supertype.element) } - .associateWithTo(LinkedHashMap()) { supertype -> - // Load the kotlin API cache into memory eagerly so we can reuse the parsed APIs - val api = if (supertype.element == element) { - // We've already parsed this api above, reuse it - kotlinApi - } else { - cachedClassInspector.toTypeSpec(supertype.element) - } - - val apiSuperClass = api.superclass - if (apiSuperClass is ParameterizedTypeName) { - // - // This extends a typed generic superclass. We want to construct a mapping of the - // superclass typevar names to their materialized types here. - // - // class Foo extends Bar - // class Bar - // - // We will store {Foo : {T : [String]}}. - // - // Then when we look at Bar later, we'll look up to the descendent Foo and extract its - // materialized type from there. - // - val superSuperClass = supertype.element.superclass as DeclaredType - - // Convert to an element and back to wipe the typed generics off of this - val untyped = superSuperClass.asElement().asType().asTypeName() as ParameterizedTypeName - resolvedTypes += ResolvedTypeMapping( - target = untyped.rawType, - args = untyped.typeArguments.asSequence() - .cast() - .map(TypeVariableName::name) - .zip(apiSuperClass.typeArguments.asSequence()) - .associate { it } - ) - } - - return@associateWithTo api + + val apiSuperClass = api.superclass + if (apiSuperClass is ParameterizedTypeName) { + // + // This extends a typed generic superclass. We want to construct a mapping of the + // superclass typevar names to their materialized types here. + // + // class Foo extends Bar + // class Bar + // + // We will store {Foo : {T : [String]}}. + // + // Then when we look at Bar later, we'll look up to the descendent Foo and extract its + // materialized type from there. + // + val superSuperClass = supertype.element.superclass as DeclaredType + + // Convert to an element and back to wipe the typed generics off of this + val untyped = superSuperClass.asElement().asType().asTypeName() as ParameterizedTypeName + resolvedTypes += ResolvedTypeMapping( + target = untyped.rawType, + args = untyped.typeArguments.asSequence() + .cast() + .map(TypeVariableName::name) + .zip(apiSuperClass.typeArguments.asSequence()) + .associate { it } + ) } + return@associateWithTo api + } + for ((localAppliedType, supertypeApi) in superTypes.entries) { val appliedClassName = localAppliedType.element.asClassName() val supertypeProperties = declaredProperties( - constructor = constructor, - kotlinApi = supertypeApi, - allowedTypeVars = typeVariables.toSet(), - currentClass = appliedClassName, - resolvedTypes = resolvedTypes + constructor = constructor, + kotlinApi = supertypeApi, + allowedTypeVars = typeVariables.toSet(), + currentClass = appliedClassName, + resolvedTypes = resolvedTypes ) for ((name, property) in supertypeProperties) { properties.putIfAbsent(name, property) @@ -273,18 +305,19 @@ internal fun targetType(messager: Messager, } else { // Implicitly public, so now look up the hierarchy val forceInternal = generateSequence(element) { it.enclosingElement } - .filterIsInstance() - .map { cachedClassInspector.toImmutableKmClass(it.metadata) } - .any { it.isInternal } + .filterIsInstance() + .map { cachedClassInspector.toImmutableKmClass(it.metadata) } + .any { it.isInternal } if (forceInternal) KModifier.INTERNAL else visibility } return TargetType( - typeName = element.asType().asTypeName(), - constructor = constructor, - properties = properties, - typeVariables = typeVariables, - isDataClass = KModifier.DATA in kotlinApi.modifiers, - visibility = resolvedVisibility) + typeName = element.asType().asTypeName(), + constructor = constructor, + properties = properties, + typeVariables = typeVariables, + isDataClass = KModifier.DATA in kotlinApi.modifiers, + visibility = resolvedVisibility + ) } /** @@ -294,11 +327,11 @@ internal fun targetType(messager: Messager, private data class ResolvedTypeMapping(val target: ClassName, val args: Map) private fun resolveTypeArgs( - targetClass: ClassName, - propertyType: TypeName, - resolvedTypes: List, - allowedTypeVars: Set, - entryStartIndex: Int = resolvedTypes.indexOfLast { it.target == targetClass } + targetClass: ClassName, + propertyType: TypeName, + resolvedTypes: List, + allowedTypeVars: Set, + entryStartIndex: Int = resolvedTypes.indexOfLast { it.target == targetClass } ): TypeName { val unwrappedType = propertyType.unwrapTypeAlias() @@ -315,8 +348,8 @@ private fun resolveTypeArgs( // We need to us a non-nullable version for mapping since we're just mapping based on raw java // type vars, but then can re-copy nullability back if it is found. val resolvedType = targetMappings[unwrappedType.name] - ?.copy(nullable = unwrappedType.isNullable) - ?: unwrappedType + ?.copy(nullable = unwrappedType.isNullable) + ?: unwrappedType return when { resolvedType !is TypeVariableName -> resolvedType @@ -336,29 +369,29 @@ private fun resolveTypeArgs( /** Returns the properties declared by `typeElement`. */ @KotlinPoetMetadataPreview private fun declaredProperties( - constructor: TargetConstructor, - kotlinApi: TypeSpec, - allowedTypeVars: Set, - currentClass: ClassName, - resolvedTypes: List + constructor: TargetConstructor, + kotlinApi: TypeSpec, + allowedTypeVars: Set, + currentClass: ClassName, + resolvedTypes: List ): Map { val result = mutableMapOf() for (initialProperty in kotlinApi.propertySpecs) { val resolvedType = resolveTypeArgs( - targetClass = currentClass, - propertyType = initialProperty.type, - resolvedTypes = resolvedTypes, - allowedTypeVars = allowedTypeVars + targetClass = currentClass, + propertyType = initialProperty.type, + resolvedTypes = resolvedTypes, + allowedTypeVars = allowedTypeVars ) val property = initialProperty.toBuilder(type = resolvedType).build() val name = property.name val parameter = constructor.parameters[name] result[name] = TargetProperty( - propertySpec = property, - parameter = parameter, - visibility = property.modifiers.visibility(), - jsonName = parameter?.jsonName ?: property.annotations.jsonName() + propertySpec = property, + parameter = parameter, + visibility = property.modifiers.visibility(), + jsonName = parameter?.jsonName ?: property.annotations.jsonName() ?: name.escapeDollarSigns() ) } @@ -370,9 +403,9 @@ private val TargetProperty.isTransient get() = propertySpec.annotations.any { it private val TargetProperty.isSettable get() = propertySpec.mutable || parameter != null private val TargetProperty.isVisible: Boolean get() { - return visibility == KModifier.INTERNAL - || visibility == KModifier.PROTECTED - || visibility == KModifier.PUBLIC + return visibility == KModifier.INTERNAL || + visibility == KModifier.PROTECTED || + visibility == KModifier.PUBLIC } /** @@ -380,23 +413,28 @@ private val TargetProperty.isVisible: Boolean * cannot be used with code gen, or if no codegen is necessary for this property. */ internal fun TargetProperty.generator( - messager: Messager, - sourceElement: TypeElement, - elements: Elements + messager: Messager, + sourceElement: TypeElement, + elements: Elements ): PropertyGenerator? { if (isTransient) { if (!hasDefault) { messager.printMessage( - ERROR, "No default value for transient property $name", - sourceElement) + ERROR, + "No default value for transient property $name", + sourceElement + ) return null } return PropertyGenerator(this, DelegateKey(type, emptyList()), true) } if (!isVisible) { - messager.printMessage(ERROR, "property $name is not visible", - sourceElement) + messager.printMessage( + ERROR, + "property $name is not visible", + sourceElement + ) return null } @@ -410,29 +448,35 @@ internal fun TargetProperty.generator( val qualifierRawType = jsonQualifier.typeName.rawType() // Check Java types since that covers both Java and Kotlin annotations. val annotationElement = elements.getTypeElement(qualifierRawType.canonicalName) - ?: continue + ?: continue annotationElement.getAnnotation(Retention::class.java)?.let { if (it.value != RetentionPolicy.RUNTIME) { - messager.printMessage(ERROR, - "JsonQualifier @${qualifierRawType.simpleName} must have RUNTIME retention") + messager.printMessage( + ERROR, + "JsonQualifier @${qualifierRawType.simpleName} must have RUNTIME retention" + ) } } annotationElement.getAnnotation(Target::class.java)?.let { if (ElementType.FIELD !in it.value) { - messager.printMessage(ERROR, - "JsonQualifier @${qualifierRawType.simpleName} must support FIELD target") + messager.printMessage( + ERROR, + "JsonQualifier @${qualifierRawType.simpleName} must support FIELD target" + ) } } } val jsonQualifierSpecs = qualifiers.map { it.toBuilder() - .useSiteTarget(AnnotationSpec.UseSiteTarget.FIELD) - .build() + .useSiteTarget(AnnotationSpec.UseSiteTarget.FIELD) + .build() } - return PropertyGenerator(this, - DelegateKey(type, jsonQualifierSpecs)) + return PropertyGenerator( + this, + DelegateKey(type, jsonQualifierSpecs) + ) } private fun List?.qualifiers(elements: Elements): Set { @@ -478,7 +522,7 @@ internal fun TypeName.unwrapTypeAlias(): TypeName { internal val TypeElement.metadata: Metadata get() { return getAnnotation(Metadata::class.java) - ?: throw IllegalStateException("Not a kotlin type! $this") + ?: throw IllegalStateException("Not a kotlin type! $this") } private fun Sequence<*>.cast(): Sequence { diff --git a/kotlin/codegen/src/test/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessorTest.kt b/kotlin/codegen/src/test/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessorTest.kt index fbf28888e..07c0f621b 100644 --- a/kotlin/codegen/src/test/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessorTest.kt +++ b/kotlin/codegen/src/test/java/com/squareup/moshi/kotlin/codegen/JsonClassCodegenProcessorTest.kt @@ -41,10 +41,12 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun privateConstructor() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) class PrivateConstructor private constructor(var a: Int, var b: Int) { fun a() = a @@ -54,7 +56,8 @@ class JsonClassCodegenProcessorTest { } } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains("constructor is not internal or public") } @@ -62,14 +65,17 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun privateConstructorParameter() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) class PrivateConstructorParameter(private var a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains("property a is not visible") } @@ -77,7 +83,9 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun privateProperties() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass @@ -87,7 +95,8 @@ class JsonClassCodegenProcessorTest { private var b: Int = -1 } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains("property a is not visible") } @@ -95,226 +104,279 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun interfacesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) interface Interface """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to Interface: must be a Kotlin class") + "error: @JsonClass can't be applied to Interface: must be a Kotlin class" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun interfacesDoNotErrorWhenGeneratorNotSet() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true, generator="customGenerator") interface Interface """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun abstractClassesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) abstract class AbstractClass(val a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to AbstractClass: must not be abstract") + "error: @JsonClass can't be applied to AbstractClass: must not be abstract" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun sealedClassesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) sealed class SealedClass(val a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to SealedClass: must not be sealed") + "error: @JsonClass can't be applied to SealedClass: must not be sealed" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun innerClassesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + class Outer { @JsonClass(generateAdapter = true) inner class InnerClass(val a: Int) } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to Outer.InnerClass: must not be an inner class") + "error: @JsonClass can't be applied to Outer.InnerClass: must not be an inner class" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun enumClassesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) enum class KotlinEnum { A, B } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass with 'generateAdapter = \"true\"' can't be applied to KotlinEnum: code gen for enums is not supported or necessary") + "error: @JsonClass with 'generateAdapter = \"true\"' can't be applied to KotlinEnum: code gen for enums is not supported or necessary" + ) } // Annotation processors don't get called for local classes, so we don't have the opportunity to @Ignore @Test fun localClassesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + fun outer() { @JsonClass(generateAdapter = true) class LocalClass(val a: Int) } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to LocalClass: must not be local") + "error: @JsonClass can't be applied to LocalClass: must not be local" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun privateClassesNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) private class PrivateClass(val a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to PrivateClass: must be internal or public") + "error: @JsonClass can't be applied to PrivateClass: must be internal or public" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun objectDeclarationsNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) object ObjectDeclaration { var a = 5 } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to ObjectDeclaration: must be a Kotlin class") + "error: @JsonClass can't be applied to ObjectDeclaration: must be a Kotlin class" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun objectExpressionsNotSupported() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) val expression = object : Any() { var a = 5 } """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: @JsonClass can't be applied to getExpression\$annotations(): must be a Kotlin class") + "error: @JsonClass can't be applied to getExpression\$annotations(): must be a Kotlin class" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun requiredTransientConstructorParameterFails() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) class RequiredTransientConstructorParameter(@Transient var a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: No default value for transient property a") + "error: No default value for transient property a" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun nonPropertyConstructorParameter() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) class NonPropertyConstructorParameter(a: Int, val b: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains( - "error: No property for required constructor parameter a") + "error: No property for required constructor parameter a" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun badGeneratedAnnotation() { - val result = prepareCompilation(kotlin("source.kt", + val result = prepareCompilation( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + @JsonClass(generateAdapter = true) data class Foo(val a: Int) """ - )).apply { + ) + ).apply { kaptArgs[JsonClassCodegenProcessor.OPTION_GENERATED] = "javax.annotation.GeneratedBlerg" }.compile() assertThat(result.messages).contains( - "Invalid option value for ${JsonClassCodegenProcessor.OPTION_GENERATED}") + "Invalid option value for ${JsonClassCodegenProcessor.OPTION_GENERATED}" + ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun multipleErrors() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass @@ -324,7 +386,8 @@ class JsonClassCodegenProcessorTest { @JsonClass(generateAdapter = true) class Class2(private var c: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains("property a is not visible") assertThat(result.messages).contains("property c is not visible") @@ -333,7 +396,9 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun extendPlatformType() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass import java.util.Date @@ -341,31 +406,37 @@ class JsonClassCodegenProcessorTest { @JsonClass(generateAdapter = true) class ExtendsPlatformClass(var a: Int) : Date() """ - )) + ) + ) assertThat(result.messages).contains("supertype java.util.Date is not a Kotlin type") } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun extendJavaType() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass import com.squareup.moshi.kotlin.codegen.JavaSuperclass - + @JsonClass(generateAdapter = true) class ExtendsJavaType(var b: Int) : JavaSuperclass() """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages) - .contains("supertype com.squareup.moshi.kotlin.codegen.JavaSuperclass is not a Kotlin type") + .contains("supertype com.squareup.moshi.kotlin.codegen.JavaSuperclass is not a Kotlin type") } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun nonFieldApplicableQualifier() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonQualifier @@ -382,7 +453,8 @@ class JsonClassCodegenProcessorTest { @JsonClass(generateAdapter = true) class ClassWithQualifier(@UpperCase val a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains("JsonQualifier @UpperCase must support FIELD target") } @@ -390,7 +462,9 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun nonRuntimeQualifier() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonQualifier @@ -408,7 +482,8 @@ class JsonClassCodegenProcessorTest { @JsonClass(generateAdapter = true) class ClassWithQualifier(@UpperCase val a: Int) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) assertThat(result.messages).contains("JsonQualifier @UpperCase must have RUNTIME retention") } @@ -416,37 +491,42 @@ class JsonClassCodegenProcessorTest { @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun `TypeAliases with the same backing type should share the same adapter`() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ import com.squareup.moshi.JsonClass - + typealias FirstName = String typealias LastName = String @JsonClass(generateAdapter = true) data class Person(val firstName: FirstName, val lastName: LastName, val hairColor: String) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) // We're checking here that we only generate one `stringAdapter` that's used for both the // regular string properties as well as the the aliased ones. val adapterClass = result.classLoader.loadClass("PersonJsonAdapter").kotlin assertThat(adapterClass.declaredMemberProperties.map { it.returnType }).containsExactly( - JsonReader.Options::class.createType(), - JsonAdapter::class.parameterizedBy(String::class) + JsonReader.Options::class.createType(), + JsonAdapter::class.parameterizedBy(String::class) ) } @Ignore("Temporarily ignored pending a new KCT release https://github.com/tschuchortdev/kotlin-compile-testing/issues/51") @Test fun `Processor should generate comprehensive proguard rules`() { - val result = compile(kotlin("source.kt", + val result = compile( + kotlin( + "source.kt", """ package testPackage import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonQualifier - + typealias FirstName = String typealias LastName = String @@ -473,7 +553,7 @@ class JsonClassCodegenProcessorTest { @JsonClass(generateAdapter = true) data class Complex(val firstName: FirstName = "", @MyQualifier val names: MutableList, val genericProp: T) - + object NestedType { @JsonQualifier annotation class NestedQualifier @@ -552,36 +632,44 @@ class JsonClassCodegenProcessorTest { val arg65: Long = 65 ) """ - )) + ) + ) assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) result.generatedFiles.filter { it.extension == "pro" }.forEach { generatedFile -> when (generatedFile.nameWithoutExtension) { - "moshi-testPackage.Aliases" -> assertThat(generatedFile).hasContent(""" + "moshi-testPackage.Aliases" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.Aliases -keepnames class testPackage.Aliases -if class testPackage.Aliases -keep class testPackage.AliasesJsonAdapter { public (com.squareup.moshi.Moshi); } - """.trimIndent()) - "moshi-testPackage.Simple" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.Simple" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.Simple -keepnames class testPackage.Simple -if class testPackage.Simple -keep class testPackage.SimpleJsonAdapter { public (com.squareup.moshi.Moshi); } - """.trimIndent()) - "moshi-testPackage.Generic" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.Generic" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.Generic -keepnames class testPackage.Generic -if class testPackage.Generic -keep class testPackage.GenericJsonAdapter { public (com.squareup.moshi.Moshi,java.lang.reflect.Type[]); } - """.trimIndent()) - "moshi-testPackage.UsingQualifiers" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.UsingQualifiers" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.UsingQualifiers -keepnames class testPackage.UsingQualifiers -if class testPackage.UsingQualifiers @@ -591,16 +679,20 @@ class JsonClassCodegenProcessorTest { } -if class testPackage.UsingQualifiers -keep @interface testPackage.MyQualifier - """.trimIndent()) - "moshi-testPackage.MixedTypes" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.MixedTypes" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.MixedTypes -keepnames class testPackage.MixedTypes -if class testPackage.MixedTypes -keep class testPackage.MixedTypesJsonAdapter { public (com.squareup.moshi.Moshi); } - """.trimIndent()) - "moshi-testPackage.DefaultParams" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.DefaultParams" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.DefaultParams -keepnames class testPackage.DefaultParams -if class testPackage.DefaultParams @@ -613,8 +705,10 @@ class JsonClassCodegenProcessorTest { -keepclassmembers class testPackage.DefaultParams { public synthetic (java.lang.String,int,kotlin.jvm.internal.DefaultConstructorMarker); } - """.trimIndent()) - "moshi-testPackage.Complex" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.Complex" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.Complex -keepnames class testPackage.Complex -if class testPackage.Complex @@ -630,8 +724,10 @@ class JsonClassCodegenProcessorTest { -keepclassmembers class testPackage.Complex { public synthetic (java.lang.String,java.util.List,java.lang.Object,int,kotlin.jvm.internal.DefaultConstructorMarker); } - """.trimIndent()) - "moshi-testPackage.MultipleMasks" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.MultipleMasks" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.MultipleMasks -keepnames class testPackage.MultipleMasks -if class testPackage.MultipleMasks @@ -644,8 +740,10 @@ class JsonClassCodegenProcessorTest { -keepclassmembers class testPackage.MultipleMasks { public synthetic (long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,int,int,int,kotlin.jvm.internal.DefaultConstructorMarker); } - """.trimIndent()) - "moshi-testPackage.NestedType.NestedSimple" -> assertThat(generatedFile).hasContent(""" + """.trimIndent() + ) + "moshi-testPackage.NestedType.NestedSimple" -> assertThat(generatedFile).hasContent( + """ -if class testPackage.NestedType${'$'}NestedSimple -keepnames class testPackage.NestedType${'$'}NestedSimple -if class testPackage.NestedType${'$'}NestedSimple @@ -655,7 +753,8 @@ class JsonClassCodegenProcessorTest { } -if class testPackage.NestedType${'$'}NestedSimple -keep @interface testPackage.NestedType${'$'}NestedQualifier - """.trimIndent()) + """.trimIndent() + ) else -> error("Unexpected proguard file! ${generatedFile.name}") } } @@ -663,13 +762,13 @@ class JsonClassCodegenProcessorTest { private fun prepareCompilation(vararg sourceFiles: SourceFile): KotlinCompilation { return KotlinCompilation() - .apply { - workingDir = temporaryFolder.root - annotationProcessors = listOf(JsonClassCodegenProcessor()) - inheritClassPath = true - sources = sourceFiles.asList() - verbose = false - } + .apply { + workingDir = temporaryFolder.root + annotationProcessors = listOf(JsonClassCodegenProcessor()) + inheritClassPath = true + sources = sourceFiles.asList() + verbose = false + } } private fun compile(vararg sourceFiles: SourceFile): KotlinCompilation.Result { @@ -682,12 +781,11 @@ class JsonClassCodegenProcessorTest { private fun KClassifier.parameterizedBy(vararg types: KType): KType { return createType( - types.map { it.asProjection() } + types.map { it.asProjection() } ) } private fun KType.asProjection(variance: KVariance? = INVARIANT): KTypeProjection { return KTypeProjection(variance, this) } - } diff --git a/kotlin/reflect/src/main/java/com/squareup/moshi/KotlinJsonAdapter.kt b/kotlin/reflect/src/main/java/com/squareup/moshi/KotlinJsonAdapter.kt index ee2d0fb8a..d71dba5bd 100644 --- a/kotlin/reflect/src/main/java/com/squareup/moshi/KotlinJsonAdapter.kt +++ b/kotlin/reflect/src/main/java/com/squareup/moshi/KotlinJsonAdapter.kt @@ -18,8 +18,8 @@ package com.squareup.moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory @Deprecated( - message = "this moved to avoid a package name conflict in the Java Platform Module System.", - replaceWith = ReplaceWith("com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory") + message = "this moved to avoid a package name conflict in the Java Platform Module System.", + replaceWith = ReplaceWith("com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory") ) -class KotlinJsonAdapterFactory - : JsonAdapter.Factory by KotlinJsonAdapterFactory() +class KotlinJsonAdapterFactory : + JsonAdapter.Factory by KotlinJsonAdapterFactory() diff --git a/kotlin/reflect/src/main/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapter.kt b/kotlin/reflect/src/main/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapter.kt index a7ec42d86..c029e37c2 100644 --- a/kotlin/reflect/src/main/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapter.kt +++ b/kotlin/reflect/src/main/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapter.kt @@ -28,7 +28,6 @@ import com.squareup.moshi.internal.Util.resolve import java.lang.reflect.Modifier import java.lang.reflect.Type import java.util.AbstractMap.SimpleEntry -import kotlin.collections.Map.Entry import kotlin.reflect.KFunction import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KParameter @@ -78,16 +77,17 @@ internal class KotlinJsonAdapter( val propertyIndex = binding.propertyIndex if (values[propertyIndex] !== ABSENT_VALUE) { throw JsonDataException( - "Multiple values for '${binding.property.name}' at ${reader.path}") + "Multiple values for '${binding.property.name}' at ${reader.path}" + ) } values[propertyIndex] = binding.adapter.fromJson(reader) if (values[propertyIndex] == null && !binding.property.returnType.isMarkedNullable) { throw Util.unexpectedNull( - binding.property.name, - binding.jsonName, - reader + binding.property.name, + binding.jsonName, + reader ) } } @@ -98,9 +98,9 @@ internal class KotlinJsonAdapter( if (values[i] === ABSENT_VALUE && !constructor.parameters[i].isOptional) { if (!constructor.parameters[i].type.isMarkedNullable) { throw Util.missingProperty( - constructor.parameters[i].name, - allBindings[i]?.jsonName, - reader + constructor.parameters[i].name, + allBindings[i]?.jsonName, + reader ) } values[i] = null // Replace absent with null. @@ -154,8 +154,8 @@ internal class KotlinJsonAdapter( /** A simple [Map] that uses parameter indexes instead of sorting or hashing. */ class IndexedParameterMap( - private val parameterKeys: List, - private val parameterValues: Array + private val parameterKeys: List, + private val parameterValues: Array ) : AbstractMutableMap() { override fun put(key: KParameter, value: Any?): Any? = null @@ -180,110 +180,113 @@ internal class KotlinJsonAdapter( } class KotlinJsonAdapterFactory : JsonAdapter.Factory { - override fun create(type: Type, annotations: MutableSet, moshi: Moshi) - : JsonAdapter<*>? { - if (annotations.isNotEmpty()) return null - - val rawType = Types.getRawType(type) - if (rawType.isInterface) return null - if (rawType.isEnum) return null - if (!rawType.isAnnotationPresent(KOTLIN_METADATA)) return null - if (Util.isPlatformType(rawType)) return null - try { - val generatedAdapter = generatedAdapter(moshi, type, rawType) - if (generatedAdapter != null) { - return generatedAdapter - } - } catch (e: RuntimeException) { - if (e.cause !is ClassNotFoundException) { - throw e + override fun create(type: Type, annotations: MutableSet, moshi: Moshi): + JsonAdapter<*>? { + if (annotations.isNotEmpty()) return null + + val rawType = Types.getRawType(type) + if (rawType.isInterface) return null + if (rawType.isEnum) return null + if (!rawType.isAnnotationPresent(KOTLIN_METADATA)) return null + if (Util.isPlatformType(rawType)) return null + try { + val generatedAdapter = generatedAdapter(moshi, type, rawType) + if (generatedAdapter != null) { + return generatedAdapter + } + } catch (e: RuntimeException) { + if (e.cause !is ClassNotFoundException) { + throw e + } + // Fall back to a reflective adapter when the generated adapter is not found. } - // Fall back to a reflective adapter when the generated adapter is not found. - } - require(!rawType.isLocalClass) { - "Cannot serialize local class or object expression ${rawType.name}" - } - val rawTypeKotlin = rawType.kotlin - require(!rawTypeKotlin.isAbstract) { - "Cannot serialize abstract class ${rawType.name}" - } - require(!rawTypeKotlin.isInner) { - "Cannot serialize inner class ${rawType.name}" - } - require(rawTypeKotlin.objectInstance == null) { - "Cannot serialize object declaration ${rawType.name}" - } - require(!rawTypeKotlin.isSealed) { - "Cannot reflectively serialize sealed class ${rawType.name}. Please register an adapter." - } + require(!rawType.isLocalClass) { + "Cannot serialize local class or object expression ${rawType.name}" + } + val rawTypeKotlin = rawType.kotlin + require(!rawTypeKotlin.isAbstract) { + "Cannot serialize abstract class ${rawType.name}" + } + require(!rawTypeKotlin.isInner) { + "Cannot serialize inner class ${rawType.name}" + } + require(rawTypeKotlin.objectInstance == null) { + "Cannot serialize object declaration ${rawType.name}" + } + require(!rawTypeKotlin.isSealed) { + "Cannot reflectively serialize sealed class ${rawType.name}. Please register an adapter." + } - val constructor = rawTypeKotlin.primaryConstructor ?: return null - val parametersByName = constructor.parameters.associateBy { it.name } - constructor.isAccessible = true + val constructor = rawTypeKotlin.primaryConstructor ?: return null + val parametersByName = constructor.parameters.associateBy { it.name } + constructor.isAccessible = true - val bindingsByName = LinkedHashMap>() + val bindingsByName = LinkedHashMap>() - for (property in rawTypeKotlin.memberProperties) { - val parameter = parametersByName[property.name] + for (property in rawTypeKotlin.memberProperties) { + val parameter = parametersByName[property.name] - if (Modifier.isTransient(property.javaField?.modifiers ?: 0)) { - require(parameter == null || parameter.isOptional) { - "No default value for transient constructor $parameter" + if (Modifier.isTransient(property.javaField?.modifiers ?: 0)) { + require(parameter == null || parameter.isOptional) { + "No default value for transient constructor $parameter" + } + continue } - continue - } - require(parameter == null || parameter.type == property.returnType) { - "'${property.name}' has a constructor parameter of type ${parameter!!.type} but a property of type ${property.returnType}." - } + require(parameter == null || parameter.type == property.returnType) { + "'${property.name}' has a constructor parameter of type ${parameter!!.type} but a property of type ${property.returnType}." + } - if (property !is KMutableProperty1 && parameter == null) continue + if (property !is KMutableProperty1 && parameter == null) continue - property.isAccessible = true - val allAnnotations = property.annotations.toMutableList() - var jsonAnnotation = property.findAnnotation() + property.isAccessible = true + val allAnnotations = property.annotations.toMutableList() + var jsonAnnotation = property.findAnnotation() - if (parameter != null) { - allAnnotations += parameter.annotations - if (jsonAnnotation == null) { - jsonAnnotation = parameter.findAnnotation() + if (parameter != null) { + allAnnotations += parameter.annotations + if (jsonAnnotation == null) { + jsonAnnotation = parameter.findAnnotation() + } } - } - val name = jsonAnnotation?.name ?: property.name - val resolvedPropertyType = resolve(type, rawType, property.returnType.javaType) - val adapter = moshi.adapter( - resolvedPropertyType, Util.jsonAnnotations(allAnnotations.toTypedArray()), property.name) + val name = jsonAnnotation?.name ?: property.name + val resolvedPropertyType = resolve(type, rawType, property.returnType.javaType) + val adapter = moshi.adapter( + resolvedPropertyType, + Util.jsonAnnotations(allAnnotations.toTypedArray()), + property.name + ) - @Suppress("UNCHECKED_CAST") - bindingsByName[property.name] = KotlinJsonAdapter.Binding( + @Suppress("UNCHECKED_CAST") + bindingsByName[property.name] = KotlinJsonAdapter.Binding( name, jsonAnnotation?.name ?: name, adapter, property as KProperty1, parameter, parameter?.index ?: -1 - ) - } + ) + } - val bindings = ArrayList?>() + val bindings = ArrayList?>() - for (parameter in constructor.parameters) { - val binding = bindingsByName.remove(parameter.name) - require(binding != null || parameter.isOptional) { - "No property for required constructor $parameter" + for (parameter in constructor.parameters) { + val binding = bindingsByName.remove(parameter.name) + require(binding != null || parameter.isOptional) { + "No property for required constructor $parameter" + } + bindings += binding } - bindings += binding - } - var index = bindings.size - for (bindingByName in bindingsByName) { - bindings += bindingByName.value.copy(propertyIndex = index++) - } + var index = bindings.size + for (bindingByName in bindingsByName) { + bindings += bindingByName.value.copy(propertyIndex = index++) + } - val nonTransientBindings = bindings.filterNotNull() - val options = JsonReader.Options.of(*nonTransientBindings.map { it.name }.toTypedArray()) - return KotlinJsonAdapter(constructor, bindings, nonTransientBindings, options).nullSafe() - } + val nonTransientBindings = bindings.filterNotNull() + val options = JsonReader.Options.of(*nonTransientBindings.map { it.name }.toTypedArray()) + return KotlinJsonAdapter(constructor, bindings, nonTransientBindings, options).nullSafe() + } } diff --git a/kotlin/reflect/src/test/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt b/kotlin/reflect/src/test/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt index 6d0755996..d8a2c4837 100644 --- a/kotlin/reflect/src/test/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt +++ b/kotlin/reflect/src/test/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt @@ -12,11 +12,11 @@ class KotlinJsonAdapterTest { @Test fun fallsBackToReflectiveAdapterWithoutCodegen() { val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + .add(KotlinJsonAdapterFactory()) + .build() val adapter = moshi.adapter(Data::class.java) assertThat(adapter.toString()).isEqualTo( - "KotlinJsonAdapter(com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest.Data).nullSafe()" + "KotlinJsonAdapter(com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest.Data).nullSafe()" ) } } diff --git a/kotlin/tests/build.gradle.kts b/kotlin/tests/build.gradle.kts index 038c0a7d8..bd34e1f2c 100644 --- a/kotlin/tests/build.gradle.kts +++ b/kotlin/tests/build.gradle.kts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -23,9 +24,9 @@ plugins { tasks.withType().configureEach { kotlinOptions { freeCompilerArgs = listOf( - "-Werror", - "-Xopt-in=kotlin.ExperimentalStdlibApi", - "-Xinline-classes" + "-Werror", + "-Xopt-in=kotlin.ExperimentalStdlibApi", + "-Xinline-classes" ) } } diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DefaultConstructorTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DefaultConstructorTest.kt index 15712f11f..6ee6ab015 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DefaultConstructorTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DefaultConstructorTest.kt @@ -8,9 +8,10 @@ class DefaultConstructorTest { @Test fun minimal() { val expected = TestClass("requiredClass") - val json = """{"required":"requiredClass"}""" + val json = + """{"required":"requiredClass"}""" val instance = Moshi.Builder().build().adapter(TestClass::class.java) - .fromJson(json)!! + .fromJson(json)!! check(instance == expected) { "No match:\nActual : $instance\nExpected: $expected" } @@ -18,9 +19,10 @@ class DefaultConstructorTest { @Test fun allSet() { val expected = TestClass("requiredClass", "customOptional", 4, "setDynamic", 5, 6) - val json = """{"required":"requiredClass","optional":"customOptional","optional2":4,"dynamicSelfReferenceOptional":"setDynamic","dynamicOptional":5,"dynamicInlineOptional":6}""" + val json = + """{"required":"requiredClass","optional":"customOptional","optional2":4,"dynamicSelfReferenceOptional":"setDynamic","dynamicOptional":5,"dynamicInlineOptional":6}""" val instance = Moshi.Builder().build().adapter(TestClass::class.java) - .fromJson(json)!! + .fromJson(json)!! check(instance == expected) { "No match:\nActual : $instance\nExpected: $expected" } @@ -28,9 +30,10 @@ class DefaultConstructorTest { @Test fun customDynamic() { val expected = TestClass("requiredClass", "customOptional") - val json = """{"required":"requiredClass","optional":"customOptional"}""" + val json = + """{"required":"requiredClass","optional":"customOptional"}""" val instance = Moshi.Builder().build().adapter(TestClass::class.java) - .fromJson(json)!! + .fromJson(json)!! check(instance == expected) { "No match:\nActual : $instance\nExpected: $expected" } @@ -39,20 +42,20 @@ class DefaultConstructorTest { @JsonClass(generateAdapter = true) data class TestClass( - val required: String, - val optional: String = "optional", - val optional2: Int = 2, - val dynamicSelfReferenceOptional: String = required, - val dynamicOptional: Int = createInt(), - val dynamicInlineOptional: Int = createInlineInt() + val required: String, + val optional: String = "optional", + val optional2: Int = 2, + val dynamicSelfReferenceOptional: String = required, + val dynamicOptional: Int = createInt(), + val dynamicInlineOptional: Int = createInlineInt() ) // Regression test for https://github.com/square/moshi/issues/905 // Just needs to compile @JsonClass(generateAdapter = true) data class GenericTestClassWithDefaults( - val input: String = "", - val genericInput: T + val input: String = "", + val genericInput: T ) private fun createInt(): Int { diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DualKotlinTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DualKotlinTest.kt index 3a5de6d28..2a1a7342b 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DualKotlinTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/DualKotlinTest.kt @@ -32,22 +32,23 @@ class DualKotlinTest(useReflection: Boolean) { @JvmStatic fun parameters(): List> { return listOf( - arrayOf(true), - arrayOf(false) + arrayOf(true), + arrayOf(false) ) } } @Suppress("UNCHECKED_CAST") private val moshi = Moshi.Builder() - .apply { - if (useReflection) { - add(KotlinJsonAdapterFactory()) - add(object : Factory { + .apply { + if (useReflection) { + add(KotlinJsonAdapterFactory()) + add( + object : Factory { override fun create( - type: Type, - annotations: MutableSet, - moshi: Moshi + type: Type, + annotations: MutableSet, + moshi: Moshi ): JsonAdapter<*>? { // Prevent falling back to generated adapter lookup val rawType = Types.getRawType(type) @@ -57,11 +58,11 @@ class DualKotlinTest(useReflection: Boolean) { } return moshi.nextAdapter(this, type, annotations) } - }) - } + } + ) } - .build() - + } + .build() @Test fun requiredValueAbsent() { val jsonAdapter = moshi.adapter() @@ -107,13 +108,15 @@ class DualKotlinTest(useReflection: Boolean) { @Test fun nonNullPropertySetToNullFromAdapterFailsWithJsonDataException() { val jsonAdapter = moshi.newBuilder() - .add(object { + .add( + object { @Suppress("UNUSED_PARAMETER") @FromJson fun fromJson(string: String): String? = null - }) - .build() - .adapter() + } + ) + .build() + .adapter() try { //language=JSON @@ -143,13 +146,15 @@ class DualKotlinTest(useReflection: Boolean) { @Test fun nonNullPropertyWithJsonNameSetToNullFromAdapterFailsWithJsonDataException() { val jsonAdapter = moshi.newBuilder() - .add(object { + .add( + object { @Suppress("UNUSED_PARAMETER") @FromJson fun fromJson(string: String): String? = null - }) - .build() - .adapter() + } + ) + .build() + .adapter() try { //language=JSON @@ -179,13 +184,15 @@ class DualKotlinTest(useReflection: Boolean) { @Test fun nonNullConstructorParameterCalledWithNullFromAdapterFailsWithJsonDataException() { val jsonAdapter = moshi.newBuilder() - .add(object { + .add( + object { @Suppress("UNUSED_PARAMETER") @FromJson fun fromJson(string: String): String? = null - }) - .build() - .adapter() + } + ) + .build() + .adapter() try { //language=JSON @@ -207,7 +214,8 @@ class DualKotlinTest(useReflection: Boolean) { @Test fun delegatesToInstalledAdaptersBeforeNullChecking() { val localMoshi = moshi.newBuilder() - .add(object { + .add( + object { @FromJson fun fromJson(@Nullable string: String?): String { return string ?: "fallback" @@ -217,23 +225,30 @@ class DualKotlinTest(useReflection: Boolean) { fun toJson(@Nullable value: String?): String { return value ?: "fallback" } - }) - .build() + } + ) + .build() val hasNonNullConstructorParameterAdapter = - localMoshi.adapter() - assertThat(hasNonNullConstructorParameterAdapter - //language=JSON - .fromJson("{\"a\":null}")).isEqualTo(HasNonNullConstructorParameter("fallback")) + localMoshi.adapter() + assertThat( + hasNonNullConstructorParameterAdapter +//language=JSON + .fromJson("{\"a\":null}") + ).isEqualTo(HasNonNullConstructorParameter("fallback")) val hasNullableConstructorParameterAdapter = - localMoshi.adapter() - assertThat(hasNullableConstructorParameterAdapter - //language=JSON - .fromJson("{\"a\":null}")).isEqualTo(HasNullableConstructorParameter("fallback")) - assertThat(hasNullableConstructorParameterAdapter - //language=JSON - .toJson(HasNullableConstructorParameter(null))).isEqualTo("{\"a\":\"fallback\"}") + localMoshi.adapter() + assertThat( + hasNullableConstructorParameterAdapter +//language=JSON + .fromJson("{\"a\":null}") + ).isEqualTo(HasNullableConstructorParameter("fallback")) + assertThat( + hasNullableConstructorParameterAdapter +//language=JSON + .toJson(HasNullableConstructorParameter(null)) + ).isEqualTo("{\"a\":\"fallback\"}") } @JsonClass(generateAdapter = true) @@ -258,10 +273,12 @@ class DualKotlinTest(useReflection: Boolean) { val inline = InlineClass(5) - val expectedJson = """{"i":5}""" + val expectedJson = + """{"i":5}""" assertThat(adapter.toJson(inline)).isEqualTo(expectedJson) - val testJson = """{"i":6}""" + val testJson = + """{"i":6}""" val result = adapter.fromJson(testJson)!! assertThat(result.i).isEqualTo(6) } @@ -275,11 +292,13 @@ class DualKotlinTest(useReflection: Boolean) { val consumer = InlineConsumer(InlineClass(23)) @Language("JSON") - val expectedJson = """{"inline":{"i":23}}""" + val expectedJson = + """{"inline":{"i":23}}""" assertThat(adapter.toJson(consumer)).isEqualTo(expectedJson) @Language("JSON") - val testJson = """{"inline":{"i":42}}""" + val testJson = + """{"inline":{"i":42}}""" val result = adapter.fromJson(testJson)!! assertThat(result.inline.i).isEqualTo(42) } @@ -289,7 +308,8 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"text":"text"}""" + val testJson = + """{"text":"text"}""" assertThat(adapter.toJson(TextAssetMetaData("text"))).isEqualTo(testJson) @@ -308,7 +328,8 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"test":"text"}""" + val testJson = + """{"test":"text"}""" assertThat(adapter.toJson(InternalAbstractProperty("text"))).isEqualTo(testJson) @@ -338,7 +359,8 @@ class DualKotlinTest(useReflection: Boolean) { assertThat(adapter.toJson(MultipleConstructorsB(6))).isEqualTo("""{"f":{"f":6},"b":6}""") @Language("JSON") - val testJson = """{"b":6}""" + val testJson = + """{"b":6}""" val result = adapter.fromJson(testJson)!! assertThat(result.b).isEqualTo(6) } @@ -348,14 +370,15 @@ class DualKotlinTest(useReflection: Boolean) { @JsonClass(generateAdapter = true) class MultipleConstructorsB(val f: MultipleConstructorsA = MultipleConstructorsA(5), val b: Int) { - constructor(f: Int, b: Int = 6): this(MultipleConstructorsA(f), b) + constructor(f: Int, b: Int = 6) : this(MultipleConstructorsA(f), b) } @Test fun `multiple non-property parameters`() { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"prop":7}""" + val testJson = + """{"prop":7}""" assertThat(adapter.toJson(MultipleNonPropertyParameters(7))).isEqualTo(testJson) @@ -365,9 +388,9 @@ class DualKotlinTest(useReflection: Boolean) { @JsonClass(generateAdapter = true) class MultipleNonPropertyParameters( - val prop: Int, - param1: Int = 1, - param2: Int = 2 + val prop: Int, + param1: Int = 1, + param2: Int = 2 ) { init { // Ensure the params always uses their default value @@ -381,10 +404,11 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"prop":7}""" + val testJson = + """{"prop":7}""" assertThat(adapter.toJson(OnlyMultipleNonPropertyParameters().apply { prop = 7 })) - .isEqualTo(testJson) + .isEqualTo(testJson) val result = adapter.fromJson(testJson)!! assertThat(result.prop).isEqualTo(7) @@ -392,8 +416,8 @@ class DualKotlinTest(useReflection: Boolean) { @JsonClass(generateAdapter = true) class OnlyMultipleNonPropertyParameters( - param1: Int = 1, - param2: Int = 2 + param1: Int = 1, + param2: Int = 2 ) { init { // Ensure the params always uses their default value @@ -406,20 +430,21 @@ class DualKotlinTest(useReflection: Boolean) { @Test fun typeAliasUnwrapping() { val adapter = moshi - .newBuilder() - .add(Types.supertypeOf(Int::class.javaObjectType), moshi.adapter()) - .build() - .adapter() + .newBuilder() + .add(Types.supertypeOf(Int::class.javaObjectType), moshi.adapter()) + .build() + .adapter() @Language("JSON") - val testJson = """{"simpleClass":6,"parameterized":{"value":6},"wildcardIn":{"value":6},"wildcardOut":{"value":6},"complex":{"value":[{"value":6}]}}""" + val testJson = + """{"simpleClass":6,"parameterized":{"value":6},"wildcardIn":{"value":6},"wildcardOut":{"value":6},"complex":{"value":[{"value":6}]}}""" val testValue = TypeAliasUnwrapping( - simpleClass = 6, - parameterized = GenericClass(6), - wildcardIn = GenericClass(6), - wildcardOut = GenericClass(6), - complex = GenericClass(listOf(GenericClass(6))) + simpleClass = 6, + parameterized = GenericClass(6), + wildcardIn = GenericClass(6), + wildcardOut = GenericClass(6), + complex = GenericClass(listOf(GenericClass(6))) ) assertThat(adapter.toJson(testValue)).isEqualTo(testJson) @@ -429,11 +454,11 @@ class DualKotlinTest(useReflection: Boolean) { @JsonClass(generateAdapter = true) data class TypeAliasUnwrapping( - val simpleClass: TypeAlias, - val parameterized: GenericClass, - val wildcardIn: GenericClass, - val wildcardOut: GenericClass, - val complex: GenericClass? + val simpleClass: TypeAlias, + val parameterized: GenericClass, + val wildcardIn: GenericClass, + val wildcardOut: GenericClass, + val complex: GenericClass? ) // Regression test for https://github.com/square/moshi/issues/991 @@ -441,21 +466,22 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"objectType":"value","boolean":true,"byte":3,"char":"a","short":3,"int":3,"long":3,"float":3.2,"double":3.2}""" + val testJson = + """{"objectType":"value","boolean":true,"byte":3,"char":"a","short":3,"int":3,"long":3,"float":3.2,"double":3.2}""" val instance = NullablePrimitives( - objectType = "value", - boolean = true, - byte = 3, - char = 'a', - short = 3, - int = 3, - long = 3, - float = 3.2f, - double = 3.2 + objectType = "value", + boolean = true, + byte = 3, + char = 'a', + short = 3, + int = 3, + long = 3, + float = 3.2f, + double = 3.2 ) assertThat(adapter.toJson(instance)) - .isEqualTo(testJson) + .isEqualTo(testJson) val result = adapter.fromJson(testJson)!! assertThat(result).isEqualTo(instance) @@ -463,23 +489,23 @@ class DualKotlinTest(useReflection: Boolean) { @JsonClass(generateAdapter = true) data class NullablePrimitives( - val objectType: String = "", - val boolean: Boolean, - val nullableBoolean: Boolean? = null, - val byte: Byte, - val nullableByte: Byte? = null, - val char: Char, - val nullableChar: Char? = null, - val short: Short, - val nullableShort: Short? = null, - val int: Int, - val nullableInt: Int? = null, - val long: Long, - val nullableLong: Long? = null, - val float: Float, - val nullableFloat: Float? = null, - val double: Double, - val nullableDouble: Double? = null + val objectType: String = "", + val boolean: Boolean, + val nullableBoolean: Boolean? = null, + val byte: Byte, + val nullableByte: Byte? = null, + val char: Char, + val nullableChar: Char? = null, + val short: Short, + val nullableShort: Short? = null, + val int: Int, + val nullableInt: Int? = null, + val long: Long, + val nullableLong: Long? = null, + val float: Float, + val nullableFloat: Float? = null, + val double: Double, + val nullableDouble: Double? = null ) // Regression test for https://github.com/square/moshi/issues/990 @@ -487,10 +513,11 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"nullableList":null}""" + val testJson = + """{"nullableList":null}""" assertThat(adapter.serializeNulls().toJson(NullableList(null))) - .isEqualTo(testJson) + .isEqualTo(testJson) val result = adapter.fromJson(testJson)!! assertThat(result.nullableList).isNull() @@ -503,11 +530,12 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter() @Language("JSON") - val testJson = """{"aShouldBeNonNull":3,"nullableAShouldBeNullable":null,"redundantNullableAShouldBeNullable":null,"manuallyNullableAShouldBeNullable":null,"convolutedMultiNullableShouldBeNullable":null,"deepNestedNullableShouldBeNullable":null}""" + val testJson = + """{"aShouldBeNonNull":3,"nullableAShouldBeNullable":null,"redundantNullableAShouldBeNullable":null,"manuallyNullableAShouldBeNullable":null,"convolutedMultiNullableShouldBeNullable":null,"deepNestedNullableShouldBeNullable":null}""" val instance = TypeAliasNullability(3, null, null, null, null, null) assertThat(adapter.serializeNulls().toJson(instance)) - .isEqualTo(testJson) + .isEqualTo(testJson) val result = adapter.fromJson(testJson)!! assertThat(result).isEqualTo(instance) @@ -516,12 +544,12 @@ class DualKotlinTest(useReflection: Boolean) { @Suppress("REDUNDANT_NULLABLE") @JsonClass(generateAdapter = true) data class TypeAliasNullability( - val aShouldBeNonNull: A, - val nullableAShouldBeNullable: NullableA, - val redundantNullableAShouldBeNullable: NullableA?, - val manuallyNullableAShouldBeNullable: A?, - val convolutedMultiNullableShouldBeNullable: NullableB?, - val deepNestedNullableShouldBeNullable: E + val aShouldBeNonNull: A, + val nullableAShouldBeNullable: NullableA, + val redundantNullableAShouldBeNullable: NullableA?, + val manuallyNullableAShouldBeNullable: A?, + val convolutedMultiNullableShouldBeNullable: NullableB?, + val deepNestedNullableShouldBeNullable: E ) // Regression test for https://github.com/square/moshi/issues/1009 @@ -529,11 +557,12 @@ class DualKotlinTest(useReflection: Boolean) { val adapter = moshi.adapter>() @Language("JSON") - val testJson = """{"input":3}""" + val testJson = + """{"input":3}""" val instance = OutDeclaration(3) assertThat(adapter.serializeNulls().toJson(instance)) - .isEqualTo(testJson) + .isEqualTo(testJson) val result = adapter.fromJson(testJson)!! assertThat(result).isEqualTo(instance) diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/ComplexGenericsInheritanceTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/ComplexGenericsInheritanceTest.kt index 5459bd4e0..19153b7c3 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/ComplexGenericsInheritanceTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/ComplexGenericsInheritanceTest.kt @@ -18,7 +18,8 @@ class ComplexGenericsInheritanceTest { val adapter = moshi.adapter() @Language("JSON") - val json = """{"data":{"name":"foo"},"data2":"bar","data3":"baz"}""" + val json = + """{"data":{"name":"foo"},"data2":"bar","data3":"baz"}""" val instance = adapter.fromJson(json)!! val testInstance = PersonResponse().apply { @@ -33,7 +34,8 @@ class ComplexGenericsInheritanceTest { val adapter = moshi.adapter() @Language("JSON") - val json = """{"data":{"name":"foo"},"data2":"bar","data3":"baz"}""" + val json = + """{"data":{"name":"foo"},"data2":"bar","data3":"baz"}""" val instance = adapter.fromJson(json)!! val testInstance = NestedPersonResponse().apply { @@ -48,7 +50,8 @@ class ComplexGenericsInheritanceTest { val adapter = moshi.adapter>() @Language("JSON") - val json = """{"data":{"name":"foo"},"data2":"bar","data3":"baz"}""" + val json = + """{"data":{"name":"foo"},"data2":"bar","data3":"baz"}""" val instance = adapter.fromJson(json)!! val testInstance = UntypedNestedPersonResponse().apply { @@ -63,16 +66,17 @@ class ComplexGenericsInheritanceTest { val adapter = moshi.adapter>>() @Language("JSON") - val json = """{"layer4E":{"name":"layer4E"},"layer4F":{"data":{"name":"layer4F"},"data2":"layer4F","data3":"layer4F"},"layer3C":[1,2,3],"layer3D":"layer3D","layer2":"layer2","layer1":"layer1"}""" + val json = + """{"layer4E":{"name":"layer4E"},"layer4F":{"data":{"name":"layer4F"},"data2":"layer4F","data3":"layer4F"},"layer3C":[1,2,3],"layer3D":"layer3D","layer2":"layer2","layer1":"layer1"}""" val instance = adapter.fromJson(json)!! val testInstance = Layer4( - layer4E = Person("layer4E"), - layer4F = UntypedNestedPersonResponse().apply { - data = Person("layer4F") - data2 = "layer4F" - data3 = "layer4F" - } + layer4E = Person("layer4E"), + layer4F = UntypedNestedPersonResponse().apply { + data = Person("layer4F") + data2 = "layer4F" + data3 = "layer4F" + } ).apply { layer3C = listOf(1, 2, 3) layer3D = "layer3D" @@ -97,7 +101,8 @@ data class Person(val name: String) : Personable @JsonClass(generateAdapter = true) data class PersonResponse( - val extra: String? = null) : ResponseWithSettableProperty() + val extra: String? = null +) : ResponseWithSettableProperty() abstract class NestedResponse : ResponseWithSettableProperty() @@ -106,7 +111,7 @@ data class NestedPersonResponse(val extra: String? = null) : NestedResponse( - val extra: String? = null + val extra: String? = null ) : NestedResponse() interface LayerInterface @@ -126,6 +131,6 @@ abstract class Layer3 : Layer2() { @JsonClass(generateAdapter = true) data class Layer4( - val layer4E: E, - val layer4F: F? = null + val layer4E: E, + val layer4F: F? = null ) : Layer3, String>(), LayerInterface diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/GeneratedAdaptersTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/GeneratedAdaptersTest.kt index d1dde58ef..577820fd4 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/GeneratedAdaptersTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/GeneratedAdaptersTest.kt @@ -50,17 +50,22 @@ class GeneratedAdaptersTest { // Read @Language("JSON") - val json = """{"foo": "bar"}""" + val json = + """{"foo": "bar"}""" val instance = adapter.fromJson(json)!! assertThat(instance.bar).isEqualTo("bar") // Write @Language("JSON") - val expectedJson = """{"foo":"baz"}""" + val expectedJson = + """{"foo":"baz"}""" - assertThat(adapter.toJson( - JsonAnnotation("baz"))).isEqualTo(expectedJson) + assertThat( + adapter.toJson( + JsonAnnotation("baz") + ) + ).isEqualTo(expectedJson) } @JsonClass(generateAdapter = true) @@ -79,8 +84,11 @@ class GeneratedAdaptersTest { // Write val expectedJson = "{\"\$foo\":\"baz\"}" - assertThat(adapter.toJson( - JsonAnnotationWithDollarSign("baz"))).isEqualTo(expectedJson) + assertThat( + adapter.toJson( + JsonAnnotationWithDollarSign("baz") + ) + ).isEqualTo(expectedJson) } @JsonClass(generateAdapter = true) @@ -91,16 +99,21 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() // Read - val json = """{"\"foo\"": "bar"}""" + val json = + """{"\"foo\"": "bar"}""" val instance = adapter.fromJson(json)!! assertThat(instance.bar).isEqualTo("bar") // Write - val expectedJson = """{"\"foo\"":"baz"}""" + val expectedJson = + """{"\"foo\"":"baz"}""" - assertThat(adapter.toJson( - JsonAnnotationWithQuotationMark("baz"))).isEqualTo(expectedJson) + assertThat( + adapter.toJson( + JsonAnnotationWithQuotationMark("baz") + ) + ).isEqualTo(expectedJson) } @JsonClass(generateAdapter = true) @@ -112,7 +125,8 @@ class GeneratedAdaptersTest { // Read/write with default values @Language("JSON") - val json = """{"foo":"fooString"}""" + val json = + """{"foo":"fooString"}""" val instance = adapter.fromJson(json)!! assertThat(instance.foo).isEqualTo("fooString") @@ -123,13 +137,18 @@ class GeneratedAdaptersTest { isEmpty() } - @Language("JSON") val expected = """{"foo":"fooString","bar":"","bazList":[]}""" - assertThat(adapter.toJson( - DefaultValues("fooString"))).isEqualTo(expected) + @Language("JSON") val expected = + """{"foo":"fooString","bar":"","bazList":[]}""" + assertThat( + adapter.toJson( + DefaultValues("fooString") + ) + ).isEqualTo(expected) // Read/write with real values @Language("JSON") - val json2 = """ + val json2 = + """ {"foo":"fooString","bar":"barString","nullableBar":"bar","bazList":["baz"]} """.trimIndent() @@ -146,14 +165,16 @@ class GeneratedAdaptersTest { val foo: String, val bar: String = "", val nullableBar: String? = null, - val bazList: List = emptyList()) + val bazList: List = emptyList() + ) @Test fun nullableArray() { val adapter = moshi.adapter() @Language("JSON") - val json = """{"data":[null,"why"]}""" + val json = + """{"data":[null,"why"]}""" val instance = adapter.fromJson(json)!! assertThat(instance.data).containsExactly(null, "why") @@ -168,7 +189,8 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() @Language("JSON") - val json = """{"ints":[0,1]}""" + val json = + """{"ints":[0,1]}""" val instance = adapter.fromJson(json)!! assertThat(instance.ints).containsExactly(0, 1) @@ -183,9 +205,11 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() @Language("JSON") - val json = """{"foo":"foo","nullableString":null}""" + val json = + """{"foo":"foo","nullableString":null}""" @Language("JSON") - val invalidJson = """{"foo":null,"nullableString":null}""" + val invalidJson = + """{"foo":null,"nullableString":null}""" val instance = adapter.fromJson(json)!! assertThat(instance.foo).isEqualTo("foo") @@ -201,8 +225,8 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) data class NullabeTypes( - val foo: String, - val nullableString: String? + val foo: String, + val nullableString: String? ) @Test @@ -210,12 +234,12 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() val specialCollections = SpecialCollections( - mutableListOf(), - mutableSetOf(), - mutableMapOf(), - emptyList(), - emptySet(), - emptyMap() + mutableListOf(), + mutableSetOf(), + mutableMapOf(), + emptyList(), + emptySet(), + emptyMap() ) val json = adapter.toJson(specialCollections) @@ -225,12 +249,12 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) data class SpecialCollections( - val mutableList: MutableList, - val mutableSet: MutableSet, - val mutableMap: MutableMap, - val immutableList: List, - val immutableSet: Set, - val immutableMap: Map + val mutableList: MutableList, + val mutableSet: MutableSet, + val mutableMap: MutableMap, + val immutableList: List, + val immutableSet: Set, + val immutableMap: Map ) @Test @@ -238,18 +262,18 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() val mutableProperties = MutableProperties( - "immutableProperty", - "mutableProperty", - mutableListOf("immutableMutableList"), - mutableListOf("immutableImmutableList"), - mutableListOf("mutableMutableList"), - mutableListOf("mutableImmutableList"), - "immutableProperty", - "mutableProperty", - mutableListOf("immutableMutableList"), - mutableListOf("immutableImmutableList"), - mutableListOf("mutableMutableList"), - mutableListOf("mutableImmutableList") + "immutableProperty", + "mutableProperty", + mutableListOf("immutableMutableList"), + mutableListOf("immutableImmutableList"), + mutableListOf("mutableMutableList"), + mutableListOf("mutableImmutableList"), + "immutableProperty", + "mutableProperty", + mutableListOf("immutableMutableList"), + mutableListOf("immutableImmutableList"), + mutableListOf("mutableMutableList"), + mutableListOf("mutableImmutableList") ) val json = adapter.toJson(mutableProperties) @@ -259,42 +283,45 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) data class MutableProperties( - val immutableProperty: String, - var mutableProperty: String, - val immutableMutableList: MutableList, - val immutableImmutableList: List, - var mutableMutableList: MutableList, - var mutableImmutableList: List, - val nullableImmutableProperty: String?, - var nullableMutableProperty: String?, - val nullableImmutableMutableList: MutableList?, - val nullableImmutableImmutableList: List?, - var nullableMutableMutableList: MutableList?, - var nullableMutableImmutableList: List + val immutableProperty: String, + var mutableProperty: String, + val immutableMutableList: MutableList, + val immutableImmutableList: List, + var mutableMutableList: MutableList, + var mutableImmutableList: List, + val nullableImmutableProperty: String?, + var nullableMutableProperty: String?, + val nullableImmutableMutableList: MutableList?, + val nullableImmutableImmutableList: List?, + var nullableMutableMutableList: MutableList?, + var nullableMutableImmutableList: List ) @Test fun nullableTypeParams() { val adapter = moshi.adapter>( - Types.newParameterizedTypeWithOwner( - GeneratedAdaptersTest::class.java, - NullableTypeParams::class.java, Int::class.javaObjectType)) + Types.newParameterizedTypeWithOwner( + GeneratedAdaptersTest::class.java, + NullableTypeParams::class.java, + Int::class.javaObjectType + ) + ) val nullSerializing = adapter.serializeNulls() val nullableTypeParams = NullableTypeParams( - listOf("foo", null, "bar"), - setOf("foo", null, "bar"), - mapOf("foo" to "bar", "baz" to null), - null, - 1 + listOf("foo", null, "bar"), + setOf("foo", null, "bar"), + mapOf("foo" to "bar", "baz" to null), + null, + 1 ) val noNullsTypeParams = NullableTypeParams( - nullableTypeParams.nullableList, - nullableTypeParams.nullableSet, - nullableTypeParams.nullableMap.filterValues { it != null }, - null, - 1 + nullableTypeParams.nullableList, + nullableTypeParams.nullableSet, + nullableTypeParams.nullableMap.filterValues { it != null }, + null, + 1 ) val json = adapter.toJson(nullableTypeParams) @@ -330,8 +357,10 @@ class GeneratedAdaptersTest { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter() - val encoded = ConstructorParameters(3, - 5) + val encoded = ConstructorParameters( + 3, + 5 + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":3,"b":5}""") val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!! @@ -367,7 +396,8 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = ConstructorParametersAndProperties( - 3) + 3 + ) encoded.b = 5 assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":3,"b":5}""") @@ -386,7 +416,9 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = ImmutableConstructorParameters( - 3, 5) + 3, + 5 + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":3,"b":5}""") val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!! @@ -420,7 +452,9 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = ConstructorDefaultValues( - 3, 5) + 3, + 5 + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":3,"b":5}""") val decoded = jsonAdapter.fromJson("""{"b":6}""")!! @@ -465,12 +499,14 @@ class GeneratedAdaptersTest { @Test fun constructorParameterWithQualifier() { val moshi = Moshi.Builder() - .add(UppercaseJsonAdapter()) - .build() + .add(UppercaseJsonAdapter()) + .build() val jsonAdapter = moshi.adapter() val encoded = ConstructorParameterWithQualifier( - "Android", "Banana") + "Android", + "Banana" + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":"ANDROID","b":"Banana"}""") val decoded = jsonAdapter.fromJson("""{"a":"Android","b":"Banana"}""")!! @@ -483,8 +519,8 @@ class GeneratedAdaptersTest { @Test fun propertyWithQualifier() { val moshi = Moshi.Builder() - .add(UppercaseJsonAdapter()) - .build() + .add(UppercaseJsonAdapter()) + .build() val jsonAdapter = moshi.adapter() val encoded = PropertyWithQualifier() @@ -508,7 +544,9 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = ConstructorParameterWithJsonName( - 3, 5) + 3, + 5 + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"key a":3,"b":5}""") val decoded = jsonAdapter.fromJson("""{"key a":4,"b":6}""")!! @@ -544,7 +582,9 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = TransientConstructorParameter( - 3, 5) + 3, + 5 + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"b":5}""") val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!! @@ -618,7 +658,7 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) class TransientDelegateProperty { - private fun delegate(initial: T) = Delegates.observable(initial) { _, _, _-> } + private fun delegate(initial: T) = Delegates.observable(initial) { _, _, _ -> } @delegate:Transient var a: Int by delegate(-1) @delegate:Transient private var b: Int by delegate(-1) @@ -637,14 +677,16 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = ManyProperties32( - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132) - val json = (""" + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132 + ) + val json = ( + """ |{ |"v01":101,"v02":102,"v03":103,"v04":104,"v05":105, |"v06":106,"v07":107,"v08":108,"v09":109,"v10":110, @@ -654,7 +696,8 @@ class GeneratedAdaptersTest { |"v26":126,"v27":127,"v28":128,"v29":129,"v30":130, |"v31":131,"v32":132 |} - |""").trimMargin().replace("\n", "") + |""" + ).trimMargin().replace("\n", "") assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json) @@ -665,27 +708,55 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) class ManyProperties32( - var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int, - var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int, - var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int, - var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int, - var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int, - var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int, - var v31: Int, var v32: Int) + var v01: Int, + var v02: Int, + var v03: Int, + var v04: Int, + var v05: Int, + var v06: Int, + var v07: Int, + var v08: Int, + var v09: Int, + var v10: Int, + var v11: Int, + var v12: Int, + var v13: Int, + var v14: Int, + var v15: Int, + var v16: Int, + var v17: Int, + var v18: Int, + var v19: Int, + var v20: Int, + var v21: Int, + var v22: Int, + var v23: Int, + var v24: Int, + var v25: Int, + var v26: Int, + var v27: Int, + var v28: Int, + var v29: Int, + var v30: Int, + var v31: Int, + var v32: Int + ) @Test fun manyProperties33() { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter() val encoded = ManyProperties33( - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133) - val json = (""" + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132, 133 + ) + val json = ( + """ |{ |"v01":101,"v02":102,"v03":103,"v04":104,"v05":105, |"v06":106,"v07":107,"v08":108,"v09":109,"v10":110, @@ -695,7 +766,8 @@ class GeneratedAdaptersTest { |"v26":126,"v27":127,"v28":128,"v29":129,"v30":130, |"v31":131,"v32":132,"v33":133 |} - |""").trimMargin().replace("\n", "") + |""" + ).trimMargin().replace("\n", "") assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json) @@ -707,13 +779,40 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) class ManyProperties33( - var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int, - var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int, - var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int, - var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int, - var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int, - var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int, - var v31: Int, var v32: Int, var v33: Int) + var v01: Int, + var v02: Int, + var v03: Int, + var v04: Int, + var v05: Int, + var v06: Int, + var v07: Int, + var v08: Int, + var v09: Int, + var v10: Int, + var v11: Int, + var v12: Int, + var v13: Int, + var v14: Int, + var v15: Int, + var v16: Int, + var v17: Int, + var v18: Int, + var v19: Int, + var v20: Int, + var v21: Int, + var v22: Int, + var v23: Int, + var v24: Int, + var v25: Int, + var v26: Int, + var v27: Int, + var v28: Int, + var v29: Int, + var v30: Int, + var v31: Int, + var v32: Int, + var v33: Int + ) @Test fun unsettablePropertyIgnored() { val moshi = Moshi.Builder().build() @@ -749,7 +848,7 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) class GetterOnly(var a: Int, var b: Int) { - val total : Int + val total: Int get() = a + b } @@ -775,7 +874,7 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) class GetterAndSetter(var a: Int, var b: Int) { - var total : Int + var total: Int get() = a + b set(value) { b = value - a @@ -787,7 +886,9 @@ class GeneratedAdaptersTest { val jsonAdapter = moshi.adapter() val encoded = SubtypeConstructorParameters( - 3, 5) + 3, + 5 + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":3,"b":5}""") val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!! @@ -831,7 +932,7 @@ class GeneratedAdaptersTest { try { jsonAdapter.fromJson("""{"a":4,"a":4}""") fail() - } catch(expected: JsonDataException) { + } catch (expected: JsonDataException) { assertThat(expected).hasMessage("Multiple values for 'a' at $.a") } } @@ -846,7 +947,7 @@ class GeneratedAdaptersTest { try { jsonAdapter.fromJson("""{"a":4,"a":4}""") fail() - } catch(expected: JsonDataException) { + } catch (expected: JsonDataException) { assertThat(expected).hasMessage("Multiple values for 'a' at $.a") } } @@ -881,18 +982,20 @@ class GeneratedAdaptersTest { /** https://github.com/square/moshi/issues/563 */ @Test fun qualifiedAdaptersAreShared() { val moshi = Moshi.Builder() - .add(UppercaseJsonAdapter()) - .build() + .add(UppercaseJsonAdapter()) + .build() val jsonAdapter = moshi.adapter() val encoded = MultiplePropertiesShareAdapter( - "Android", "Banana") + "Android", + "Banana" + ) assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"a":"ANDROID","b":"BANANA"}""") val delegateAdapters = GeneratedAdaptersTest_MultiplePropertiesShareAdapterJsonAdapter::class - .memberProperties.filter { - it.returnType.classifier == JsonAdapter::class - } + .memberProperties.filter { + it.returnType.classifier == JsonAdapter::class + } assertThat(delegateAdapters).hasSize(1) } @@ -904,12 +1007,15 @@ class GeneratedAdaptersTest { @Test fun toJsonOnly() { val moshi = Moshi.Builder() - .add(CustomToJsonOnlyAdapter()) - .build() + .add(CustomToJsonOnlyAdapter()) + .build() val jsonAdapter = moshi.adapter() - assertThat(jsonAdapter.toJson( - CustomToJsonOnly(1, 2))).isEqualTo("""[1,2]""") + assertThat( + jsonAdapter.toJson( + CustomToJsonOnly(1, 2) + ) + ).isEqualTo("""[1,2]""") val fromJson = jsonAdapter.fromJson("""{"a":3,"b":4}""")!! assertThat(fromJson.a).isEqualTo(3) @@ -920,19 +1026,22 @@ class GeneratedAdaptersTest { class CustomToJsonOnly(var a: Int, var b: Int) class CustomToJsonOnlyAdapter { - @ToJson fun toJson(v: CustomToJsonOnly) : List { + @ToJson fun toJson(v: CustomToJsonOnly): List { return listOf(v.a, v.b) } } @Test fun fromJsonOnly() { val moshi = Moshi.Builder() - .add(CustomFromJsonOnlyAdapter()) - .build() + .add(CustomFromJsonOnlyAdapter()) + .build() val jsonAdapter = moshi.adapter() - assertThat(jsonAdapter.toJson( - CustomFromJsonOnly(1, 2))).isEqualTo("""{"a":1,"b":2}""") + assertThat( + jsonAdapter.toJson( + CustomFromJsonOnly(1, 2) + ) + ).isEqualTo("""{"a":1,"b":2}""") val fromJson = jsonAdapter.fromJson("""[3,4]""")!! assertThat(fromJson.a).isEqualTo(3) @@ -943,7 +1052,7 @@ class GeneratedAdaptersTest { class CustomFromJsonOnly(var a: Int, var b: Int) class CustomFromJsonOnlyAdapter { - @FromJson fun fromJson(v: List) : CustomFromJsonOnly { + @FromJson fun fromJson(v: List): CustomFromJsonOnly { return CustomFromJsonOnly(v[0], v[1]) } } @@ -977,8 +1086,8 @@ class GeneratedAdaptersTest { @Test fun propertyIsNothing() { val moshi = Moshi.Builder() - .add(NothingAdapter()) - .build() + .add(NothingAdapter()) + .build() val jsonAdapter = moshi.adapter().serializeNulls() val toJson = HasNothingProperty() @@ -995,7 +1104,7 @@ class GeneratedAdaptersTest { jsonWriter.nullValue() } - @FromJson fun fromJson(jsonReader: JsonReader) : Nothing? { + @FromJson fun fromJson(jsonReader: JsonReader): Nothing? { jsonReader.skipValue() return null } @@ -1010,10 +1119,14 @@ class GeneratedAdaptersTest { @Test fun enclosedParameterizedType() { val jsonAdapter = moshi.adapter() - assertThat(jsonAdapter.toJson( + assertThat( + jsonAdapter.toJson( HasParameterizedProperty( - Twins("1", "2")))) - .isEqualTo("""{"twins":{"a":"1","b":"2"}}""") + Twins("1", "2") + ) + ) + ) + .isEqualTo("""{"twins":{"a":"1","b":"2"}}""") val hasParameterizedProperty = jsonAdapter.fromJson("""{"twins":{"a":"3","b":"4"}}""")!! assertThat(hasParameterizedProperty.twins.a).isEqualTo("3") @@ -1033,8 +1146,11 @@ class GeneratedAdaptersTest { assertThat(instance.AAA).isEqualTo(1) assertThat(instance.BBB).isEqualTo(2) - assertThat(adapter.toJson( - UppercasePropertyName(3, 4))).isEqualTo("""{"AAA":3,"BBB":4}""") + assertThat( + adapter.toJson( + UppercasePropertyName(3, 4) + ) + ).isEqualTo("""{"AAA":3,"BBB":4}""") } @JsonClass(generateAdapter = true) @@ -1064,10 +1180,10 @@ class GeneratedAdaptersTest { annotation class Uppercase(val inFrench: Boolean, val onSundays: Boolean = false) class UppercaseJsonAdapter { - @ToJson fun toJson(@Uppercase(inFrench = true) s: String) : String { + @ToJson fun toJson(@Uppercase(inFrench = true) s: String): String { return s.toUpperCase(Locale.US) } - @FromJson @Uppercase(inFrench = true) fun fromJson(s: String) : String { + @FromJson @Uppercase(inFrench = true) fun fromJson(s: String): String { return s.toLowerCase(Locale.US) } } @@ -1077,9 +1193,10 @@ class GeneratedAdaptersTest { @Test fun nullablePrimitivesUseBoxedPrimitiveAdapters() { val moshi = Moshi.Builder() - .add(JsonAdapter.Factory { type, _, _ -> + .add( + JsonAdapter.Factory { type, _, _ -> if (Boolean::class.javaObjectType == type) { - return@Factory object:JsonAdapter() { + return@Factory object : JsonAdapter() { override fun fromJson(reader: JsonReader): Boolean? { if (reader.peek() != JsonReader.Token.BOOLEAN) { reader.skipValue() @@ -1094,13 +1211,17 @@ class GeneratedAdaptersTest { } } null - }) - .build() + } + ) + .build() val adapter = moshi.adapter().serializeNulls() assertThat(adapter.fromJson("""{"boolean":"not a boolean"}""")) - .isEqualTo(HasNullableBoolean(null)) - assertThat(adapter.toJson( - HasNullableBoolean(null))).isEqualTo("""{"boolean":null}""") + .isEqualTo(HasNullableBoolean(null)) + assertThat( + adapter.toJson( + HasNullableBoolean(null) + ) + ).isEqualTo("""{"boolean":null}""") } @Test fun adaptersAreNullSafe() { @@ -1118,13 +1239,16 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() val encoded = HasCollectionOfPrimitives( - listOf(1, 2, -3)) + listOf(1, 2, -3) + ) assertThat(adapter.toJson(encoded)).isEqualTo("""{"listOfInts":[1,2,-3]}""") val decoded = adapter.fromJson("""{"listOfInts":[4,-5,6]}""")!! assertThat(decoded).isEqualTo( - HasCollectionOfPrimitives( - listOf(4, -5, 6))) + HasCollectionOfPrimitives( + listOf(4, -5, 6) + ) + ) } @JsonClass(generateAdapter = true, generator = "custom") @@ -1135,7 +1259,8 @@ class GeneratedAdaptersTest { val adapter = moshi.adapter() val unwrapped = (adapter as NullSafeJsonAdapter).delegate() assertThat(unwrapped).isInstanceOf( - GeneratedAdaptersTest_CustomGeneratedClassJsonAdapter::class.java) + GeneratedAdaptersTest_CustomGeneratedClassJsonAdapter::class.java + ) } @JsonClass(generateAdapter = true, generator = "custom") @@ -1176,7 +1301,7 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) data class ClassWithFieldJson( - @field:Json(name = "_links") val links: String + @field:Json(name = "_links") val links: String ) { @field:Json(name = "_ids") var ids: String? = null } @@ -1206,7 +1331,6 @@ class GeneratedAdaptersTest { @JsonClass(generateAdapter = true) data class DeprecatedProperty(@Deprecated("Deprecated for reasons") val foo: String) - @Target(TYPE) annotation class TypeAnnotation @@ -1216,8 +1340,8 @@ class GeneratedAdaptersTest { */ @JsonClass(generateAdapter = true) data class TypeAnnotationClass( - val propertyWithAnnotatedType: @TypeAnnotation String = "", - val generic: List<@TypeAnnotation String> + val propertyWithAnnotatedType: @TypeAnnotation String = "", + val generic: List<@TypeAnnotation String> ) @Test fun typesSizeCheckMessages_noArgs() { @@ -1232,8 +1356,8 @@ class GeneratedAdaptersTest { @Test fun typesSizeCheckMessages_wrongNumberOfArgs() { try { GeneratedAdaptersTest_MultipleGenericsJsonAdapter( - moshi, - arrayOf(String::class.java) + moshi, + arrayOf(String::class.java) ) fail("Should have failed to construct the adapter due to wrong number of generics") } catch (e: IllegalArgumentException) { @@ -1249,13 +1373,13 @@ class GeneratedAdaptersTest { // Compile-only test @JsonClass(generateAdapter = true) internal data class MismatchParentAndNestedClassVisibility( - val type: Int, - val name: String? = null + val type: Int, + val name: String? = null ) { @JsonClass(generateAdapter = true) data class NestedClass( - val nestedProperty: String + val nestedProperty: String ) } @@ -1263,22 +1387,22 @@ internal data class MismatchParentAndNestedClassVisibility( // Compile-only test @JsonClass(generateAdapter = true) data class KeysWithSpaces( - @Json(name = "1. Information") val information: String, - @Json(name = "2. Symbol") val symbol: String, - @Json(name = "3. Last Refreshed") val lastRefreshed: String, - @Json(name = "4. Interval") val interval: String, - @Json(name = "5. Output Size") val size: String, - @Json(name = "6. Time Zone") val timeZone: String + @Json(name = "1. Information") val information: String, + @Json(name = "2. Symbol") val symbol: String, + @Json(name = "3. Last Refreshed") val lastRefreshed: String, + @Json(name = "4. Interval") val interval: String, + @Json(name = "5. Output Size") val size: String, + @Json(name = "6. Time Zone") val timeZone: String ) // Has to be outside to avoid Types seeing an owning class @JsonClass(generateAdapter = true) data class NullableTypeParams( - val nullableList: List, - val nullableSet: Set, - val nullableMap: Map, - val nullableT: T?, - val nonNullT: T + val nullableList: List, + val nullableSet: Set, + val nullableMap: Map, + val nullableT: T?, + val nonNullT: T ) /** @@ -1315,7 +1439,7 @@ data class SmokeTestType( // Compile only, regression test for https://github.com/square/moshi/issues/848 @JsonClass(generateAdapter = true) data class Hotwords( - val `class`: List? + val `class`: List? ) typealias TypeAliasName = String diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MultipleMasksTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MultipleMasksTest.kt index c31dcded2..80758528c 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MultipleMasksTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MultipleMasksTest.kt @@ -38,10 +38,11 @@ class MultipleMasksTest { // Set some arbitrary values to make sure offsets are aligning correctly @Language("JSON") - val json = """{"arg50":500,"arg3":34,"arg11":11,"arg65":67}""" + val json = + """{"arg50":500,"arg3":34,"arg11":11,"arg65":67}""" val instance = Moshi.Builder().build().adapter(MultipleMasks::class.java) - .fromJson(json)!! + .fromJson(json)!! assertEquals(instance.arg2, 2) assertEquals(instance.arg3, 34) @@ -55,70 +56,70 @@ class MultipleMasksTest { @JsonClass(generateAdapter = true) class MultipleMasks( - val arg0: Long = 0, - val arg1: Long = 1, - val arg2: Long = 2, - val arg3: Long = 3, - val arg4: Long = 4, - val arg5: Long = 5, - val arg6: Long = 6, - val arg7: Long = 7, - val arg8: Long = 8, - val arg9: Long = 9, - val arg10: Long = 10, - val arg11: Long, - val arg12: Long = 12, - val arg13: Long = 13, - val arg14: Long = 14, - val arg15: Long = 15, - val arg16: Long = 16, - val arg17: Long = 17, - val arg18: Long = 18, - val arg19: Long = 19, - @Suppress("UNUSED_PARAMETER") arg20: Long = 20, - val arg21: Long = 21, - val arg22: Long = 22, - val arg23: Long = 23, - val arg24: Long = 24, - val arg25: Long = 25, - val arg26: Long = 26, - val arg27: Long = 27, - val arg28: Long = 28, - val arg29: Long = 29, - val arg30: Long = 30, - val arg31: Long = 31, - val arg32: Long = 32, - val arg33: Long = 33, - val arg34: Long = 34, - val arg35: Long = 35, - val arg36: Long = 36, - val arg37: Long = 37, - val arg38: Long = 38, - @Transient val arg39: Long = 39, - val arg40: Long = 40, - val arg41: Long = 41, - val arg42: Long = 42, - val arg43: Long = 43, - val arg44: Long = 44, - val arg45: Long = 45, - val arg46: Long = 46, - val arg47: Long = 47, - val arg48: Long = 48, - val arg49: Long = 49, - val arg50: Long = 50, - val arg51: Long = 51, - val arg52: Long = 52, - @Transient val arg53: Long = 53, - val arg54: Long = 54, - val arg55: Long = 55, - val arg56: Long = 56, - val arg57: Long = 57, - val arg58: Long = 58, - val arg59: Long = 59, - val arg60: Long = 60, - val arg61: Long = 61, - val arg62: Long = 62, - val arg63: Long = 63, - val arg64: Long = 64, - val arg65: Long = 65 + val arg0: Long = 0, + val arg1: Long = 1, + val arg2: Long = 2, + val arg3: Long = 3, + val arg4: Long = 4, + val arg5: Long = 5, + val arg6: Long = 6, + val arg7: Long = 7, + val arg8: Long = 8, + val arg9: Long = 9, + val arg10: Long = 10, + val arg11: Long, + val arg12: Long = 12, + val arg13: Long = 13, + val arg14: Long = 14, + val arg15: Long = 15, + val arg16: Long = 16, + val arg17: Long = 17, + val arg18: Long = 18, + val arg19: Long = 19, + @Suppress("UNUSED_PARAMETER") arg20: Long = 20, + val arg21: Long = 21, + val arg22: Long = 22, + val arg23: Long = 23, + val arg24: Long = 24, + val arg25: Long = 25, + val arg26: Long = 26, + val arg27: Long = 27, + val arg28: Long = 28, + val arg29: Long = 29, + val arg30: Long = 30, + val arg31: Long = 31, + val arg32: Long = 32, + val arg33: Long = 33, + val arg34: Long = 34, + val arg35: Long = 35, + val arg36: Long = 36, + val arg37: Long = 37, + val arg38: Long = 38, + @Transient val arg39: Long = 39, + val arg40: Long = 40, + val arg41: Long = 41, + val arg42: Long = 42, + val arg43: Long = 43, + val arg44: Long = 44, + val arg45: Long = 45, + val arg46: Long = 46, + val arg47: Long = 47, + val arg48: Long = 48, + val arg49: Long = 49, + val arg50: Long = 50, + val arg51: Long = 51, + val arg52: Long = 52, + @Transient val arg53: Long = 53, + val arg54: Long = 54, + val arg55: Long = 55, + val arg56: Long = 56, + val arg57: Long = 57, + val arg58: Long = 58, + val arg59: Long = 59, + val arg60: Long = 60, + val arg61: Long = 61, + val arg62: Long = 62, + val arg63: Long = 63, + val arg64: Long = 64, + val arg65: Long = 65 ) diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt index 739bad4a3..0bec5d076 100644 --- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt +++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt @@ -140,7 +140,7 @@ class KotlinJsonAdapterTest { try { jsonAdapter.fromJson("""{"a":4,"a":4}""") fail() - } catch(expected: JsonDataException) { + } catch (expected: JsonDataException) { assertThat(expected).hasMessage("Multiple values for 'a' at $.a") } } @@ -154,7 +154,7 @@ class KotlinJsonAdapterTest { try { jsonAdapter.fromJson("""{"a":4,"a":4}""") fail() - } catch(expected: JsonDataException) { + } catch (expected: JsonDataException) { assertThat(expected).hasMessage("Multiple values for 'a' at $.a") } } @@ -201,7 +201,7 @@ class KotlinJsonAdapterTest { try { jsonAdapter.fromJson("""{"a":4,"b":null,"b":6}""") fail() - } catch(expected: JsonDataException) { + } catch (expected: JsonDataException) { assertThat(expected).hasMessage("Multiple values for 'b' at $.b") } } @@ -210,9 +210,9 @@ class KotlinJsonAdapterTest { @Test fun constructorParameterWithQualifier() { val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .add(UppercaseJsonAdapter()) - .build() + .add(KotlinJsonAdapterFactory()) + .add(UppercaseJsonAdapter()) + .build() val jsonAdapter = moshi.adapter() val encoded = ConstructorParameterWithQualifier("Android", "Banana") @@ -227,9 +227,9 @@ class KotlinJsonAdapterTest { @Test fun propertyWithQualifier() { val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .add(UppercaseJsonAdapter()) - .build() + .add(KotlinJsonAdapterFactory()) + .add(UppercaseJsonAdapter()) + .build() val jsonAdapter = moshi.adapter() val encoded = PropertyWithQualifier() @@ -315,9 +315,11 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (expected: IllegalArgumentException) { - assertThat(expected).hasMessage("No default value for transient constructor parameter #0 " + + assertThat(expected).hasMessage( + "No default value for transient constructor parameter #0 " + "a of fun (kotlin.Int): " + - "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest.RequiredTransientConstructorParameter") + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest.RequiredTransientConstructorParameter" + ) } } @@ -357,8 +359,10 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (expected: IllegalArgumentException) { - assertThat(expected).hasMessage("'a' has a constructor parameter of type " + - "kotlin.Int but a property of type kotlin.String.") + assertThat(expected).hasMessage( + "'a' has a constructor parameter of type " + + "kotlin.Int but a property of type kotlin.String." + ) } } @@ -443,7 +447,8 @@ class KotlinJsonAdapterTest { fail() } catch (e: IllegalArgumentException) { assertThat(e).hasMessage( - "Platform class kotlin.Triple in kotlin.Triple requires explicit JsonAdapter to be registered") + "Platform class kotlin.Triple in kotlin.Triple requires explicit JsonAdapter to be registered" + ) } } @@ -547,7 +552,7 @@ class KotlinJsonAdapterTest { } class GetterOnly(var a: Int, var b: Int) { - val total : Int + val total: Int get() = a + b } @@ -572,7 +577,7 @@ class KotlinJsonAdapterTest { } class GetterAndSetter(var a: Int, var b: Int) { - var total : Int + var total: Int get() = a + b set(value) { b = value - a @@ -584,10 +589,11 @@ class KotlinJsonAdapterTest { try { moshi.adapter() fail() - } catch(expected: IllegalArgumentException) { + } catch (expected: IllegalArgumentException) { assertThat(expected).hasMessage( - "No property for required constructor parameter #0 a of fun (" + - "kotlin.Int, kotlin.Int): ${NonPropertyConstructorParameter::class.qualifiedName}") + "No property for required constructor parameter #0 a of fun (" + + "kotlin.Int, kotlin.Int): ${NonPropertyConstructorParameter::class.qualifiedName}" + ) } } @@ -612,8 +618,10 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (e: IllegalArgumentException) { - assertThat(e).hasMessage("No JsonAdapter for interface " + - "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$Interface (with no annotations)") + assertThat(e).hasMessage( + "No JsonAdapter for interface " + + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$Interface (with no annotations)" + ) } } @@ -625,8 +633,10 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (e: IllegalArgumentException) { - assertThat(e).hasMessage("Cannot serialize abstract class " + - "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$AbstractClass") + assertThat(e).hasMessage( + "Cannot serialize abstract class " + + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$AbstractClass" + ) } } @@ -638,8 +648,10 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (e: IllegalArgumentException) { - assertThat(e).hasMessage("Cannot serialize inner class " + - "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$InnerClass") + assertThat(e).hasMessage( + "Cannot serialize inner class " + + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$InnerClass" + ) } } @@ -652,8 +664,10 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (e: IllegalArgumentException) { - assertThat(e).hasMessage("Cannot serialize local class or object expression " + - "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$localClassesNotSupported\$LocalClass") + assertThat(e).hasMessage( + "Cannot serialize local class or object expression " + + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$localClassesNotSupported\$LocalClass" + ) } } @@ -663,8 +677,10 @@ class KotlinJsonAdapterTest { moshi.adapter() fail() } catch (e: IllegalArgumentException) { - assertThat(e).hasMessage("Cannot serialize object declaration " + - "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$ObjectDeclaration") + assertThat(e).hasMessage( + "Cannot serialize object declaration " + + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$ObjectDeclaration" + ) } } @@ -681,9 +697,11 @@ class KotlinJsonAdapterTest { moshi.adapter(expression.javaClass) fail() } catch (e: IllegalArgumentException) { - assertThat(e).hasMessage("Cannot serialize local class or object expression " + + assertThat(e).hasMessage( + "Cannot serialize local class or object expression " + "com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest\$objectExpressionsNotSupported" + - "\$expression$1") + "\$expression$1" + ) } } @@ -692,14 +710,16 @@ class KotlinJsonAdapterTest { val jsonAdapter = moshi.adapter() val encoded = ManyProperties32( - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132) - val json = (""" + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132 + ) + val json = ( + """ |{ |"v01":101,"v02":102,"v03":103,"v04":104,"v05":105, |"v06":106,"v07":107,"v08":108,"v09":109,"v10":110, @@ -709,7 +729,8 @@ class KotlinJsonAdapterTest { |"v26":126,"v27":127,"v28":128,"v29":129,"v30":130, |"v31":131,"v32":132 |} - |""").trimMargin().replace("\n", "") + |""" + ).trimMargin().replace("\n", "") assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json) @@ -719,27 +740,55 @@ class KotlinJsonAdapterTest { } class ManyProperties32( - var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int, - var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int, - var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int, - var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int, - var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int, - var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int, - var v31: Int, var v32: Int) + var v01: Int, + var v02: Int, + var v03: Int, + var v04: Int, + var v05: Int, + var v06: Int, + var v07: Int, + var v08: Int, + var v09: Int, + var v10: Int, + var v11: Int, + var v12: Int, + var v13: Int, + var v14: Int, + var v15: Int, + var v16: Int, + var v17: Int, + var v18: Int, + var v19: Int, + var v20: Int, + var v21: Int, + var v22: Int, + var v23: Int, + var v24: Int, + var v25: Int, + var v26: Int, + var v27: Int, + var v28: Int, + var v29: Int, + var v30: Int, + var v31: Int, + var v32: Int + ) @Test fun manyProperties33() { val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() val jsonAdapter = moshi.adapter() val encoded = ManyProperties33( - 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, - 131, 132, 133) - val json = (""" + 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, + 131, 132, 133 + ) + val json = ( + """ |{ |"v01":101,"v02":102,"v03":103,"v04":104,"v05":105, |"v06":106,"v07":107,"v08":108,"v09":109,"v10":110, @@ -749,7 +798,8 @@ class KotlinJsonAdapterTest { |"v26":126,"v27":127,"v28":128,"v29":129,"v30":130, |"v31":131,"v32":132,"v33":133 |} - |""").trimMargin().replace("\n", "") + |""" + ).trimMargin().replace("\n", "") assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json) @@ -760,21 +810,52 @@ class KotlinJsonAdapterTest { } class ManyProperties33( - var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int, - var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int, - var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int, - var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int, - var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int, - var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int, - var v31: Int, var v32: Int, var v33: Int) + var v01: Int, + var v02: Int, + var v03: Int, + var v04: Int, + var v05: Int, + var v06: Int, + var v07: Int, + var v08: Int, + var v09: Int, + var v10: Int, + var v11: Int, + var v12: Int, + var v13: Int, + var v14: Int, + var v15: Int, + var v16: Int, + var v17: Int, + var v18: Int, + var v19: Int, + var v20: Int, + var v21: Int, + var v22: Int, + var v23: Int, + var v24: Int, + var v25: Int, + var v26: Int, + var v27: Int, + var v28: Int, + var v29: Int, + var v30: Int, + var v31: Int, + var v32: Int, + var v33: Int + ) data class Box(val data: T) @Test fun genericTypes() { val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() val stringBoxAdapter = moshi.adapter>( - Types.newParameterizedTypeWithOwner(KotlinJsonAdapterTest::class.java, Box::class.java, - String::class.java)) + Types.newParameterizedTypeWithOwner( + KotlinJsonAdapterTest::class.java, + Box::class.java, + String::class.java + ) + ) assertThat(stringBoxAdapter.fromJson("""{"data":"hello"}""")).isEqualTo(Box("hello")) assertThat(stringBoxAdapter.toJson(Box("hello"))).isEqualTo("""{"data":"hello"}""") } @@ -784,18 +865,19 @@ class KotlinJsonAdapterTest { @Test fun nestedGenericTypes() { val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() val type = Types.newParameterizedTypeWithOwner( + KotlinJsonAdapterTest::class.java, + NestedGenerics::class.java, + String::class.java, + Int::class.javaObjectType, + Types.newParameterizedTypeWithOwner( KotlinJsonAdapterTest::class.java, - NestedGenerics::class.java, - String::class.java, - Int::class.javaObjectType, - Types.newParameterizedTypeWithOwner( - KotlinJsonAdapterTest::class.java, - Box::class.java, - String::class.java - ) + Box::class.java, + String::class.java + ) ) val adapter = moshi.adapter>>(type).indent(" ") - val json = """ + val json = + """ |{ | "value": { | "hello": { @@ -818,16 +900,18 @@ class KotlinJsonAdapterTest { @Test fun mixingReflectionAndCodegen() { val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + .add(KotlinJsonAdapterFactory()) + .build() val generatedAdapter = moshi.adapter() val reflectionAdapter = moshi.adapter() assertThat(generatedAdapter.toString()) - .isEqualTo("GeneratedJsonAdapter(KotlinJsonAdapterTest.UsesGeneratedAdapter).nullSafe()") + .isEqualTo("GeneratedJsonAdapter(KotlinJsonAdapterTest.UsesGeneratedAdapter).nullSafe()") assertThat(reflectionAdapter.toString()) - .isEqualTo("KotlinJsonAdapter(com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest" + - ".UsesReflectionAdapter).nullSafe()") + .isEqualTo( + "KotlinJsonAdapter(com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterTest" + + ".UsesReflectionAdapter).nullSafe()" + ) } @JsonClass(generateAdapter = true) @@ -841,10 +925,10 @@ class KotlinJsonAdapterTest { annotation class Uppercase class UppercaseJsonAdapter { - @ToJson fun toJson(@Uppercase s: String) : String { + @ToJson fun toJson(@Uppercase s: String): String { return s.toUpperCase(Locale.US) } - @FromJson @Uppercase fun fromJson(s: String) : String { + @FromJson @Uppercase fun fromJson(s: String): String { return s.toLowerCase(Locale.US) } } @@ -853,9 +937,10 @@ class KotlinJsonAdapterTest { @Test fun nullablePrimitivesUseBoxedPrimitiveAdapters() { val moshi = Moshi.Builder() - .add(JsonAdapter.Factory { type, _, _ -> + .add( + JsonAdapter.Factory { type, _, _ -> if (Boolean::class.javaObjectType == type) { - return@Factory object: JsonAdapter() { + return@Factory object : JsonAdapter() { override fun fromJson(reader: JsonReader): Boolean? { if (reader.peek() != JsonReader.Token.BOOLEAN) { reader.skipValue() @@ -870,19 +955,20 @@ class KotlinJsonAdapterTest { } } null - }) - .add(KotlinJsonAdapterFactory()) - .build() + } + ) + .add(KotlinJsonAdapterFactory()) + .build() val adapter = moshi.adapter().serializeNulls() assertThat(adapter.fromJson("""{"boolean":"not a boolean"}""")) - .isEqualTo(HasNullableBoolean(null)) + .isEqualTo(HasNullableBoolean(null)) assertThat(adapter.toJson(HasNullableBoolean(null))).isEqualTo("""{"boolean":null}""") } @Test fun adaptersAreNullSafe() { val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + .add(KotlinJsonAdapterFactory()) + .build() // TODO in CR: We had to mark this as nullable, vs before the jsonadapter factory would always run val adapter = moshi.adapter() @@ -904,9 +990,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToStandardReflectionWildcards() { mapWildcardsParameterizedTest( - MapOfStringToStandardReflection::class.java, - """{"map":{"key":"value"}}""", - MapOfStringToStandardReflection(mapOf("key" to "value"))) + MapOfStringToStandardReflection::class.java, + """{"map":{"key":"value"}}""", + MapOfStringToStandardReflection(mapOf("key" to "value")) + ) } @JvmSuppressWildcards(suppress = false) @@ -914,9 +1001,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToStandardCodegenWildcards() { mapWildcardsParameterizedTest( - MapOfStringToStandardCodegen::class.java, - """{"map":{"key":"value"}}""", - MapOfStringToStandardCodegen(mapOf("key" to "value"))) + MapOfStringToStandardCodegen::class.java, + """{"map":{"key":"value"}}""", + MapOfStringToStandardCodegen(mapOf("key" to "value")) + ) } @JsonClass(generateAdapter = true) @@ -925,9 +1013,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToEnumReflectionWildcards() { mapWildcardsParameterizedTest( - MapOfStringToEnumReflection::class.java, - """{"map":{"key":"A"}}""", - MapOfStringToEnumReflection(mapOf("key" to KotlinEnum.A))) + MapOfStringToEnumReflection::class.java, + """{"map":{"key":"A"}}""", + MapOfStringToEnumReflection(mapOf("key" to KotlinEnum.A)) + ) } @JvmSuppressWildcards(suppress = false) @@ -935,9 +1024,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToEnumCodegenWildcards() { mapWildcardsParameterizedTest( - MapOfStringToEnumCodegen::class.java, - """{"map":{"key":"A"}}""", - MapOfStringToEnumCodegen(mapOf("key" to KotlinEnum.A))) + MapOfStringToEnumCodegen::class.java, + """{"map":{"key":"A"}}""", + MapOfStringToEnumCodegen(mapOf("key" to KotlinEnum.A)) + ) } @JsonClass(generateAdapter = true) @@ -946,9 +1036,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToCollectionReflectionWildcards() { mapWildcardsParameterizedTest( - MapOfStringToCollectionReflection::class.java, - """{"map":{"key":[]}}""", - MapOfStringToCollectionReflection(mapOf("key" to listOf()))) + MapOfStringToCollectionReflection::class.java, + """{"map":{"key":[]}}""", + MapOfStringToCollectionReflection(mapOf("key" to listOf())) + ) } @JvmSuppressWildcards(suppress = false) @@ -956,9 +1047,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToCollectionCodegenWildcards() { mapWildcardsParameterizedTest( - MapOfStringToCollectionCodegen::class.java, - """{"map":{"key":[]}}""", - MapOfStringToCollectionCodegen(mapOf("key" to listOf()))) + MapOfStringToCollectionCodegen::class.java, + """{"map":{"key":[]}}""", + MapOfStringToCollectionCodegen(mapOf("key" to listOf())) + ) } @JsonClass(generateAdapter = true) @@ -967,9 +1059,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToMapReflectionWildcards() { mapWildcardsParameterizedTest( - MapOfStringToMapReflection::class.java, - """{"map":{"key":{}}}""", - MapOfStringToMapReflection(mapOf("key" to mapOf()))) + MapOfStringToMapReflection::class.java, + """{"map":{"key":{}}}""", + MapOfStringToMapReflection(mapOf("key" to mapOf())) + ) } @JvmSuppressWildcards(suppress = false) @@ -977,9 +1070,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToMapCodegenWildcards() { mapWildcardsParameterizedTest( - MapOfStringToMapCodegen::class.java, - """{"map":{"key":{}}}""", - MapOfStringToMapCodegen(mapOf("key" to mapOf()))) + MapOfStringToMapCodegen::class.java, + """{"map":{"key":{}}}""", + MapOfStringToMapCodegen(mapOf("key" to mapOf())) + ) } @JsonClass(generateAdapter = true) @@ -988,9 +1082,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToArrayReflectionWildcards() { mapWildcardsParameterizedTest( - MapOfStringToArrayReflection::class.java, - """{"map":{"key":[]}}""", - MapOfStringToArrayReflection(mapOf("key" to arrayOf()))) + MapOfStringToArrayReflection::class.java, + """{"map":{"key":[]}}""", + MapOfStringToArrayReflection(mapOf("key" to arrayOf())) + ) } @JvmSuppressWildcards(suppress = false) @@ -998,9 +1093,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToArrayCodegenWildcards() { mapWildcardsParameterizedTest( - MapOfStringToArrayCodegen::class.java, - """{"map":{"key":[]}}""", - MapOfStringToArrayCodegen(mapOf("key" to arrayOf()))) + MapOfStringToArrayCodegen::class.java, + """{"map":{"key":[]}}""", + MapOfStringToArrayCodegen(mapOf("key" to arrayOf())) + ) } @JsonClass(generateAdapter = true) @@ -1009,9 +1105,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToClassReflectionWildcards() { mapWildcardsParameterizedTest( - MapOfStringToClassReflection::class.java, - """{"map":{"key":{"a":19,"b":42}}}""", - MapOfStringToClassReflection(mapOf("key" to ConstructorParameters(19, 42)))) + MapOfStringToClassReflection::class.java, + """{"map":{"key":{"a":19,"b":42}}}""", + MapOfStringToClassReflection(mapOf("key" to ConstructorParameters(19, 42))) + ) } @JvmSuppressWildcards(suppress = false) @@ -1019,9 +1116,10 @@ class KotlinJsonAdapterTest { @Test fun mapOfStringToClassCodegenWildcards() { mapWildcardsParameterizedTest( - MapOfStringToClassCodegen::class.java, - """{"map":{"key":{"a":19,"b":42}}}""", - MapOfStringToClassCodegen(mapOf("key" to ConstructorParameters(19, 42)))) + MapOfStringToClassCodegen::class.java, + """{"map":{"key":{"a":19,"b":42}}}""", + MapOfStringToClassCodegen(mapOf("key" to ConstructorParameters(19, 42))) + ) } @JsonClass(generateAdapter = true) @@ -1030,8 +1128,8 @@ class KotlinJsonAdapterTest { @Test fun sealedClassesAreRejected() { val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + .add(KotlinJsonAdapterFactory()) + .build() try { moshi.adapter() diff --git a/moshi/src/main/java/com/squareup/moshi/AdapterMethodsFactory.java b/moshi/src/main/java/com/squareup/moshi/AdapterMethodsFactory.java index f26230a79..017c8a391 100644 --- a/moshi/src/main/java/com/squareup/moshi/AdapterMethodsFactory.java +++ b/moshi/src/main/java/com/squareup/moshi/AdapterMethodsFactory.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.internal.Util.canonicalize; +import static com.squareup.moshi.internal.Util.jsonAnnotations; +import static com.squareup.moshi.internal.Util.typeAnnotatedWithAnnotations; + import com.squareup.moshi.internal.Util; import java.io.IOException; import java.lang.annotation.Annotation; @@ -27,10 +31,6 @@ import java.util.Set; import javax.annotation.Nullable; -import static com.squareup.moshi.internal.Util.canonicalize; -import static com.squareup.moshi.internal.Util.jsonAnnotations; -import static com.squareup.moshi.internal.Util.typeAnnotatedWithAnnotations; - final class AdapterMethodsFactory implements JsonAdapter.Factory { private final List toAdapters; private final List fromAdapters; @@ -40,7 +40,8 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory { this.fromAdapters = fromAdapters; } - @Override public @Nullable JsonAdapter create( + @Override + public @Nullable JsonAdapter create( final Type type, final Set annotations, final Moshi moshi) { final AdapterMethod toAdapter = get(toAdapters, type, annotations); final AdapterMethod fromAdapter = get(fromAdapters, type, annotations); @@ -52,8 +53,12 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory { delegate = moshi.nextAdapter(this, type, annotations); } catch (IllegalArgumentException e) { String missingAnnotation = toAdapter == null ? "@ToJson" : "@FromJson"; - throw new IllegalArgumentException("No " + missingAnnotation + " adapter for " - + typeAnnotatedWithAnnotations(type, annotations), e); + throw new IllegalArgumentException( + "No " + + missingAnnotation + + " adapter for " + + typeAnnotatedWithAnnotations(type, annotations), + e); } } else { delegate = null; @@ -63,7 +68,8 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory { if (fromAdapter != null) fromAdapter.bind(moshi, this); return new JsonAdapter() { - @Override public void toJson(JsonWriter writer, @Nullable Object value) throws IOException { + @Override + public void toJson(JsonWriter writer, @Nullable Object value) throws IOException { if (toAdapter == null) { delegate.toJson(writer, value); } else if (!toAdapter.nullable && value == null) { @@ -79,7 +85,8 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory { } } - @Override public @Nullable Object fromJson(JsonReader reader) throws IOException { + @Override + public @Nullable Object fromJson(JsonReader reader) throws IOException { if (fromAdapter == null) { return delegate.fromJson(reader); } else if (!fromAdapter.nullable && reader.peek() == JsonReader.Token.NULL) { @@ -96,7 +103,8 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory { } } - @Override public String toString() { + @Override + public String toString() { return "JsonAdapter" + annotations + "(" + type + ")"; } }; @@ -112,9 +120,13 @@ public static AdapterMethodsFactory get(Object adapter) { AdapterMethod toAdapter = toAdapter(adapter, m); AdapterMethod conflicting = get(toAdapters, toAdapter.type, toAdapter.annotations); if (conflicting != null) { - throw new IllegalArgumentException("Conflicting @ToJson methods:\n" - + " " + conflicting.method + "\n" - + " " + toAdapter.method); + throw new IllegalArgumentException( + "Conflicting @ToJson methods:\n" + + " " + + conflicting.method + + "\n" + + " " + + toAdapter.method); } toAdapters.add(toAdapter); } @@ -123,9 +135,13 @@ public static AdapterMethodsFactory get(Object adapter) { AdapterMethod fromAdapter = fromAdapter(adapter, m); AdapterMethod conflicting = get(fromAdapters, fromAdapter.type, fromAdapter.annotations); if (conflicting != null) { - throw new IllegalArgumentException("Conflicting @FromJson methods:\n" - + " " + conflicting.method + "\n" - + " " + fromAdapter.method); + throw new IllegalArgumentException( + "Conflicting @FromJson methods:\n" + + " " + + conflicting.method + + "\n" + + " " + + fromAdapter.method); } fromAdapters.add(fromAdapter); } @@ -133,8 +149,8 @@ public static AdapterMethodsFactory get(Object adapter) { } if (toAdapters.isEmpty() && fromAdapters.isEmpty()) { - throw new IllegalArgumentException("Expected at least one @ToJson or @FromJson method on " - + adapter.getClass().getName()); + throw new IllegalArgumentException( + "Expected at least one @ToJson or @FromJson method on " + adapter.getClass().getName()); } return new AdapterMethodsFactory(toAdapters, fromAdapters); @@ -157,9 +173,16 @@ && parametersAreJsonAdapters(2, parameterTypes)) { // void pointToJson(JsonWriter jsonWriter, Point point) { // void pointToJson(JsonWriter jsonWriter, Point point, JsonAdapter adapter, ...) { Set qualifierAnnotations = jsonAnnotations(parameterAnnotations[1]); - return new AdapterMethod(parameterTypes[1], qualifierAnnotations, adapter, method, - parameterTypes.length, 2, true) { - @Override public void toJson(Moshi moshi, JsonWriter writer, @Nullable Object value) + return new AdapterMethod( + parameterTypes[1], + qualifierAnnotations, + adapter, + method, + parameterTypes.length, + 2, + true) { + @Override + public void toJson(Moshi moshi, JsonWriter writer, @Nullable Object value) throws IOException, InvocationTargetException { invoke(writer, value); } @@ -171,19 +194,28 @@ && parametersAreJsonAdapters(2, parameterTypes)) { final Set qualifierAnnotations = jsonAnnotations(parameterAnnotations[0]); boolean nullable = Util.hasNullable(parameterAnnotations[0]); - return new AdapterMethod(parameterTypes[0], qualifierAnnotations, adapter, method, - parameterTypes.length, 1, nullable) { + return new AdapterMethod( + parameterTypes[0], + qualifierAnnotations, + adapter, + method, + parameterTypes.length, + 1, + nullable) { private JsonAdapter delegate; - @Override public void bind(Moshi moshi, JsonAdapter.Factory factory) { + @Override + public void bind(Moshi moshi, JsonAdapter.Factory factory) { super.bind(moshi, factory); - delegate = Types.equals(parameterTypes[0], returnType) - && qualifierAnnotations.equals(returnTypeAnnotations) - ? moshi.nextAdapter(factory, returnType, returnTypeAnnotations) - : moshi.adapter(returnType, returnTypeAnnotations); + delegate = + Types.equals(parameterTypes[0], returnType) + && qualifierAnnotations.equals(returnTypeAnnotations) + ? moshi.nextAdapter(factory, returnType, returnTypeAnnotations) + : moshi.adapter(returnType, returnTypeAnnotations); } - @Override public void toJson(Moshi moshi, JsonWriter writer, @Nullable Object value) + @Override + public void toJson(Moshi moshi, JsonWriter writer, @Nullable Object value) throws IOException, InvocationTargetException { Object intermediate = invoke(value); delegate.toJson(writer, intermediate); @@ -191,12 +223,15 @@ && parametersAreJsonAdapters(2, parameterTypes)) { }; } else { - throw new IllegalArgumentException("Unexpected signature for " + method + ".\n" - + "@ToJson method signatures may have one of the following structures:\n" - + " void toJson(JsonWriter writer, T value) throws ;\n" - + " void toJson(JsonWriter writer, T value," - + " JsonAdapter delegate, ) throws ;\n" - + " R toJson(T value) throws ;\n"); + throw new IllegalArgumentException( + "Unexpected signature for " + + method + + ".\n" + + "@ToJson method signatures may have one of the following structures:\n" + + " void toJson(JsonWriter writer, T value) throws ;\n" + + " void toJson(JsonWriter writer, T value," + + " JsonAdapter delegate, ) throws ;\n" + + " R toJson(T value) throws ;\n"); } } @@ -226,9 +261,10 @@ static AdapterMethod fromAdapter(Object adapter, Method method) { && parametersAreJsonAdapters(1, parameterTypes)) { // Point pointFromJson(JsonReader jsonReader) { // Point pointFromJson(JsonReader jsonReader, JsonAdapter adapter, ...) { - return new AdapterMethod(returnType, returnTypeAnnotations, adapter, method, - parameterTypes.length, 1, true) { - @Override public Object fromJson(Moshi moshi, JsonReader reader) + return new AdapterMethod( + returnType, returnTypeAnnotations, adapter, method, parameterTypes.length, 1, true) { + @Override + public Object fromJson(Moshi moshi, JsonReader reader) throws IOException, InvocationTargetException { return invoke(reader); } @@ -236,22 +272,25 @@ && parametersAreJsonAdapters(1, parameterTypes)) { } else if (parameterTypes.length == 1 && returnType != void.class) { // Point pointFromJson(List o) { - final Set qualifierAnnotations - = jsonAnnotations(parameterAnnotations[0]); + final Set qualifierAnnotations = + jsonAnnotations(parameterAnnotations[0]); boolean nullable = Util.hasNullable(parameterAnnotations[0]); - return new AdapterMethod(returnType, returnTypeAnnotations, adapter, method, - parameterTypes.length, 1, nullable) { + return new AdapterMethod( + returnType, returnTypeAnnotations, adapter, method, parameterTypes.length, 1, nullable) { JsonAdapter delegate; - @Override public void bind(Moshi moshi, JsonAdapter.Factory factory) { + @Override + public void bind(Moshi moshi, JsonAdapter.Factory factory) { super.bind(moshi, factory); - delegate = Types.equals(parameterTypes[0], returnType) - && qualifierAnnotations.equals(returnTypeAnnotations) - ? moshi.nextAdapter(factory, parameterTypes[0], qualifierAnnotations) - : moshi.adapter(parameterTypes[0], qualifierAnnotations); + delegate = + Types.equals(parameterTypes[0], returnType) + && qualifierAnnotations.equals(returnTypeAnnotations) + ? moshi.nextAdapter(factory, parameterTypes[0], qualifierAnnotations) + : moshi.adapter(parameterTypes[0], qualifierAnnotations); } - @Override public Object fromJson(Moshi moshi, JsonReader reader) + @Override + public Object fromJson(Moshi moshi, JsonReader reader) throws IOException, InvocationTargetException { Object intermediate = delegate.fromJson(reader); return invoke(intermediate); @@ -259,12 +298,15 @@ && parametersAreJsonAdapters(1, parameterTypes)) { }; } else { - throw new IllegalArgumentException("Unexpected signature for " + method + ".\n" - + "@FromJson method signatures may have one of the following structures:\n" - + " R fromJson(JsonReader jsonReader) throws ;\n" - + " R fromJson(JsonReader jsonReader," - + " JsonAdapter delegate, ) throws ;\n" - + " R fromJson(T value) throws ;\n"); + throw new IllegalArgumentException( + "Unexpected signature for " + + method + + ".\n" + + "@FromJson method signatures may have one of the following structures:\n" + + " R fromJson(JsonReader jsonReader) throws ;\n" + + " R fromJson(JsonReader jsonReader," + + " JsonAdapter delegate, ) throws ;\n" + + " R fromJson(T value) throws ;\n"); } } @@ -289,8 +331,14 @@ abstract static class AdapterMethod { final JsonAdapter[] jsonAdapters; final boolean nullable; - AdapterMethod(Type type, Set annotations, Object adapter, - Method method, int parameterCount, int adaptersOffset, boolean nullable) { + AdapterMethod( + Type type, + Set annotations, + Object adapter, + Method method, + int parameterCount, + int adaptersOffset, + boolean nullable) { this.type = canonicalize(type); this.annotations = annotations; this.adapter = adapter; diff --git a/moshi/src/main/java/com/squareup/moshi/ArrayJsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/ArrayJsonAdapter.java index 9f382bd82..2f6d65240 100644 --- a/moshi/src/main/java/com/squareup/moshi/ArrayJsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/ArrayJsonAdapter.java @@ -25,21 +25,23 @@ import javax.annotation.Nullable; /** - * Converts arrays to JSON arrays containing their converted contents. This - * supports both primitive and object arrays. + * Converts arrays to JSON arrays containing their converted contents. This supports both primitive + * and object arrays. */ final class ArrayJsonAdapter extends JsonAdapter { - public static final Factory FACTORY = new Factory() { - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - Type elementType = Types.arrayComponentType(type); - if (elementType == null) return null; - if (!annotations.isEmpty()) return null; - Class elementClass = Types.getRawType(elementType); - JsonAdapter elementAdapter = moshi.adapter(elementType); - return new ArrayJsonAdapter(elementClass, elementAdapter).nullSafe(); - } - }; + public static final Factory FACTORY = + new Factory() { + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + Type elementType = Types.arrayComponentType(type); + if (elementType == null) return null; + if (!annotations.isEmpty()) return null; + Class elementClass = Types.getRawType(elementType); + JsonAdapter elementAdapter = moshi.adapter(elementType); + return new ArrayJsonAdapter(elementClass, elementAdapter).nullSafe(); + } + }; private final Class elementClass; private final JsonAdapter elementAdapter; @@ -49,7 +51,8 @@ final class ArrayJsonAdapter extends JsonAdapter { this.elementAdapter = elementAdapter; } - @Override public Object fromJson(JsonReader reader) throws IOException { + @Override + public Object fromJson(JsonReader reader) throws IOException { List list = new ArrayList<>(); reader.beginArray(); while (reader.hasNext()) { @@ -63,7 +66,8 @@ final class ArrayJsonAdapter extends JsonAdapter { return array; } - @Override public void toJson(JsonWriter writer, Object value) throws IOException { + @Override + public void toJson(JsonWriter writer, Object value) throws IOException { writer.beginArray(); for (int i = 0, size = Array.getLength(value); i < size; i++) { elementAdapter.toJson(writer, Array.get(value, i)); @@ -71,7 +75,8 @@ final class ArrayJsonAdapter extends JsonAdapter { writer.endArray(); } - @Override public String toString() { + @Override + public String toString() { return elementAdapter + ".array()"; } } diff --git a/moshi/src/main/java/com/squareup/moshi/ClassFactory.java b/moshi/src/main/java/com/squareup/moshi/ClassFactory.java index b33203908..890b4716c 100644 --- a/moshi/src/main/java/com/squareup/moshi/ClassFactory.java +++ b/moshi/src/main/java/com/squareup/moshi/ClassFactory.java @@ -31,8 +31,8 @@ * @author Jesse Wilson */ abstract class ClassFactory { - abstract T newInstance() throws - InvocationTargetException, IllegalAccessException, InstantiationException; + abstract T newInstance() + throws InvocationTargetException, IllegalAccessException, InstantiationException; public static ClassFactory get(final Class rawType) { // Try to find a no-args constructor. May be any visibility including private. @@ -41,12 +41,15 @@ public static ClassFactory get(final Class rawType) { constructor.setAccessible(true); return new ClassFactory() { @SuppressWarnings("unchecked") // T is the same raw type as is requested - @Override public T newInstance() throws IllegalAccessException, InvocationTargetException, - InstantiationException { + @Override + public T newInstance() + throws IllegalAccessException, InvocationTargetException, InstantiationException { Object[] args = null; return (T) constructor.newInstance(args); } - @Override public String toString() { + + @Override + public String toString() { return rawType.getName(); } }; @@ -66,10 +69,13 @@ public static ClassFactory get(final Class rawType) { final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class); return new ClassFactory() { @SuppressWarnings("unchecked") - @Override public T newInstance() throws InvocationTargetException, IllegalAccessException { + @Override + public T newInstance() throws InvocationTargetException, IllegalAccessException { return (T) allocateInstance.invoke(unsafe, rawType); } - @Override public String toString() { + + @Override + public String toString() { return rawType.getName(); } }; @@ -85,19 +91,22 @@ public static ClassFactory get(final Class rawType) { // private static native Object newInstance(Class instantiationClass, int methodId); // } try { - Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod( - "getConstructorId", Class.class); + Method getConstructorId = + ObjectStreamClass.class.getDeclaredMethod("getConstructorId", Class.class); getConstructorId.setAccessible(true); final int constructorId = (Integer) getConstructorId.invoke(null, Object.class); - final Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance", - Class.class, int.class); + final Method newInstance = + ObjectStreamClass.class.getDeclaredMethod("newInstance", Class.class, int.class); newInstance.setAccessible(true); return new ClassFactory() { @SuppressWarnings("unchecked") - @Override public T newInstance() throws InvocationTargetException, IllegalAccessException { + @Override + public T newInstance() throws InvocationTargetException, IllegalAccessException { return (T) newInstance.invoke(null, rawType, constructorId); } - @Override public String toString() { + + @Override + public String toString() { return rawType.getName(); } }; @@ -115,15 +124,18 @@ public static ClassFactory get(final Class rawType) { // Class instantiationClass, Class constructorClass); // } try { - final Method newInstance = ObjectInputStream.class.getDeclaredMethod( - "newInstance", Class.class, Class.class); + final Method newInstance = + ObjectInputStream.class.getDeclaredMethod("newInstance", Class.class, Class.class); newInstance.setAccessible(true); return new ClassFactory() { @SuppressWarnings("unchecked") - @Override public T newInstance() throws InvocationTargetException, IllegalAccessException { + @Override + public T newInstance() throws InvocationTargetException, IllegalAccessException { return (T) newInstance.invoke(null, rawType, Object.class); } - @Override public String toString() { + + @Override + public String toString() { return rawType.getName(); } }; diff --git a/moshi/src/main/java/com/squareup/moshi/ClassJsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/ClassJsonAdapter.java index 9d335532b..554916882 100644 --- a/moshi/src/main/java/com/squareup/moshi/ClassJsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/ClassJsonAdapter.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.internal.Util.resolve; + import com.squareup.moshi.internal.Util; import java.io.IOException; import java.lang.annotation.Annotation; @@ -30,14 +32,13 @@ import java.util.TreeMap; import javax.annotation.Nullable; -import static com.squareup.moshi.internal.Util.resolve; - /** * Emits a regular class as a JSON object by mapping Java fields to JSON object properties. * *

    Platform Types

    - * Fields from platform classes are omitted from both serialization and deserialization unless - * they are either public or protected. This includes the following packages and their subpackages: + * + * Fields from platform classes are omitted from both serialization and deserialization unless they + * are either public or protected. This includes the following packages and their subpackages: * *
      *
    • android.* @@ -50,108 +51,122 @@ *
    */ final class ClassJsonAdapter extends JsonAdapter { - public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() { - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - if (!(type instanceof Class) && !(type instanceof ParameterizedType)) { - return null; - } - Class rawType = Types.getRawType(type); - if (rawType.isInterface() || rawType.isEnum()) return null; - if (!annotations.isEmpty()) return null; - if (Util.isPlatformType(rawType)) { - throwIfIsCollectionClass(type, List.class); - throwIfIsCollectionClass(type, Set.class); - throwIfIsCollectionClass(type, Map.class); - throwIfIsCollectionClass(type, Collection.class); - - String messagePrefix = "Platform " + rawType; - if (type instanceof ParameterizedType) { - messagePrefix += " in " + type; + public static final JsonAdapter.Factory FACTORY = + new JsonAdapter.Factory() { + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + if (!(type instanceof Class) && !(type instanceof ParameterizedType)) { + return null; + } + Class rawType = Types.getRawType(type); + if (rawType.isInterface() || rawType.isEnum()) return null; + if (!annotations.isEmpty()) return null; + if (Util.isPlatformType(rawType)) { + throwIfIsCollectionClass(type, List.class); + throwIfIsCollectionClass(type, Set.class); + throwIfIsCollectionClass(type, Map.class); + throwIfIsCollectionClass(type, Collection.class); + + String messagePrefix = "Platform " + rawType; + if (type instanceof ParameterizedType) { + messagePrefix += " in " + type; + } + throw new IllegalArgumentException( + messagePrefix + " requires explicit JsonAdapter to be registered"); + } + + if (rawType.isAnonymousClass()) { + throw new IllegalArgumentException( + "Cannot serialize anonymous class " + rawType.getName()); + } + if (rawType.isLocalClass()) { + throw new IllegalArgumentException("Cannot serialize local class " + rawType.getName()); + } + if (rawType.getEnclosingClass() != null && !Modifier.isStatic(rawType.getModifiers())) { + throw new IllegalArgumentException( + "Cannot serialize non-static nested class " + rawType.getName()); + } + if (Modifier.isAbstract(rawType.getModifiers())) { + throw new IllegalArgumentException( + "Cannot serialize abstract class " + rawType.getName()); + } + if (Util.isKotlin(rawType)) { + throw new IllegalArgumentException( + "Cannot serialize Kotlin type " + + rawType.getName() + + ". Reflective serialization of Kotlin classes without using kotlin-reflect has " + + "undefined and unexpected behavior. Please use KotlinJsonAdapter from the " + + "moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact."); + } + + ClassFactory classFactory = ClassFactory.get(rawType); + Map> fields = new TreeMap<>(); + for (Type t = type; t != Object.class; t = Types.getGenericSuperclass(t)) { + createFieldBindings(moshi, t, fields); + } + return new ClassJsonAdapter<>(classFactory, fields).nullSafe(); } - throw new IllegalArgumentException( - messagePrefix + " requires explicit JsonAdapter to be registered"); - } - if (rawType.isAnonymousClass()) { - throw new IllegalArgumentException("Cannot serialize anonymous class " + rawType.getName()); - } - if (rawType.isLocalClass()) { - throw new IllegalArgumentException("Cannot serialize local class " + rawType.getName()); - } - if (rawType.getEnclosingClass() != null && !Modifier.isStatic(rawType.getModifiers())) { - throw new IllegalArgumentException( - "Cannot serialize non-static nested class " + rawType.getName()); - } - if (Modifier.isAbstract(rawType.getModifiers())) { - throw new IllegalArgumentException("Cannot serialize abstract class " + rawType.getName()); - } - if (Util.isKotlin(rawType)) { - throw new IllegalArgumentException("Cannot serialize Kotlin type " + rawType.getName() - + ". Reflective serialization of Kotlin classes without using kotlin-reflect has " - + "undefined and unexpected behavior. Please use KotlinJsonAdapter from the " - + "moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact."); - } - - ClassFactory classFactory = ClassFactory.get(rawType); - Map> fields = new TreeMap<>(); - for (Type t = type; t != Object.class; t = Types.getGenericSuperclass(t)) { - createFieldBindings(moshi, t, fields); - } - return new ClassJsonAdapter<>(classFactory, fields).nullSafe(); - } - - /** - * Throw clear error messages for the common beginner mistake of using the concrete - * collection classes instead of the collection interfaces, eg: ArrayList instead of List. - */ - private void throwIfIsCollectionClass(Type type, Class collectionInterface) { - Class rawClass = Types.getRawType(type); - if (collectionInterface.isAssignableFrom(rawClass)) { - throw new IllegalArgumentException( - "No JsonAdapter for " + type + ", you should probably use " - + collectionInterface.getSimpleName() + " instead of " + rawClass.getSimpleName() - + " (Moshi only supports the collection interfaces by default)" - + " or else register a custom JsonAdapter."); - } - } + /** + * Throw clear error messages for the common beginner mistake of using the concrete + * collection classes instead of the collection interfaces, eg: ArrayList instead of List. + */ + private void throwIfIsCollectionClass(Type type, Class collectionInterface) { + Class rawClass = Types.getRawType(type); + if (collectionInterface.isAssignableFrom(rawClass)) { + throw new IllegalArgumentException( + "No JsonAdapter for " + + type + + ", you should probably use " + + collectionInterface.getSimpleName() + + " instead of " + + rawClass.getSimpleName() + + " (Moshi only supports the collection interfaces by default)" + + " or else register a custom JsonAdapter."); + } + } - /** Creates a field binding for each of declared field of {@code type}. */ - private void createFieldBindings( - Moshi moshi, Type type, Map> fieldBindings) { - Class rawType = Types.getRawType(type); - boolean platformType = Util.isPlatformType(rawType); - for (Field field : rawType.getDeclaredFields()) { - if (!includeField(platformType, field.getModifiers())) continue; - - // Look up a type adapter for this type. - Type fieldType = resolve(type, rawType, field.getGenericType()); - Set annotations = Util.jsonAnnotations(field); - String fieldName = field.getName(); - JsonAdapter adapter = moshi.adapter(fieldType, annotations, fieldName); - - // Create the binding between field and JSON. - field.setAccessible(true); - - // Store it using the field's name. If there was already a field with this name, fail! - Json jsonAnnotation = field.getAnnotation(Json.class); - String name = jsonAnnotation != null ? jsonAnnotation.name() : fieldName; - FieldBinding fieldBinding = new FieldBinding<>(name, field, adapter); - FieldBinding replaced = fieldBindings.put(name, fieldBinding); - if (replaced != null) { - throw new IllegalArgumentException("Conflicting fields:\n" - + " " + replaced.field + "\n" - + " " + fieldBinding.field); + /** Creates a field binding for each of declared field of {@code type}. */ + private void createFieldBindings( + Moshi moshi, Type type, Map> fieldBindings) { + Class rawType = Types.getRawType(type); + boolean platformType = Util.isPlatformType(rawType); + for (Field field : rawType.getDeclaredFields()) { + if (!includeField(platformType, field.getModifiers())) continue; + + // Look up a type adapter for this type. + Type fieldType = resolve(type, rawType, field.getGenericType()); + Set annotations = Util.jsonAnnotations(field); + String fieldName = field.getName(); + JsonAdapter adapter = moshi.adapter(fieldType, annotations, fieldName); + + // Create the binding between field and JSON. + field.setAccessible(true); + + // Store it using the field's name. If there was already a field with this name, fail! + Json jsonAnnotation = field.getAnnotation(Json.class); + String name = jsonAnnotation != null ? jsonAnnotation.name() : fieldName; + FieldBinding fieldBinding = new FieldBinding<>(name, field, adapter); + FieldBinding replaced = fieldBindings.put(name, fieldBinding); + if (replaced != null) { + throw new IllegalArgumentException( + "Conflicting fields:\n" + + " " + + replaced.field + + "\n" + + " " + + fieldBinding.field); + } + } } - } - } - /** Returns true if fields with {@code modifiers} are included in the emitted JSON. */ - private boolean includeField(boolean platformType, int modifiers) { - if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) return false; - return Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers) || !platformType; - } - }; + /** Returns true if fields with {@code modifiers} are included in the emitted JSON. */ + private boolean includeField(boolean platformType, int modifiers) { + if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) return false; + return Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers) || !platformType; + } + }; private final ClassFactory classFactory; private final FieldBinding[] fieldsArray; @@ -160,11 +175,11 @@ private boolean includeField(boolean platformType, int modifiers) { ClassJsonAdapter(ClassFactory classFactory, Map> fieldsMap) { this.classFactory = classFactory; this.fieldsArray = fieldsMap.values().toArray(new FieldBinding[fieldsMap.size()]); - this.options = JsonReader.Options.of( - fieldsMap.keySet().toArray(new String[fieldsMap.size()])); + this.options = JsonReader.Options.of(fieldsMap.keySet().toArray(new String[fieldsMap.size()])); } - @Override public T fromJson(JsonReader reader) throws IOException { + @Override + public T fromJson(JsonReader reader) throws IOException { T result; try { result = classFactory.newInstance(); @@ -194,7 +209,8 @@ private boolean includeField(boolean platformType, int modifiers) { } } - @Override public void toJson(JsonWriter writer, T value) throws IOException { + @Override + public void toJson(JsonWriter writer, T value) throws IOException { try { writer.beginObject(); for (FieldBinding fieldBinding : fieldsArray) { @@ -207,7 +223,8 @@ private boolean includeField(boolean platformType, int modifiers) { } } - @Override public String toString() { + @Override + public String toString() { return "JsonAdapter(" + classFactory + ")"; } diff --git a/moshi/src/main/java/com/squareup/moshi/CollectionJsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/CollectionJsonAdapter.java index a027f2959..7c3dbc8bb 100644 --- a/moshi/src/main/java/com/squareup/moshi/CollectionJsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/CollectionJsonAdapter.java @@ -27,19 +27,21 @@ /** Converts collection types to JSON arrays containing their converted contents. */ abstract class CollectionJsonAdapter, T> extends JsonAdapter { - public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() { - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - Class rawType = Types.getRawType(type); - if (!annotations.isEmpty()) return null; - if (rawType == List.class || rawType == Collection.class) { - return newArrayListAdapter(type, moshi).nullSafe(); - } else if (rawType == Set.class) { - return newLinkedHashSetAdapter(type, moshi).nullSafe(); - } - return null; - } - }; + public static final JsonAdapter.Factory FACTORY = + new JsonAdapter.Factory() { + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + Class rawType = Types.getRawType(type); + if (!annotations.isEmpty()) return null; + if (rawType == List.class || rawType == Collection.class) { + return newArrayListAdapter(type, moshi).nullSafe(); + } else if (rawType == Set.class) { + return newLinkedHashSetAdapter(type, moshi).nullSafe(); + } + return null; + } + }; private final JsonAdapter elementAdapter; @@ -51,7 +53,8 @@ static JsonAdapter> newArrayListAdapter(Type type, Moshi moshi Type elementType = Types.collectionElementType(type, Collection.class); JsonAdapter elementAdapter = moshi.adapter(elementType); return new CollectionJsonAdapter, T>(elementAdapter) { - @Override Collection newCollection() { + @Override + Collection newCollection() { return new ArrayList<>(); } }; @@ -61,7 +64,8 @@ static JsonAdapter> newLinkedHashSetAdapter(Type type, Moshi moshi) { Type elementType = Types.collectionElementType(type, Collection.class); JsonAdapter elementAdapter = moshi.adapter(elementType); return new CollectionJsonAdapter, T>(elementAdapter) { - @Override Set newCollection() { + @Override + Set newCollection() { return new LinkedHashSet<>(); } }; @@ -69,7 +73,8 @@ static JsonAdapter> newLinkedHashSetAdapter(Type type, Moshi moshi) { abstract C newCollection(); - @Override public C fromJson(JsonReader reader) throws IOException { + @Override + public C fromJson(JsonReader reader) throws IOException { C result = newCollection(); reader.beginArray(); while (reader.hasNext()) { @@ -79,7 +84,8 @@ static JsonAdapter> newLinkedHashSetAdapter(Type type, Moshi moshi) { return result; } - @Override public void toJson(JsonWriter writer, C value) throws IOException { + @Override + public void toJson(JsonWriter writer, C value) throws IOException { writer.beginArray(); for (T element : value) { elementAdapter.toJson(writer, element); @@ -87,7 +93,8 @@ static JsonAdapter> newLinkedHashSetAdapter(Type type, Moshi moshi) { writer.endArray(); } - @Override public String toString() { + @Override + public String toString() { return elementAdapter + ".collection()"; } } diff --git a/moshi/src/main/java/com/squareup/moshi/FromJson.java b/moshi/src/main/java/com/squareup/moshi/FromJson.java index 960c61265..76c7712ab 100644 --- a/moshi/src/main/java/com/squareup/moshi/FromJson.java +++ b/moshi/src/main/java/com/squareup/moshi/FromJson.java @@ -22,5 +22,4 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface FromJson { -} +public @interface FromJson {} diff --git a/moshi/src/main/java/com/squareup/moshi/Json.java b/moshi/src/main/java/com/squareup/moshi/Json.java index 0da3be920..217051f00 100644 --- a/moshi/src/main/java/com/squareup/moshi/Json.java +++ b/moshi/src/main/java/com/squareup/moshi/Json.java @@ -15,12 +15,12 @@ */ package com.squareup.moshi; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - /** * Customizes how a field is encoded as JSON. * diff --git a/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java index e71bd0f33..1700f83ce 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonAdapter.java @@ -37,13 +37,16 @@ *

    Custom JsonAdapter implementations should be designed to be thread-safe. */ public abstract class JsonAdapter { - @CheckReturnValue public abstract @Nullable T fromJson(JsonReader reader) throws IOException; + @CheckReturnValue + public abstract @Nullable T fromJson(JsonReader reader) throws IOException; - @CheckReturnValue public final @Nullable T fromJson(BufferedSource source) throws IOException { + @CheckReturnValue + public final @Nullable T fromJson(BufferedSource source) throws IOException { return fromJson(JsonReader.of(source)); } - @CheckReturnValue public final @Nullable T fromJson(String string) throws IOException { + @CheckReturnValue + public final @Nullable T fromJson(String string) throws IOException { JsonReader reader = JsonReader.of(new Buffer().writeUtf8(string)); T result = fromJson(reader); if (!isLenient() && reader.peek() != JsonReader.Token.END_DOCUMENT) { @@ -59,7 +62,8 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio toJson(writer, value); } - @CheckReturnValue public final String toJson(@Nullable T value) { + @CheckReturnValue + public final String toJson(@Nullable T value) { Buffer buffer = new Buffer(); try { toJson(buffer, value); @@ -74,12 +78,13 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio * booleans, and nulls. * *

    Values encoded using {@code value(double)} or {@code value(long)} are modeled with the - * corresponding boxed type. Values encoded using {@code value(Number)} are modeled as a - * {@link Long} for boxed integer types ({@link Byte}, {@link Short}, {@link Integer}, and {@link - * Long}), as a {@link Double} for boxed floating point types ({@link Float} and {@link Double}), - * and as a {@link BigDecimal} for all other types. + * corresponding boxed type. Values encoded using {@code value(Number)} are modeled as a {@link + * Long} for boxed integer types ({@link Byte}, {@link Short}, {@link Integer}, and {@link Long}), + * as a {@link Double} for boxed floating point types ({@link Float} and {@link Double}), and as a + * {@link BigDecimal} for all other types. */ - @CheckReturnValue public final @Nullable Object toJsonValue(@Nullable T value) { + @CheckReturnValue + public final @Nullable Object toJsonValue(@Nullable T value) { JsonValueWriter writer = new JsonValueWriter(); try { toJson(writer, value); @@ -93,7 +98,8 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio * Decodes a Java value object from {@code value}, which must be comprised of maps, lists, * strings, numbers, booleans and nulls. */ - @CheckReturnValue public final @Nullable T fromJsonValue(@Nullable Object value) { + @CheckReturnValue + public final @Nullable T fromJsonValue(@Nullable Object value) { JsonValueReader reader = new JsonValueReader(value); try { return fromJson(reader); @@ -106,13 +112,17 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio * Returns a JSON adapter equal to this JSON adapter, but that serializes nulls when encoding * JSON. */ - @CheckReturnValue public final JsonAdapter serializeNulls() { + @CheckReturnValue + public final JsonAdapter serializeNulls() { final JsonAdapter delegate = this; return new JsonAdapter() { - @Override public @Nullable T fromJson(JsonReader reader) throws IOException { + @Override + public @Nullable T fromJson(JsonReader reader) throws IOException { return delegate.fromJson(reader); } - @Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException { + + @Override + public void toJson(JsonWriter writer, @Nullable T value) throws IOException { boolean serializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(true); try { @@ -121,10 +131,14 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio writer.setSerializeNulls(serializeNulls); } } - @Override boolean isLenient() { + + @Override + boolean isLenient() { return delegate.isLenient(); } - @Override public String toString() { + + @Override + public String toString() { return delegate + ".serializeNulls()"; } }; @@ -134,7 +148,8 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio * Returns a JSON adapter equal to this JSON adapter, but with support for reading and writing * nulls. */ - @CheckReturnValue public final JsonAdapter nullSafe() { + @CheckReturnValue + public final JsonAdapter nullSafe() { if (this instanceof NullSafeJsonAdapter) { return this; } @@ -148,7 +163,8 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio *

    Note that this adapter will not usually be invoked for absent values and so those must be * handled elsewhere. This should only be used to fail on explicit nulls. */ - @CheckReturnValue public final JsonAdapter nonNull() { + @CheckReturnValue + public final JsonAdapter nonNull() { if (this instanceof NonNullJsonAdapter) { return this; } @@ -156,10 +172,12 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio } /** Returns a JSON adapter equal to this, but is lenient when reading and writing. */ - @CheckReturnValue public final JsonAdapter lenient() { + @CheckReturnValue + public final JsonAdapter lenient() { final JsonAdapter delegate = this; return new JsonAdapter() { - @Override public @Nullable T fromJson(JsonReader reader) throws IOException { + @Override + public @Nullable T fromJson(JsonReader reader) throws IOException { boolean lenient = reader.isLenient(); reader.setLenient(true); try { @@ -168,7 +186,9 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio reader.setLenient(lenient); } } - @Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException { + + @Override + public void toJson(JsonWriter writer, @Nullable T value) throws IOException { boolean lenient = writer.isLenient(); writer.setLenient(true); try { @@ -177,10 +197,14 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio writer.setLenient(lenient); } } - @Override boolean isLenient() { + + @Override + boolean isLenient() { return true; } - @Override public String toString() { + + @Override + public String toString() { return delegate + ".lenient()"; } }; @@ -192,10 +216,12 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio * This constraint applies to both the top-level message handled by this type adapter as well as * to nested messages. */ - @CheckReturnValue public final JsonAdapter failOnUnknown() { + @CheckReturnValue + public final JsonAdapter failOnUnknown() { final JsonAdapter delegate = this; return new JsonAdapter() { - @Override public @Nullable T fromJson(JsonReader reader) throws IOException { + @Override + public @Nullable T fromJson(JsonReader reader) throws IOException { boolean skipForbidden = reader.failOnUnknown(); reader.setFailOnUnknown(true); try { @@ -204,13 +230,19 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio reader.setFailOnUnknown(skipForbidden); } } - @Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException { + + @Override + public void toJson(JsonWriter writer, @Nullable T value) throws IOException { delegate.toJson(writer, value); } - @Override boolean isLenient() { + + @Override + boolean isLenient() { return delegate.isLenient(); } - @Override public String toString() { + + @Override + public String toString() { return delegate + ".failOnUnknown()"; } }; @@ -224,16 +256,20 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio * * @param indent a string containing only whitespace. */ - @CheckReturnValue public JsonAdapter indent(final String indent) { + @CheckReturnValue + public JsonAdapter indent(final String indent) { if (indent == null) { throw new NullPointerException("indent == null"); } final JsonAdapter delegate = this; return new JsonAdapter() { - @Override public @Nullable T fromJson(JsonReader reader) throws IOException { + @Override + public @Nullable T fromJson(JsonReader reader) throws IOException { return delegate.fromJson(reader); } - @Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException { + + @Override + public void toJson(JsonWriter writer, @Nullable T value) throws IOException { String originalIndent = writer.getIndent(); writer.setIndent(indent); try { @@ -242,10 +278,14 @@ public final void toJson(BufferedSink sink, @Nullable T value) throws IOExceptio writer.setIndent(originalIndent); } } - @Override boolean isLenient() { + + @Override + boolean isLenient() { return delegate.isLenient(); } - @Override public String toString() { + + @Override + public String toString() { return delegate + ".indent(\"" + indent + "\")"; } }; @@ -265,6 +305,7 @@ public interface Factory { * {@link Moshi#nextAdapter} to delegate to the underlying adapter of the same type. */ @CheckReturnValue - @Nullable JsonAdapter create(Type type, Set annotations, Moshi moshi); + @Nullable + JsonAdapter create(Type type, Set annotations, Moshi moshi); } } diff --git a/moshi/src/main/java/com/squareup/moshi/JsonClass.java b/moshi/src/main/java/com/squareup/moshi/JsonClass.java index 120b01074..d625d039f 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonClass.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonClass.java @@ -15,15 +15,13 @@ */ package com.squareup.moshi; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.reflect.Type; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Customizes how a type is encoded as JSON. - */ +/** Customizes how a type is encoded as JSON. */ @Retention(RUNTIME) @Documented public @interface JsonClass { @@ -32,15 +30,14 @@ * *

    There are currently some restrictions on which types that can be used with generated * adapters: + * *

      - *
    • - * The class must be implemented in Kotlin (unless using a custom generator, see - * {@link #generator()}). - *
    • - *
    • The class may not be an abstract class, an inner class, or a local class.
    • - *
    • All superclasses must be implemented in Kotlin.
    • - *
    • All properties must be public, protected, or internal.
    • - *
    • All properties must be either non-transient or have a default value.
    • + *
    • The class must be implemented in Kotlin (unless using a custom generator, see {@link + * #generator()}). + *
    • The class may not be an abstract class, an inner class, or a local class. + *
    • All superclasses must be implemented in Kotlin. + *
    • All properties must be public, protected, or internal. + *
    • All properties must be either non-transient or have a default value. *
    */ boolean generateAdapter(); @@ -48,29 +45,28 @@ /** * An optional custom generator tag used to indicate which generator should be used. If empty, * Moshi's annotation processor will generate an adapter for the annotated type. If not empty, - * Moshi's processor will skip it and defer to a custom generator. This can be used to allow - * other custom code generation tools to run and still allow Moshi to read their generated - * JsonAdapter outputs. + * Moshi's processor will skip it and defer to a custom generator. This can be used to allow other + * custom code generation tools to run and still allow Moshi to read their generated JsonAdapter + * outputs. * *

    Requirements for generated adapter class signatures: + * *

      - *
    • - * The generated adapter must subclass {@link JsonAdapter} and be parameterized by this type. - *
    • - *
    • - * {@link Types#generatedJsonAdapterName} should be used for the fully qualified class name in - * order for Moshi to correctly resolve and load the generated JsonAdapter. - *
    • - *
    • The first parameter must be a {@link Moshi} instance.
    • - *
    • - * If generic, a second {@link Type Type[]} parameter should be declared to accept type arguments. - *
    • + *
    • The generated adapter must subclass {@link JsonAdapter} and be parameterized by this + * type. + *
    • {@link Types#generatedJsonAdapterName} should be used for the fully qualified class name + * in order for Moshi to correctly resolve and load the generated JsonAdapter. + *
    • The first parameter must be a {@link Moshi} instance. + *
    • If generic, a second {@link Type Type[]} parameter should be declared to accept type + * arguments. *
    * - *

    Example for a class "CustomType":

    {@code
    -   *   class CustomTypeJsonAdapter(moshi: Moshi, types: Array) : JsonAdapter() {
    -   *     // ...
    -   *   }
    +   * 

    Example for a class "CustomType": + * + *

    {@code
    +   * class CustomTypeJsonAdapter(moshi: Moshi, types: Array) : JsonAdapter() {
    +   *   // ...
    +   * }
        * }
    * *

    To help ensure your own generator meets requirements above, you can use Moshi’s built-in diff --git a/moshi/src/main/java/com/squareup/moshi/JsonDataException.java b/moshi/src/main/java/com/squareup/moshi/JsonDataException.java index 3bfbf4ff9..802fa3ec6 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonDataException.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonDataException.java @@ -22,16 +22,15 @@ * example, suppose the application expects a boolean but the JSON document contains a string. When * the call to {@link JsonReader#nextBoolean} is made, a {@code JsonDataException} is thrown. * - *

    Exceptions of this type should be fixed by either changing the application code to accept - * the unexpected JSON, or by changing the JSON to conform to the application's expectations. + *

    Exceptions of this type should be fixed by either changing the application code to accept the + * unexpected JSON, or by changing the JSON to conform to the application's expectations. * *

    This exception may also be triggered if a document's nesting exceeds 31 levels. This depth is * sufficient for all practical applications, but shallow enough to avoid uglier failures like * {@link StackOverflowError}. */ public final class JsonDataException extends RuntimeException { - public JsonDataException() { - } + public JsonDataException() {} public JsonDataException(@Nullable String message) { super(message); diff --git a/moshi/src/main/java/com/squareup/moshi/JsonQualifier.java b/moshi/src/main/java/com/squareup/moshi/JsonQualifier.java index 10c2f1e8c..23f64b55f 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonQualifier.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonQualifier.java @@ -15,16 +15,15 @@ */ package com.squareup.moshi; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - /** Annotates another annotation, causing it to specialize how values are encoded and decoded. */ @Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented -public @interface JsonQualifier { -} +public @interface JsonQualifier {} diff --git a/moshi/src/main/java/com/squareup/moshi/JsonReader.java b/moshi/src/main/java/com/squareup/moshi/JsonReader.java index d65429ef7..d21d56909 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonReader.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonReader.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi; +import static java.util.Collections.unmodifiableList; + import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; @@ -27,47 +29,46 @@ import okio.BufferedSource; import okio.ByteString; -import static java.util.Collections.unmodifiableList; - /** - * Reads a JSON (RFC 7159) - * encoded value as a stream of tokens. This stream includes both literal - * values (strings, numbers, booleans, and nulls) as well as the begin and - * end delimiters of objects and arrays. The tokens are traversed in - * depth-first order, the same order that they appear in the JSON document. - * Within JSON objects, name/value pairs are represented by a single token. + * Reads a JSON (RFC 7159) encoded value as a + * stream of tokens. This stream includes both literal values (strings, numbers, booleans, and + * nulls) as well as the begin and end delimiters of objects and arrays. The tokens are traversed in + * depth-first order, the same order that they appear in the JSON document. Within JSON objects, + * name/value pairs are represented by a single token. * *

    Parsing JSON

    - * To create a recursive descent parser for your own JSON streams, first create - * an entry point method that creates a {@code JsonReader}. * - *

    Next, create handler methods for each structure in your JSON text. You'll - * need a method for each object type and for each array type. + * To create a recursive descent parser for your own JSON streams, first create an entry point + * method that creates a {@code JsonReader}. + * + *

    Next, create handler methods for each structure in your JSON text. You'll need a method for + * each object type and for each array type. + * *

      - *
    • Within array handling methods, first call {@link - * #beginArray} to consume the array's opening bracket. Then create a - * while loop that accumulates values, terminating when {@link #hasNext} - * is false. Finally, read the array's closing bracket by calling {@link + *
    • Within array handling methods, first call {@link #beginArray} to consume + * the array's opening bracket. Then create a while loop that accumulates values, terminating + * when {@link #hasNext} is false. Finally, read the array's closing bracket by calling {@link * #endArray}. - *
    • Within object handling methods, first call {@link - * #beginObject} to consume the object's opening brace. Then create a - * while loop that assigns values to local variables based on their name. - * This loop should terminate when {@link #hasNext} is false. Finally, + *
    • Within object handling methods, first call {@link #beginObject} to consume + * the object's opening brace. Then create a while loop that assigns values to local variables + * based on their name. This loop should terminate when {@link #hasNext} is false. Finally, * read the object's closing brace by calling {@link #endObject}. *
    - *

    When a nested object or array is encountered, delegate to the - * corresponding handler method. * - *

    When an unknown name is encountered, strict parsers should fail with an - * exception. Lenient parsers should call {@link #skipValue()} to recursively - * skip the value's nested tokens, which may otherwise conflict. + *

    When a nested object or array is encountered, delegate to the corresponding handler method. + * + *

    When an unknown name is encountered, strict parsers should fail with an exception. Lenient + * parsers should call {@link #skipValue()} to recursively skip the value's nested tokens, which may + * otherwise conflict. * - *

    If a value may be null, you should first check using {@link #peek()}. - * Null literals can be consumed using either {@link #nextNull()} or {@link - * #skipValue()}. + *

    If a value may be null, you should first check using {@link #peek()}. Null literals can be + * consumed using either {@link #nextNull()} or {@link #skipValue()}. * *

    Example

    - * Suppose we'd like to parse a stream of messages such as the following:
     {@code
    + *
    + * Suppose we'd like to parse a stream of messages such as the following:
    + *
    + * 
    {@code
      * [
      *   {
      *     "id": 912345678901,
    @@ -87,96 +88,99 @@
      *       "followers_count": 2
      *     }
      *   }
    - * ]}
    - * This code implements the parser for the above structure:
       {@code
    + * ]
    + * }
    * - * public List readJsonStream(BufferedSource source) throws IOException { - * JsonReader reader = JsonReader.of(source); - * try { - * return readMessagesArray(reader); - * } finally { - * reader.close(); - * } + * This code implements the parser for the above structure: + * + *
    {@code
    + * public List readJsonStream(BufferedSource source) throws IOException {
    + *   JsonReader reader = JsonReader.of(source);
    + *   try {
    + *     return readMessagesArray(reader);
    + *   } finally {
    + *     reader.close();
      *   }
    + * }
      *
    - *   public List readMessagesArray(JsonReader reader) throws IOException {
    - *     List messages = new ArrayList();
    + * public List readMessagesArray(JsonReader reader) throws IOException {
    + *   List messages = new ArrayList();
      *
    - *     reader.beginArray();
    - *     while (reader.hasNext()) {
    - *       messages.add(readMessage(reader));
    - *     }
    - *     reader.endArray();
    - *     return messages;
    + *   reader.beginArray();
    + *   while (reader.hasNext()) {
    + *     messages.add(readMessage(reader));
      *   }
    + *   reader.endArray();
    + *   return messages;
    + * }
      *
    - *   public Message readMessage(JsonReader reader) throws IOException {
    - *     long id = -1;
    - *     String text = null;
    - *     User user = null;
    - *     List geo = null;
    + * public Message readMessage(JsonReader reader) throws IOException {
    + *   long id = -1;
    + *   String text = null;
    + *   User user = null;
    + *   List geo = null;
      *
    - *     reader.beginObject();
    - *     while (reader.hasNext()) {
    - *       String name = reader.nextName();
    - *       if (name.equals("id")) {
    - *         id = reader.nextLong();
    - *       } else if (name.equals("text")) {
    - *         text = reader.nextString();
    - *       } else if (name.equals("geo") && reader.peek() != Token.NULL) {
    - *         geo = readDoublesArray(reader);
    - *       } else if (name.equals("user")) {
    - *         user = readUser(reader);
    - *       } else {
    - *         reader.skipValue();
    - *       }
    + *   reader.beginObject();
    + *   while (reader.hasNext()) {
    + *     String name = reader.nextName();
    + *     if (name.equals("id")) {
    + *       id = reader.nextLong();
    + *     } else if (name.equals("text")) {
    + *       text = reader.nextString();
    + *     } else if (name.equals("geo") && reader.peek() != Token.NULL) {
    + *       geo = readDoublesArray(reader);
    + *     } else if (name.equals("user")) {
    + *       user = readUser(reader);
    + *     } else {
    + *       reader.skipValue();
      *     }
    - *     reader.endObject();
    - *     return new Message(id, text, user, geo);
      *   }
    + *   reader.endObject();
    + *   return new Message(id, text, user, geo);
    + * }
      *
    - *   public List readDoublesArray(JsonReader reader) throws IOException {
    - *     List doubles = new ArrayList();
    + * public List readDoublesArray(JsonReader reader) throws IOException {
    + *   List doubles = new ArrayList();
      *
    - *     reader.beginArray();
    - *     while (reader.hasNext()) {
    - *       doubles.add(reader.nextDouble());
    - *     }
    - *     reader.endArray();
    - *     return doubles;
    + *   reader.beginArray();
    + *   while (reader.hasNext()) {
    + *     doubles.add(reader.nextDouble());
      *   }
    + *   reader.endArray();
    + *   return doubles;
    + * }
      *
    - *   public User readUser(JsonReader reader) throws IOException {
    - *     String username = null;
    - *     int followersCount = -1;
    + * public User readUser(JsonReader reader) throws IOException {
    + *   String username = null;
    + *   int followersCount = -1;
      *
    - *     reader.beginObject();
    - *     while (reader.hasNext()) {
    - *       String name = reader.nextName();
    - *       if (name.equals("name")) {
    - *         username = reader.nextString();
    - *       } else if (name.equals("followers_count")) {
    - *         followersCount = reader.nextInt();
    - *       } else {
    - *         reader.skipValue();
    - *       }
    + *   reader.beginObject();
    + *   while (reader.hasNext()) {
    + *     String name = reader.nextName();
    + *     if (name.equals("name")) {
    + *       username = reader.nextString();
    + *     } else if (name.equals("followers_count")) {
    + *       followersCount = reader.nextInt();
    + *     } else {
    + *       reader.skipValue();
      *     }
    - *     reader.endObject();
    - *     return new User(username, followersCount);
    - *   }}
    + * } + * reader.endObject(); + * return new User(username, followersCount); + * } + * }
    * *

    Number Handling

    - * This reader permits numeric values to be read as strings and string values to - * be read as numbers. For example, both elements of the JSON array {@code - * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}. - * This behavior is intended to prevent lossy numeric conversions: double is - * JavaScript's only numeric type and very large values like {@code - * 9007199254740993} cannot be represented exactly on that platform. To minimize - * precision loss, extremely large values should be written and read as strings - * in JSON. * - *

    Each {@code JsonReader} may be used to read a single JSON stream. Instances - * of this class are not thread safe. + * This reader permits numeric values to be read as strings and string values to be read as numbers. + * For example, both elements of the JSON array {@code [1, "1"]} may be read using either {@link + * #nextInt} or {@link #nextString}. This behavior is intended to prevent lossy numeric conversions: + * double is JavaScript's only numeric type and very large values like {@code 9007199254740993} + * cannot be represented exactly on that platform. To minimize precision loss, extremely large + * values should be written and read as strings in JSON. + * + *

    Each {@code JsonReader} may be used to read a single JSON stream. Instances of this class are + * not thread safe. */ public abstract class JsonReader implements Closeable { // The nesting stack. Using a manual array rather than an ArrayList saves 20%. This stack will @@ -194,7 +198,8 @@ public abstract class JsonReader implements Closeable { boolean failOnUnknown; /** Returns a new instance that reads UTF-8 encoded JSON from {@code source}. */ - @CheckReturnValue public static JsonReader of(BufferedSource source) { + @CheckReturnValue + public static JsonReader of(BufferedSource source) { return new JsonUtf8Reader(source); } @@ -228,8 +233,8 @@ final void pushScope(int newTop) { } /** - * Throws a new IO exception with the given message and a context snippet - * with this reader's content. + * Throws a new IO exception with the given message and a context snippet with this reader's + * content. */ final JsonEncodingException syntaxError(String message) throws JsonEncodingException { throw new JsonEncodingException(message + " at path " + getPath()); @@ -237,36 +242,39 @@ final JsonEncodingException syntaxError(String message) throws JsonEncodingExcep final JsonDataException typeMismatch(@Nullable Object value, Object expected) { if (value == null) { - return new JsonDataException( - "Expected " + expected + " but was null at path " + getPath()); + return new JsonDataException("Expected " + expected + " but was null at path " + getPath()); } else { - return new JsonDataException("Expected " + expected + " but was " + value + ", a " - + value.getClass().getName() + ", at path " + getPath()); + return new JsonDataException( + "Expected " + + expected + + " but was " + + value + + ", a " + + value.getClass().getName() + + ", at path " + + getPath()); } } /** - * Configure this parser to be liberal in what it accepts. By default - * this parser is strict and only accepts JSON as specified by RFC 7159. Setting the - * parser to lenient causes it to ignore the following syntax errors: + * Configure this parser to be liberal in what it accepts. By default this parser is strict and + * only accepts JSON as specified by RFC 7159. + * Setting the parser to lenient causes it to ignore the following syntax errors: * *

      - *
    • Streams that include multiple top-level values. With strict parsing, - * each stream must contain exactly one top-level value. - *
    • Numbers may be {@linkplain Double#isNaN() NaNs} or {@link - * Double#isInfinite() infinities}. - *
    • End of line comments starting with {@code //} or {@code #} and - * ending with a newline character. - *
    • C-style comments starting with {@code /*} and ending with - * {@code *}{@code /}. Such comments may not be nested. + *
    • Streams that include multiple top-level values. With strict parsing, each stream must + * contain exactly one top-level value. + *
    • Numbers may be {@linkplain Double#isNaN() NaNs} or {@link Double#isInfinite() + * infinities}. + *
    • End of line comments starting with {@code //} or {@code #} and ending with a newline + * character. + *
    • C-style comments starting with {@code /*} and ending with {@code *}{@code /}. Such + * comments may not be nested. *
    • Names that are unquoted or {@code 'single quoted'}. *
    • Strings that are unquoted or {@code 'single quoted'}. *
    • Array elements separated by {@code ;} instead of {@code ,}. - *
    • Unnecessary array separators. These are interpreted as if null - * was the omitted value. - *
    • Names and values separated by {@code =} or {@code =>} instead of - * {@code :}. + *
    • Unnecessary array separators. These are interpreted as if null was the omitted value. + *
    • Names and values separated by {@code =} or {@code =>} instead of {@code :}. *
    • Name/value pairs separated by {@code ;} instead of {@code ,}. *
    */ @@ -274,10 +282,9 @@ public final void setLenient(boolean lenient) { this.lenient = lenient; } - /** - * Returns true if this parser is liberal in what it accepts. - */ - @CheckReturnValue public final boolean isLenient() { + /** Returns true if this parser is liberal in what it accepts. */ + @CheckReturnValue + public final boolean isLenient() { return lenient; } @@ -293,10 +300,9 @@ public final void setFailOnUnknown(boolean failOnUnknown) { this.failOnUnknown = failOnUnknown; } - /** - * Returns true if this parser forbids skipping names and values. - */ - @CheckReturnValue public final boolean failOnUnknown() { + /** Returns true if this parser forbids skipping names and values. */ + @CheckReturnValue + public final boolean failOnUnknown() { return failOnUnknown; } @@ -307,8 +313,8 @@ public final void setFailOnUnknown(boolean failOnUnknown) { public abstract void beginArray() throws IOException; /** - * Consumes the next token from the JSON stream and asserts that it is the - * end of the current array. + * Consumes the next token from the JSON stream and asserts that it is the end of the current + * array. */ public abstract void endArray() throws IOException; @@ -324,28 +330,28 @@ public final void setFailOnUnknown(boolean failOnUnknown) { */ public abstract void endObject() throws IOException; - /** - * Returns true if the current array or object has another element. - */ - @CheckReturnValue public abstract boolean hasNext() throws IOException; + /** Returns true if the current array or object has another element. */ + @CheckReturnValue + public abstract boolean hasNext() throws IOException; - /** - * Returns the type of the next token without consuming it. - */ - @CheckReturnValue public abstract Token peek() throws IOException; + /** Returns the type of the next token without consuming it. */ + @CheckReturnValue + public abstract Token peek() throws IOException; /** * Returns the next token, a {@linkplain Token#NAME property name}, and consumes it. * * @throws JsonDataException if the next token in the stream is not a property name. */ - @CheckReturnValue public abstract String nextName() throws IOException; + @CheckReturnValue + public abstract String nextName() throws IOException; /** * If the next token is a {@linkplain Token#NAME property name} that's in {@code options}, this * consumes it and returns its index. Otherwise this returns -1 and no name is consumed. */ - @CheckReturnValue public abstract int selectName(Options options) throws IOException; + @CheckReturnValue + public abstract int selectName(Options options) throws IOException; /** * Skips the next token, consuming it. This method is intended for use when the JSON token stream @@ -368,7 +374,8 @@ public final void setFailOnUnknown(boolean failOnUnknown) { * If the next token is a {@linkplain Token#STRING string} that's in {@code options}, this * consumes it and returns its index. Otherwise this returns -1 and no string is consumed. */ - @CheckReturnValue public abstract int selectString(Options options) throws IOException; + @CheckReturnValue + public abstract int selectString(Options options) throws IOException; /** * Returns the {@linkplain Token#BOOLEAN boolean} value of the next token, consuming it. @@ -430,7 +437,7 @@ public final void setFailOnUnknown(boolean failOnUnknown) { * null, map, or list, according to the JSON structure. * * @throws JsonDataException if the next token is not a literal value, if a JSON object has a - * duplicate key. + * duplicate key. * @see JsonWriter#jsonValue(Object) */ public final @Nullable Object readJsonValue() throws IOException { @@ -452,8 +459,15 @@ public final void setFailOnUnknown(boolean failOnUnknown) { Object value = readJsonValue(); Object replaced = map.put(name, value); if (replaced != null) { - throw new JsonDataException("Map key '" + name + "' has multiple values at path " - + getPath() + ": " + replaced + " and " + value); + throw new JsonDataException( + "Map key '" + + name + + "' has multiple values at path " + + getPath() + + ": " + + replaced + + " and " + + value); } } endObject(); @@ -484,30 +498,31 @@ public final void setFailOnUnknown(boolean failOnUnknown) { *

    For example, we can use {@code peekJson()} to lookahead and read the same data multiple * times. * - *

     {@code
    +   * 
    {@code
    +   * Buffer buffer = new Buffer();
    +   * buffer.writeUtf8("[123, 456, 789]")
        *
    -   *   Buffer buffer = new Buffer();
    -   *   buffer.writeUtf8("[123, 456, 789]")
    +   * JsonReader jsonReader = JsonReader.of(buffer);
    +   * jsonReader.beginArray();
    +   * jsonReader.nextInt(); // Returns 123, reader contains 456, 789 and ].
        *
    -   *   JsonReader jsonReader = JsonReader.of(buffer);
    -   *   jsonReader.beginArray();
    -   *   jsonReader.nextInt(); // Returns 123, reader contains 456, 789 and ].
    +   * JsonReader peek = reader.peekJson();
    +   * peek.nextInt() // Returns 456.
    +   * peek.nextInt() // Returns 789.
    +   * peek.endArray()
        *
    -   *   JsonReader peek = reader.peekJson();
    -   *   peek.nextInt() // Returns 456.
    -   *   peek.nextInt() // Returns 789.
    -   *   peek.endArray()
    -   *
    -   *   jsonReader.nextInt() // Returns 456, reader contains 789 and ].
    +   * jsonReader.nextInt() // Returns 456, reader contains 789 and ].
        * }
    */ - @CheckReturnValue public abstract JsonReader peekJson(); + @CheckReturnValue + public abstract JsonReader peekJson(); /** - * Returns a JsonPath to - * the current location in the JSON value. + * Returns a JsonPath to the current location + * in the JSON value. */ - @CheckReturnValue public final String getPath() { + @CheckReturnValue + public final String getPath() { return JsonScope.getPath(stackSize, scopes, pathNames, pathIndices); } @@ -516,14 +531,14 @@ public final void setFailOnUnknown(boolean failOnUnknown) { * that arbitrary type adapters can use {@link #nextString} to read a name value. * *

    In this example, calling this method allows two sequential calls to {@link #nextString()}: - *

     {@code
        *
    -   *     JsonReader reader = JsonReader.of(new Buffer().writeUtf8("{\"a\":\"b\"}"));
    -   *     reader.beginObject();
    -   *     reader.promoteNameToValue();
    -   *     assertEquals("a", reader.nextString());
    -   *     assertEquals("b", reader.nextString());
    -   *     reader.endObject();
    +   * 
    {@code
    +   * JsonReader reader = JsonReader.of(new Buffer().writeUtf8("{\"a\":\"b\"}"));
    +   * reader.beginObject();
    +   * reader.promoteNameToValue();
    +   * assertEquals("a", reader.nextString());
    +   * assertEquals("b", reader.nextString());
    +   * reader.endObject();
        * }
    */ public abstract void promoteNameToValue() throws IOException; @@ -546,7 +561,8 @@ public List strings() { return unmodifiableList(Arrays.asList(strings)); } - @CheckReturnValue public static Options of(String... strings) { + @CheckReturnValue + public static Options of(String... strings) { try { ByteString[] result = new ByteString[strings.length]; Buffer buffer = new Buffer(); @@ -562,67 +578,56 @@ public List strings() { } } - /** - * A structure, name, or value type in a JSON-encoded string. - */ + /** A structure, name, or value type in a JSON-encoded string. */ public enum Token { /** - * The opening of a JSON array. Written using {@link JsonWriter#beginArray} - * and read using {@link JsonReader#beginArray}. + * The opening of a JSON array. Written using {@link JsonWriter#beginArray} and read using + * {@link JsonReader#beginArray}. */ BEGIN_ARRAY, /** - * The closing of a JSON array. Written using {@link JsonWriter#endArray} - * and read using {@link JsonReader#endArray}. + * The closing of a JSON array. Written using {@link JsonWriter#endArray} and read using {@link + * JsonReader#endArray}. */ END_ARRAY, /** - * The opening of a JSON object. Written using {@link JsonWriter#beginObject} - * and read using {@link JsonReader#beginObject}. + * The opening of a JSON object. Written using {@link JsonWriter#beginObject} and read using + * {@link JsonReader#beginObject}. */ BEGIN_OBJECT, /** - * The closing of a JSON object. Written using {@link JsonWriter#endObject} - * and read using {@link JsonReader#endObject}. + * The closing of a JSON object. Written using {@link JsonWriter#endObject} and read using + * {@link JsonReader#endObject}. */ END_OBJECT, /** - * A JSON property name. Within objects, tokens alternate between names and - * their values. Written using {@link JsonWriter#name} and read using {@link - * JsonReader#nextName} + * A JSON property name. Within objects, tokens alternate between names and their values. + * Written using {@link JsonWriter#name} and read using {@link JsonReader#nextName} */ NAME, - /** - * A JSON string. - */ + /** A JSON string. */ STRING, /** - * A JSON number represented in this API by a Java {@code double}, {@code - * long}, or {@code int}. + * A JSON number represented in this API by a Java {@code double}, {@code long}, or {@code int}. */ NUMBER, - /** - * A JSON {@code true} or {@code false}. - */ + /** A JSON {@code true} or {@code false}. */ BOOLEAN, - /** - * A JSON {@code null}. - */ + /** A JSON {@code null}. */ NULL, /** - * The end of the JSON stream. This sentinel value is returned by {@link - * JsonReader#peek()} to signal that the JSON-encoded value has no more - * tokens. + * The end of the JSON stream. This sentinel value is returned by {@link JsonReader#peek()} to + * signal that the JSON-encoded value has no more tokens. */ END_DOCUMENT } diff --git a/moshi/src/main/java/com/squareup/moshi/JsonScope.java b/moshi/src/main/java/com/squareup/moshi/JsonScope.java index 8f1b13c44..f16be6820 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonScope.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonScope.java @@ -17,8 +17,7 @@ /** Lexical scoping elements within a JSON reader or writer. */ final class JsonScope { - private JsonScope() { - } + private JsonScope() {} /** An array with no elements requires no separators or newlines before it is closed. */ static final int EMPTY_ARRAY = 1; diff --git a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java index dfcc10e11..0b8e56757 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.java @@ -28,8 +28,8 @@ final class JsonUtf8Reader extends JsonReader { private static final ByteString SINGLE_QUOTE_OR_SLASH = ByteString.encodeUtf8("'\\"); private static final ByteString DOUBLE_QUOTE_OR_SLASH = ByteString.encodeUtf8("\"\\"); - private static final ByteString UNQUOTED_STRING_TERMINALS - = ByteString.encodeUtf8("{}[]:, \n\t\r\f/\\;#="); + private static final ByteString UNQUOTED_STRING_TERMINALS = + ByteString.encodeUtf8("{}[]:, \n\t\r\f/\\;#="); private static final ByteString LINEFEED_OR_CARRIAGE_RETURN = ByteString.encodeUtf8("\n\r"); private static final ByteString CLOSING_BLOCK_COMMENT = ByteString.encodeUtf8("*/"); @@ -46,12 +46,14 @@ final class JsonUtf8Reader extends JsonReader { private static final int PEEKED_UNQUOTED = 10; /** When this is returned, the string value is stored in peekedString. */ private static final int PEEKED_BUFFERED = 11; + private static final int PEEKED_SINGLE_QUOTED_NAME = 12; private static final int PEEKED_DOUBLE_QUOTED_NAME = 13; private static final int PEEKED_UNQUOTED_NAME = 14; private static final int PEEKED_BUFFERED_NAME = 15; /** When this is returned, the integer value is stored in peekedLong. */ private static final int PEEKED_LONG = 16; + private static final int PEEKED_NUMBER = 17; private static final int PEEKED_EOF = 18; @@ -67,25 +69,23 @@ final class JsonUtf8Reader extends JsonReader { /** The input JSON. */ private final BufferedSource source; + private final Buffer buffer; private int peeked = PEEKED_NONE; /** - * A peeked value that was composed entirely of digits with an optional - * leading dash. Positive values may not have a leading 0. + * A peeked value that was composed entirely of digits with an optional leading dash. Positive + * values may not have a leading 0. */ private long peekedLong; - /** - * The number of characters in a peeked number literal. - */ + /** The number of characters in a peeked number literal. */ private int peekedNumberLength; /** - * A peeked string that should be parsed on the next double, long or string. - * This is populated before a numeric value is parsed and used if that parsing - * fails. + * A peeked string that should be parsed on the next double, long or string. This is populated + * before a numeric value is parsed and used if that parsing fails. */ private @Nullable String peekedString; @@ -119,7 +119,8 @@ final class JsonUtf8Reader extends JsonReader { } } - @Override public void beginArray() throws IOException { + @Override + public void beginArray() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -129,12 +130,13 @@ final class JsonUtf8Reader extends JsonReader { pathIndices[stackSize - 1] = 0; peeked = PEEKED_NONE; } else { - throw new JsonDataException("Expected BEGIN_ARRAY but was " + peek() - + " at path " + getPath()); + throw new JsonDataException( + "Expected BEGIN_ARRAY but was " + peek() + " at path " + getPath()); } } - @Override public void endArray() throws IOException { + @Override + public void endArray() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -144,12 +146,12 @@ final class JsonUtf8Reader extends JsonReader { pathIndices[stackSize - 1]++; peeked = PEEKED_NONE; } else { - throw new JsonDataException("Expected END_ARRAY but was " + peek() - + " at path " + getPath()); + throw new JsonDataException("Expected END_ARRAY but was " + peek() + " at path " + getPath()); } } - @Override public void beginObject() throws IOException { + @Override + public void beginObject() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -158,12 +160,13 @@ final class JsonUtf8Reader extends JsonReader { pushScope(JsonScope.EMPTY_OBJECT); peeked = PEEKED_NONE; } else { - throw new JsonDataException("Expected BEGIN_OBJECT but was " + peek() - + " at path " + getPath()); + throw new JsonDataException( + "Expected BEGIN_OBJECT but was " + peek() + " at path " + getPath()); } } - @Override public void endObject() throws IOException { + @Override + public void endObject() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -174,12 +177,13 @@ final class JsonUtf8Reader extends JsonReader { pathIndices[stackSize - 1]++; peeked = PEEKED_NONE; } else { - throw new JsonDataException("Expected END_OBJECT but was " + peek() - + " at path " + getPath()); + throw new JsonDataException( + "Expected END_OBJECT but was " + peek() + " at path " + getPath()); } } - @Override public boolean hasNext() throws IOException { + @Override + public boolean hasNext() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -187,7 +191,8 @@ final class JsonUtf8Reader extends JsonReader { return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY && p != PEEKED_EOF; } - @Override public Token peek() throws IOException { + @Override + public Token peek() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -474,8 +479,9 @@ private int peekNumber() throws IOException { return PEEKED_NONE; // Leading '0' prefix is not allowed (since it could be octal). } long newValue = value * 10 - (c - '0'); - fitsInLong &= value > MIN_INCOMPLETE_INTEGER - || (value == MIN_INCOMPLETE_INTEGER && newValue < value); + fitsInLong &= + value > MIN_INCOMPLETE_INTEGER + || (value == MIN_INCOMPLETE_INTEGER && newValue < value); value = newValue; } else if (last == NUMBER_CHAR_DECIMAL) { last = NUMBER_CHAR_FRACTION_DIGIT; @@ -486,12 +492,15 @@ private int peekNumber() throws IOException { } // We've read a complete number. Decide if it's a PEEKED_LONG or a PEEKED_NUMBER. - if (last == NUMBER_CHAR_DIGIT && fitsInLong && (value != Long.MIN_VALUE || negative) + if (last == NUMBER_CHAR_DIGIT + && fitsInLong + && (value != Long.MIN_VALUE || negative) && (value != 0 || !negative)) { peekedLong = negative ? value : -value; buffer.skip(i); return peeked = PEEKED_LONG; - } else if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT + } else if (last == NUMBER_CHAR_DIGIT + || last == NUMBER_CHAR_FRACTION_DIGIT || last == NUMBER_CHAR_EXP_DIGIT) { peekedNumberLength = i; return peeked = PEEKED_NUMBER; @@ -525,7 +534,8 @@ private boolean isLiteral(int c) throws IOException { } } - @Override public String nextName() throws IOException { + @Override + public String nextName() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -547,7 +557,8 @@ private boolean isLiteral(int c) throws IOException { return result; } - @Override public int selectName(Options options) throws IOException { + @Override + public int selectName(Options options) throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -584,7 +595,8 @@ private boolean isLiteral(int c) throws IOException { return result; } - @Override public void skipName() throws IOException { + @Override + public void skipName() throws IOException { if (failOnUnknown) { // Capture the peeked value before nextName() since it will reset its value. Token peeked = peek(); @@ -609,8 +621,8 @@ private boolean isLiteral(int c) throws IOException { } /** - * If {@code name} is in {@code options} this consumes it and returns its index. - * Otherwise this returns -1 and no name is consumed. + * If {@code name} is in {@code options} this consumes it and returns its index. Otherwise this + * returns -1 and no name is consumed. */ private int findName(String name, Options options) { for (int i = 0, size = options.strings.length; i < size; i++) { @@ -624,7 +636,8 @@ private int findName(String name, Options options) { return -1; } - @Override public String nextString() throws IOException { + @Override + public String nextString() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -651,7 +664,8 @@ private int findName(String name, Options options) { return result; } - @Override public int selectString(Options options) throws IOException { + @Override + public int selectString(Options options) throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -684,8 +698,8 @@ private int findName(String name, Options options) { } /** - * If {@code string} is in {@code options} this consumes it and returns its index. - * Otherwise this returns -1 and no string is consumed. + * If {@code string} is in {@code options} this consumes it and returns its index. Otherwise this + * returns -1 and no string is consumed. */ private int findString(String string, Options options) { for (int i = 0, size = options.strings.length; i < size; i++) { @@ -699,7 +713,8 @@ private int findString(String string, Options options) { return -1; } - @Override public boolean nextBoolean() throws IOException { + @Override + public boolean nextBoolean() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -716,7 +731,8 @@ private int findString(String string, Options options) { throw new JsonDataException("Expected a boolean but was " + peek() + " at path " + getPath()); } - @Override public @Nullable T nextNull() throws IOException { + @Override + public @Nullable T nextNull() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -730,7 +746,8 @@ private int findString(String string, Options options) { } } - @Override public double nextDouble() throws IOException { + @Override + public double nextDouble() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -759,12 +776,12 @@ private int findString(String string, Options options) { try { result = Double.parseDouble(peekedString); } catch (NumberFormatException e) { - throw new JsonDataException("Expected a double but was " + peekedString - + " at path " + getPath()); + throw new JsonDataException( + "Expected a double but was " + peekedString + " at path " + getPath()); } if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) { - throw new JsonEncodingException("JSON forbids NaN and infinities: " + result - + " at path " + getPath()); + throw new JsonEncodingException( + "JSON forbids NaN and infinities: " + result + " at path " + getPath()); } peekedString = null; peeked = PEEKED_NONE; @@ -772,7 +789,8 @@ private int findString(String string, Options options) { return result; } - @Override public long nextLong() throws IOException { + @Override + public long nextLong() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -787,9 +805,10 @@ private int findString(String string, Options options) { if (p == PEEKED_NUMBER) { peekedString = buffer.readUtf8(peekedNumberLength); } else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED) { - peekedString = p == PEEKED_DOUBLE_QUOTED - ? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) - : nextQuotedValue(SINGLE_QUOTE_OR_SLASH); + peekedString = + p == PEEKED_DOUBLE_QUOTED + ? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) + : nextQuotedValue(SINGLE_QUOTE_OR_SLASH); try { long result = Long.parseLong(peekedString); peeked = PEEKED_NONE; @@ -799,8 +818,7 @@ private int findString(String string, Options options) { // Fall back to parse as a BigDecimal below. } } else if (p != PEEKED_BUFFERED) { - throw new JsonDataException("Expected a long but was " + peek() - + " at path " + getPath()); + throw new JsonDataException("Expected a long but was " + peek() + " at path " + getPath()); } peeked = PEEKED_BUFFERED; @@ -809,8 +827,8 @@ private int findString(String string, Options options) { BigDecimal asDecimal = new BigDecimal(peekedString); result = asDecimal.longValueExact(); } catch (NumberFormatException | ArithmeticException e) { - throw new JsonDataException("Expected a long but was " + peekedString - + " at path " + getPath()); + throw new JsonDataException( + "Expected a long but was " + peekedString + " at path " + getPath()); } peekedString = null; peeked = PEEKED_NONE; @@ -879,7 +897,8 @@ private void skipUnquotedValue() throws IOException { buffer.skip(i != -1L ? i : buffer.size()); } - @Override public int nextInt() throws IOException { + @Override + public int nextInt() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -889,8 +908,8 @@ private void skipUnquotedValue() throws IOException { if (p == PEEKED_LONG) { result = (int) peekedLong; if (peekedLong != result) { // Make sure no precision was lost casting to 'int'. - throw new JsonDataException("Expected an int but was " + peekedLong - + " at path " + getPath()); + throw new JsonDataException( + "Expected an int but was " + peekedLong + " at path " + getPath()); } peeked = PEEKED_NONE; pathIndices[stackSize - 1]++; @@ -900,9 +919,10 @@ private void skipUnquotedValue() throws IOException { if (p == PEEKED_NUMBER) { peekedString = buffer.readUtf8(peekedNumberLength); } else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED) { - peekedString = p == PEEKED_DOUBLE_QUOTED - ? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) - : nextQuotedValue(SINGLE_QUOTE_OR_SLASH); + peekedString = + p == PEEKED_DOUBLE_QUOTED + ? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) + : nextQuotedValue(SINGLE_QUOTE_OR_SLASH); try { result = Integer.parseInt(peekedString); peeked = PEEKED_NONE; @@ -920,13 +940,13 @@ private void skipUnquotedValue() throws IOException { try { asDouble = Double.parseDouble(peekedString); } catch (NumberFormatException e) { - throw new JsonDataException("Expected an int but was " + peekedString - + " at path " + getPath()); + throw new JsonDataException( + "Expected an int but was " + peekedString + " at path " + getPath()); } result = (int) asDouble; if (result != asDouble) { // Make sure no precision was lost casting to 'int'. - throw new JsonDataException("Expected an int but was " + peekedString - + " at path " + getPath()); + throw new JsonDataException( + "Expected an int but was " + peekedString + " at path " + getPath()); } peekedString = null; peeked = PEEKED_NONE; @@ -934,7 +954,8 @@ private void skipUnquotedValue() throws IOException { return result; } - @Override public void close() throws IOException { + @Override + public void close() throws IOException { peeked = PEEKED_NONE; scopes[0] = JsonScope.CLOSED; stackSize = 1; @@ -942,7 +963,8 @@ private void skipUnquotedValue() throws IOException { source.close(); } - @Override public void skipValue() throws IOException { + @Override + public void skipValue() throws IOException { if (failOnUnknown) { throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath()); } @@ -982,8 +1004,7 @@ private void skipUnquotedValue() throws IOException { } else if (p == PEEKED_NUMBER) { buffer.skip(peekedNumberLength); } else if (p == PEEKED_EOF) { - throw new JsonDataException( - "Expected a value but was " + peek() + " at path " + getPath()); + throw new JsonDataException("Expected a value but was " + peek() + " at path " + getPath()); } peeked = PEEKED_NONE; } while (count != 0); @@ -993,9 +1014,8 @@ private void skipUnquotedValue() throws IOException { } /** - * Returns the next character in the stream that is neither whitespace nor a - * part of a comment. When this returns, the returned character is always at - * {@code buffer.getByte(0)}. + * Returns the next character in the stream that is neither whitespace nor a part of a comment. + * When this returns, the returned character is always at {@code buffer.getByte(0)}. */ private int nextNonWhitespace(boolean throwOnEof) throws IOException { /* @@ -1067,18 +1087,15 @@ private void checkLenient() throws IOException { } /** - * Advances the position until after the next newline character. If the line - * is terminated by "\r\n", the '\n' must be consumed as whitespace by the - * caller. + * Advances the position until after the next newline character. If the line is terminated by + * "\r\n", the '\n' must be consumed as whitespace by the caller. */ private void skipToEndOfLine() throws IOException { long index = source.indexOfElement(LINEFEED_OR_CARRIAGE_RETURN); buffer.skip(index != -1 ? index + 1 : buffer.size()); } - /** - * Skips through the next closing block comment. - */ + /** Skips through the next closing block comment. */ private boolean skipToEndOfBlockComment() throws IOException { long index = source.indexOf(CLOSING_BLOCK_COMMENT); boolean found = index != -1; @@ -1086,11 +1103,13 @@ private boolean skipToEndOfBlockComment() throws IOException { return found; } - @Override public JsonReader peekJson() { + @Override + public JsonReader peekJson() { return new JsonUtf8Reader(this); } - @Override public String toString() { + @Override + public String toString() { return "JsonReader(" + source + ")"; } @@ -1158,7 +1177,8 @@ private char readEscapeCharacter() throws IOException { } } - @Override public void promoteNameToValue() throws IOException { + @Override + public void promoteNameToValue() throws IOException { if (hasNext()) { peekedString = nextName(); peeked = PEEKED_BUFFERED; diff --git a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java index 19610394d..5cee11f51 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Writer.java @@ -15,14 +15,6 @@ */ package com.squareup.moshi; -import java.io.IOException; -import javax.annotation.Nullable; -import okio.Buffer; -import okio.BufferedSink; -import okio.Okio; -import okio.Sink; -import okio.Timeout; - import static com.squareup.moshi.JsonScope.DANGLING_NAME; import static com.squareup.moshi.JsonScope.EMPTY_ARRAY; import static com.squareup.moshi.JsonScope.EMPTY_DOCUMENT; @@ -32,6 +24,14 @@ import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT; import static com.squareup.moshi.JsonScope.STREAMING_VALUE; +import java.io.IOException; +import javax.annotation.Nullable; +import okio.Buffer; +import okio.BufferedSink; +import okio.Okio; +import okio.Sink; +import okio.Timeout; + final class JsonUtf8Writer extends JsonWriter { /* @@ -45,6 +45,7 @@ final class JsonUtf8Writer extends JsonWriter { * error. http://code.google.com/p/google-gson/issues/detail?id=341 */ private static final String[] REPLACEMENT_CHARS; + static { REPLACEMENT_CHARS = new String[128]; for (int i = 0; i <= 0x1f; i++) { @@ -75,12 +76,14 @@ final class JsonUtf8Writer extends JsonWriter { pushScope(EMPTY_DOCUMENT); } - @Override public void setIndent(String indent) { + @Override + public void setIndent(String indent) { super.setIndent(indent); this.separator = !indent.isEmpty() ? ": " : ":"; } - @Override public JsonWriter beginArray() throws IOException { + @Override + public JsonWriter beginArray() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Array cannot be used as a map key in JSON at path " + getPath()); @@ -89,11 +92,13 @@ final class JsonUtf8Writer extends JsonWriter { return open(EMPTY_ARRAY, NONEMPTY_ARRAY, '['); } - @Override public JsonWriter endArray() throws IOException { + @Override + public JsonWriter endArray() throws IOException { return close(EMPTY_ARRAY, NONEMPTY_ARRAY, ']'); } - @Override public JsonWriter beginObject() throws IOException { + @Override + public JsonWriter beginObject() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Object cannot be used as a map key in JSON at path " + getPath()); @@ -102,15 +107,13 @@ final class JsonUtf8Writer extends JsonWriter { return open(EMPTY_OBJECT, NONEMPTY_OBJECT, '{'); } - @Override public JsonWriter endObject() throws IOException { + @Override + public JsonWriter endObject() throws IOException { promoteValueToName = false; return close(EMPTY_OBJECT, NONEMPTY_OBJECT, '}'); } - /** - * Enters a new scope by appending any necessary whitespace and the given - * bracket. - */ + /** Enters a new scope by appending any necessary whitespace and the given bracket. */ private JsonWriter open(int empty, int nonempty, char openBracket) throws IOException { if (stackSize == flattenStackSize && (scopes[stackSize - 1] == empty || scopes[stackSize - 1] == nonempty)) { @@ -126,10 +129,7 @@ private JsonWriter open(int empty, int nonempty, char openBracket) throws IOExce return this; } - /** - * Closes the current scope by appending any necessary whitespace and the - * given bracket. - */ + /** Closes the current scope by appending any necessary whitespace and the given bracket. */ private JsonWriter close(int empty, int nonempty, char closeBracket) throws IOException { int context = peekScope(); if (context != nonempty && context != empty) { @@ -154,7 +154,8 @@ private JsonWriter close(int empty, int nonempty, char closeBracket) throws IOEx return this; } - @Override public JsonWriter name(String name) throws IOException { + @Override + public JsonWriter name(String name) throws IOException { if (name == null) { throw new NullPointerException("name == null"); } @@ -180,7 +181,8 @@ private void writeDeferredName() throws IOException { } } - @Override public JsonWriter value(String value) throws IOException { + @Override + public JsonWriter value(String value) throws IOException { if (value == null) { return nullValue(); } @@ -195,7 +197,8 @@ private void writeDeferredName() throws IOException { return this; } - @Override public JsonWriter nullValue() throws IOException { + @Override + public JsonWriter nullValue() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "null cannot be used as a map key in JSON at path " + getPath()); @@ -214,7 +217,8 @@ private void writeDeferredName() throws IOException { return this; } - @Override public JsonWriter value(boolean value) throws IOException { + @Override + public JsonWriter value(boolean value) throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Boolean cannot be used as a map key in JSON at path " + getPath()); @@ -226,14 +230,16 @@ private void writeDeferredName() throws IOException { return this; } - @Override public JsonWriter value(Boolean value) throws IOException { + @Override + public JsonWriter value(Boolean value) throws IOException { if (value == null) { return nullValue(); } return value(value.booleanValue()); } - @Override public JsonWriter value(double value) throws IOException { + @Override + public JsonWriter value(double value) throws IOException { if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) { throw new IllegalArgumentException("Numeric values must be finite, but was " + value); } @@ -248,7 +254,8 @@ private void writeDeferredName() throws IOException { return this; } - @Override public JsonWriter value(long value) throws IOException { + @Override + public JsonWriter value(long value) throws IOException { if (promoteValueToName) { promoteValueToName = false; return name(Long.toString(value)); @@ -260,7 +267,8 @@ private void writeDeferredName() throws IOException { return this; } - @Override public JsonWriter value(@Nullable Number value) throws IOException { + @Override + public JsonWriter value(@Nullable Number value) throws IOException { if (value == null) { return nullValue(); } @@ -281,7 +289,8 @@ private void writeDeferredName() throws IOException { return this; } - @Override public BufferedSink valueSink() throws IOException { + @Override + public BufferedSink valueSink() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "BufferedSink cannot be used as a map key in JSON at path " + getPath()); @@ -289,34 +298,39 @@ private void writeDeferredName() throws IOException { writeDeferredName(); beforeValue(); pushScope(STREAMING_VALUE); - return Okio.buffer(new Sink() { - @Override public void write(Buffer source, long byteCount) throws IOException { - sink.write(source, byteCount); - } - - @Override public void close() { - if (peekScope() != STREAMING_VALUE) { - throw new AssertionError(); - } - stackSize--; // Remove STREAMING_VALUE from the stack. - pathIndices[stackSize - 1]++; - } - - @Override public void flush() throws IOException { - sink.flush(); - } - - @Override public Timeout timeout() { - return Timeout.NONE; - } - }); + return Okio.buffer( + new Sink() { + @Override + public void write(Buffer source, long byteCount) throws IOException { + sink.write(source, byteCount); + } + + @Override + public void close() { + if (peekScope() != STREAMING_VALUE) { + throw new AssertionError(); + } + stackSize--; // Remove STREAMING_VALUE from the stack. + pathIndices[stackSize - 1]++; + } + + @Override + public void flush() throws IOException { + sink.flush(); + } + + @Override + public Timeout timeout() { + return Timeout.NONE; + } + }); } /** - * Ensures all buffered data is written to the underlying {@link Sink} - * and flushes that writer. + * Ensures all buffered data is written to the underlying {@link Sink} and flushes that writer. */ - @Override public void flush() throws IOException { + @Override + public void flush() throws IOException { if (stackSize == 0) { throw new IllegalStateException("JsonWriter is closed."); } @@ -328,7 +342,8 @@ private void writeDeferredName() throws IOException { * * @throws JsonDataException if the JSON document is incomplete. */ - @Override public void close() throws IOException { + @Override + public void close() throws IOException { sink.close(); int size = stackSize; @@ -386,8 +401,8 @@ private void newline() throws IOException { } /** - * Inserts any necessary separators and whitespace before a name. Also - * adjusts the stack to expect the name's value. + * Inserts any necessary separators and whitespace before a name. Also adjusts the stack to expect + * the name's value. */ private void beforeName() throws IOException { int context = peekScope(); @@ -401,9 +416,8 @@ private void beforeName() throws IOException { } /** - * Inserts any necessary separators and whitespace before a literal value, - * inline array, or inline object. Also adjusts the stack to expect either a - * closing bracket or another element. + * Inserts any necessary separators and whitespace before a literal value, inline array, or inline + * object. Also adjusts the stack to expect either a closing bracket or another element. */ @SuppressWarnings("fallthrough") private void beforeValue() throws IOException { @@ -411,8 +425,7 @@ private void beforeValue() throws IOException { switch (peekScope()) { case NONEMPTY_DOCUMENT: if (!lenient) { - throw new IllegalStateException( - "JSON must have only one top-level value."); + throw new IllegalStateException("JSON must have only one top-level value."); } // fall-through case EMPTY_DOCUMENT: // first in document diff --git a/moshi/src/main/java/com/squareup/moshi/JsonValueReader.java b/moshi/src/main/java/com/squareup/moshi/JsonValueReader.java index 85ba5074f..bc0f6c5cf 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonValueReader.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonValueReader.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.JsonScope.CLOSED; + import java.io.IOException; import java.math.BigDecimal; import java.util.Arrays; @@ -23,8 +25,6 @@ import java.util.Map; import javax.annotation.Nullable; -import static com.squareup.moshi.JsonScope.CLOSED; - /** * This class reads a JSON document by traversing a Java object comprising maps, lists, and JSON * primitives. It does depth-first traversal keeping a stack starting with the root object. During @@ -70,11 +70,12 @@ final class JsonValueReader extends JsonReader { } } - @Override public void beginArray() throws IOException { + @Override + public void beginArray() throws IOException { List peeked = require(List.class, Token.BEGIN_ARRAY); - JsonIterator iterator = new JsonIterator( - Token.END_ARRAY, peeked.toArray(new Object[peeked.size()]), 0); + JsonIterator iterator = + new JsonIterator(Token.END_ARRAY, peeked.toArray(new Object[peeked.size()]), 0); stack[stackSize - 1] = iterator; scopes[stackSize - 1] = JsonScope.EMPTY_ARRAY; pathIndices[stackSize - 1] = 0; @@ -85,7 +86,8 @@ final class JsonValueReader extends JsonReader { } } - @Override public void endArray() throws IOException { + @Override + public void endArray() throws IOException { JsonIterator peeked = require(JsonIterator.class, Token.END_ARRAY); if (peeked.endToken != Token.END_ARRAY || peeked.hasNext()) { throw typeMismatch(peeked, Token.END_ARRAY); @@ -93,11 +95,12 @@ final class JsonValueReader extends JsonReader { remove(); } - @Override public void beginObject() throws IOException { + @Override + public void beginObject() throws IOException { Map peeked = require(Map.class, Token.BEGIN_OBJECT); - JsonIterator iterator = new JsonIterator( - Token.END_OBJECT, peeked.entrySet().toArray(new Object[peeked.size()]), 0); + JsonIterator iterator = + new JsonIterator(Token.END_OBJECT, peeked.entrySet().toArray(new Object[peeked.size()]), 0); stack[stackSize - 1] = iterator; scopes[stackSize - 1] = JsonScope.EMPTY_OBJECT; @@ -107,7 +110,8 @@ final class JsonValueReader extends JsonReader { } } - @Override public void endObject() throws IOException { + @Override + public void endObject() throws IOException { JsonIterator peeked = require(JsonIterator.class, Token.END_OBJECT); if (peeked.endToken != Token.END_OBJECT || peeked.hasNext()) { throw typeMismatch(peeked, Token.END_OBJECT); @@ -116,14 +120,16 @@ final class JsonValueReader extends JsonReader { remove(); } - @Override public boolean hasNext() throws IOException { + @Override + public boolean hasNext() throws IOException { if (stackSize == 0) return false; Object peeked = stack[stackSize - 1]; return !(peeked instanceof Iterator) || ((Iterator) peeked).hasNext(); } - @Override public Token peek() throws IOException { + @Override + public Token peek() throws IOException { if (stackSize == 0) return Token.END_DOCUMENT; // If the top of the stack is an iterator, take its first element and push it on the stack. @@ -141,7 +147,8 @@ final class JsonValueReader extends JsonReader { throw typeMismatch(peeked, "a JSON value"); } - @Override public String nextName() throws IOException { + @Override + public String nextName() throws IOException { Map.Entry peeked = require(Map.Entry.class, Token.NAME); // Swap the Map.Entry for its value on the stack and return its key. @@ -151,7 +158,8 @@ final class JsonValueReader extends JsonReader { return result; } - @Override public int selectName(Options options) throws IOException { + @Override + public int selectName(Options options) throws IOException { Map.Entry peeked = require(Map.Entry.class, Token.NAME); String name = stringKey(peeked); for (int i = 0, length = options.strings.length; i < length; i++) { @@ -165,7 +173,8 @@ final class JsonValueReader extends JsonReader { return -1; } - @Override public void skipName() throws IOException { + @Override + public void skipName() throws IOException { if (failOnUnknown) { // Capture the peeked value before nextName() since it will reset its value. Token peeked = peek(); @@ -180,7 +189,8 @@ final class JsonValueReader extends JsonReader { pathNames[stackSize - 2] = "null"; } - @Override public String nextString() throws IOException { + @Override + public String nextString() throws IOException { Object peeked = (stackSize != 0 ? stack[stackSize - 1] : null); if (peeked instanceof String) { remove(); @@ -196,7 +206,8 @@ final class JsonValueReader extends JsonReader { throw typeMismatch(peeked, Token.STRING); } - @Override public int selectString(Options options) throws IOException { + @Override + public int selectString(Options options) throws IOException { Object peeked = (stackSize != 0 ? stack[stackSize - 1] : null); if (!(peeked instanceof String)) { @@ -216,19 +227,22 @@ final class JsonValueReader extends JsonReader { return -1; } - @Override public boolean nextBoolean() throws IOException { + @Override + public boolean nextBoolean() throws IOException { Boolean peeked = require(Boolean.class, Token.BOOLEAN); remove(); return peeked; } - @Override public @Nullable T nextNull() throws IOException { + @Override + public @Nullable T nextNull() throws IOException { require(Void.class, Token.NULL); remove(); return null; } - @Override public double nextDouble() throws IOException { + @Override + public double nextDouble() throws IOException { Object peeked = require(Object.class, Token.NUMBER); double result; @@ -244,14 +258,15 @@ final class JsonValueReader extends JsonReader { throw typeMismatch(peeked, Token.NUMBER); } if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) { - throw new JsonEncodingException("JSON forbids NaN and infinities: " + result - + " at path " + getPath()); + throw new JsonEncodingException( + "JSON forbids NaN and infinities: " + result + " at path " + getPath()); } remove(); return result; } - @Override public long nextLong() throws IOException { + @Override + public long nextLong() throws IOException { Object peeked = require(Object.class, Token.NUMBER); long result; @@ -275,7 +290,8 @@ final class JsonValueReader extends JsonReader { return result; } - @Override public int nextInt() throws IOException { + @Override + public int nextInt() throws IOException { Object peeked = require(Object.class, Token.NUMBER); int result; @@ -299,7 +315,8 @@ final class JsonValueReader extends JsonReader { return result; } - @Override public void skipValue() throws IOException { + @Override + public void skipValue() throws IOException { if (failOnUnknown) { throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath()); } @@ -326,18 +343,21 @@ final class JsonValueReader extends JsonReader { } } - @Override public JsonReader peekJson() { + @Override + public JsonReader peekJson() { return new JsonValueReader(this); } - @Override public void promoteNameToValue() throws IOException { + @Override + public void promoteNameToValue() throws IOException { if (hasNext()) { String name = nextName(); push(name); } } - @Override public void close() throws IOException { + @Override + public void close() throws IOException { Arrays.fill(stack, 0, stackSize, null); stack[0] = JSON_READER_CLOSED; scopes[0] = CLOSED; @@ -413,19 +433,23 @@ static final class JsonIterator implements Iterator, Cloneable { this.next = next; } - @Override public boolean hasNext() { + @Override + public boolean hasNext() { return next < array.length; } - @Override public Object next() { + @Override + public Object next() { return array[next++]; } - @Override public void remove() { + @Override + public void remove() { throw new UnsupportedOperationException(); } - @Override protected JsonIterator clone() { + @Override + protected JsonIterator clone() { // No need to copy the array; it's read-only. return new JsonIterator(endToken, array, next); } diff --git a/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java b/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java index 2aab89499..021263dd3 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonValueWriter.java @@ -15,6 +15,14 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.JsonScope.EMPTY_ARRAY; +import static com.squareup.moshi.JsonScope.EMPTY_DOCUMENT; +import static com.squareup.moshi.JsonScope.EMPTY_OBJECT; +import static com.squareup.moshi.JsonScope.NONEMPTY_DOCUMENT; +import static com.squareup.moshi.JsonScope.STREAMING_VALUE; +import static java.lang.Double.NEGATIVE_INFINITY; +import static java.lang.Double.POSITIVE_INFINITY; + import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; @@ -26,14 +34,6 @@ import okio.ForwardingSink; import okio.Okio; -import static com.squareup.moshi.JsonScope.EMPTY_ARRAY; -import static com.squareup.moshi.JsonScope.EMPTY_DOCUMENT; -import static com.squareup.moshi.JsonScope.EMPTY_OBJECT; -import static com.squareup.moshi.JsonScope.NONEMPTY_DOCUMENT; -import static com.squareup.moshi.JsonScope.STREAMING_VALUE; -import static java.lang.Double.NEGATIVE_INFINITY; -import static java.lang.Double.POSITIVE_INFINITY; - /** Writes JSON by building a Java object comprising maps, lists, and JSON primitives. */ final class JsonValueWriter extends JsonWriter { Object[] stack = new Object[32]; @@ -51,7 +51,8 @@ public Object root() { return stack[0]; } - @Override public JsonWriter beginArray() throws IOException { + @Override + public JsonWriter beginArray() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Array cannot be used as a map key in JSON at path " + getPath()); @@ -70,7 +71,8 @@ public Object root() { return this; } - @Override public JsonWriter endArray() throws IOException { + @Override + public JsonWriter endArray() throws IOException { if (peekScope() != EMPTY_ARRAY) { throw new IllegalStateException("Nesting problem."); } @@ -85,7 +87,8 @@ public Object root() { return this; } - @Override public JsonWriter beginObject() throws IOException { + @Override + public JsonWriter beginObject() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Object cannot be used as a map key in JSON at path " + getPath()); @@ -103,7 +106,8 @@ public Object root() { return this; } - @Override public JsonWriter endObject() throws IOException { + @Override + public JsonWriter endObject() throws IOException { if (peekScope() != EMPTY_OBJECT) { throw new IllegalStateException("Nesting problem."); } @@ -123,7 +127,8 @@ public Object root() { return this; } - @Override public JsonWriter name(String name) throws IOException { + @Override + public JsonWriter name(String name) throws IOException { if (name == null) { throw new NullPointerException("name == null"); } @@ -138,7 +143,8 @@ public Object root() { return this; } - @Override public JsonWriter value(@Nullable String value) throws IOException { + @Override + public JsonWriter value(@Nullable String value) throws IOException { if (promoteValueToName) { promoteValueToName = false; return name(value); @@ -148,7 +154,8 @@ public Object root() { return this; } - @Override public JsonWriter nullValue() throws IOException { + @Override + public JsonWriter nullValue() throws IOException { if (promoteValueToName) { throw new IllegalStateException( "null cannot be used as a map key in JSON at path " + getPath()); @@ -158,7 +165,8 @@ public Object root() { return this; } - @Override public JsonWriter value(boolean value) throws IOException { + @Override + public JsonWriter value(boolean value) throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Boolean cannot be used as a map key in JSON at path " + getPath()); @@ -168,7 +176,8 @@ public Object root() { return this; } - @Override public JsonWriter value(@Nullable Boolean value) throws IOException { + @Override + public JsonWriter value(@Nullable Boolean value) throws IOException { if (promoteValueToName) { throw new IllegalStateException( "Boolean cannot be used as a map key in JSON at path " + getPath()); @@ -178,7 +187,8 @@ public Object root() { return this; } - @Override public JsonWriter value(double value) throws IOException { + @Override + public JsonWriter value(double value) throws IOException { if (!lenient && (Double.isNaN(value) || value == NEGATIVE_INFINITY || value == POSITIVE_INFINITY)) { throw new IllegalArgumentException("Numeric values must be finite, but was " + value); @@ -192,7 +202,8 @@ public Object root() { return this; } - @Override public JsonWriter value(long value) throws IOException { + @Override + public JsonWriter value(long value) throws IOException { if (promoteValueToName) { promoteValueToName = false; return name(Long.toString(value)); @@ -202,7 +213,8 @@ public Object root() { return this; } - @Override public JsonWriter value(@Nullable Number value) throws IOException { + @Override + public JsonWriter value(@Nullable Number value) throws IOException { // If it's trivially converted to a long, do that. if (value instanceof Byte || value instanceof Short @@ -221,9 +233,8 @@ public Object root() { } // Everything else gets converted to a BigDecimal. - BigDecimal bigDecimalValue = value instanceof BigDecimal - ? ((BigDecimal) value) - : new BigDecimal(value.toString()); + BigDecimal bigDecimalValue = + value instanceof BigDecimal ? ((BigDecimal) value) : new BigDecimal(value.toString()); if (promoteValueToName) { promoteValueToName = false; return name(bigDecimalValue.toString()); @@ -233,7 +244,8 @@ public Object root() { return this; } - @Override public BufferedSink valueSink() { + @Override + public BufferedSink valueSink() { if (promoteValueToName) { throw new IllegalStateException( "BufferedSink cannot be used as a map key in JSON at path " + getPath()); @@ -244,27 +256,30 @@ public Object root() { pushScope(STREAMING_VALUE); final Buffer buffer = new Buffer(); - return Okio.buffer(new ForwardingSink(buffer) { - @Override public void close() throws IOException { - if (peekScope() != STREAMING_VALUE || stack[stackSize] != null) { - throw new AssertionError(); - } - stackSize--; // Remove STREAMING_VALUE from the stack. - - Object value = JsonReader.of(buffer).readJsonValue(); - boolean serializeNulls = JsonValueWriter.this.serializeNulls; - JsonValueWriter.this.serializeNulls = true; - try { - add(value); - } finally { - JsonValueWriter.this.serializeNulls = serializeNulls; - } - pathIndices[stackSize - 1]++; - } - }); + return Okio.buffer( + new ForwardingSink(buffer) { + @Override + public void close() throws IOException { + if (peekScope() != STREAMING_VALUE || stack[stackSize] != null) { + throw new AssertionError(); + } + stackSize--; // Remove STREAMING_VALUE from the stack. + + Object value = JsonReader.of(buffer).readJsonValue(); + boolean serializeNulls = JsonValueWriter.this.serializeNulls; + JsonValueWriter.this.serializeNulls = true; + try { + add(value); + } finally { + JsonValueWriter.this.serializeNulls = serializeNulls; + } + pathIndices[stackSize - 1]++; + } + }); } - @Override public void close() throws IOException { + @Override + public void close() throws IOException { int size = stackSize; if (size > 1 || size == 1 && scopes[size - 1] != NONEMPTY_DOCUMENT) { throw new IOException("Incomplete document"); @@ -272,7 +287,8 @@ public Object root() { stackSize = 0; } - @Override public void flush() throws IOException { + @Override + public void flush() throws IOException { if (stackSize == 0) { throw new IllegalStateException("JsonWriter is closed."); } @@ -294,8 +310,15 @@ private JsonValueWriter add(@Nullable Object newTop) { Map map = (Map) stack[stackSize - 1]; Object replaced = map.put(deferredName, newTop); if (replaced != null) { - throw new IllegalArgumentException("Map key '" + deferredName - + "' has multiple values at path " + getPath() + ": " + replaced + " and " + newTop); + throw new IllegalArgumentException( + "Map key '" + + deferredName + + "' has multiple values at path " + + getPath() + + ": " + + replaced + + " and " + + newTop); } } deferredName = null; diff --git a/moshi/src/main/java/com/squareup/moshi/JsonWriter.java b/moshi/src/main/java/com/squareup/moshi/JsonWriter.java index 1ff161050..7b45b408e 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonWriter.java +++ b/moshi/src/main/java/com/squareup/moshi/JsonWriter.java @@ -15,6 +15,11 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.JsonScope.EMPTY_ARRAY; +import static com.squareup.moshi.JsonScope.EMPTY_OBJECT; +import static com.squareup.moshi.JsonScope.NONEMPTY_ARRAY; +import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT; + import java.io.Closeable; import java.io.Flushable; import java.io.IOException; @@ -26,36 +31,32 @@ import okio.BufferedSink; import okio.BufferedSource; -import static com.squareup.moshi.JsonScope.EMPTY_ARRAY; -import static com.squareup.moshi.JsonScope.EMPTY_OBJECT; -import static com.squareup.moshi.JsonScope.NONEMPTY_ARRAY; -import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT; - /** - * Writes a JSON (RFC 7159) - * encoded value to a stream, one token at a time. The stream includes both - * literal values (strings, numbers, booleans and nulls) as well as the begin - * and end delimiters of objects and arrays. + * Writes a JSON (RFC 7159) encoded value to a + * stream, one token at a time. The stream includes both literal values (strings, numbers, booleans + * and nulls) as well as the begin and end delimiters of objects and arrays. * *

    Encoding JSON

    - * To encode your data as JSON, create a new {@code JsonWriter}. Each JSON - * document must contain one top-level array or object. Call methods on the - * writer as you walk the structure's contents, nesting arrays and objects as - * necessary: + * + * To encode your data as JSON, create a new {@code JsonWriter}. Each JSON document must contain one + * top-level array or object. Call methods on the writer as you walk the structure's contents, + * nesting arrays and objects as necessary: + * *
      - *
    • To write arrays, first call {@link #beginArray()}. - * Write each of the array's elements with the appropriate {@link #value} - * methods or by nesting other arrays and objects. Finally close the array - * using {@link #endArray()}. - *
    • To write objects, first call {@link #beginObject()}. - * Write each of the object's properties by alternating calls to - * {@link #name} with the property's value. Write property values with the - * appropriate {@link #value} method or by nesting other objects or arrays. - * Finally close the object using {@link #endObject()}. + *
    • To write arrays, first call {@link #beginArray()}. Write each of the + * array's elements with the appropriate {@link #value} methods or by nesting other arrays and + * objects. Finally close the array using {@link #endArray()}. + *
    • To write objects, first call {@link #beginObject()}. Write each of the + * object's properties by alternating calls to {@link #name} with the property's value. Write + * property values with the appropriate {@link #value} method or by nesting other objects or + * arrays. Finally close the object using {@link #endObject()}. *
    * *

    Example

    - * Suppose we'd like to encode a stream of messages such as the following:
     {@code
    + *
    + * Suppose we'd like to encode a stream of messages such as the following:
    + *
    + * 
    {@code
      * [
      *   {
      *     "id": 912345678901,
    @@ -75,56 +76,61 @@
      *       "followers_count": 2
      *     }
      *   }
    - * ]}
    - * This code encodes the above structure:
       {@code
    - *   public void writeJsonStream(BufferedSink sink, List messages) throws IOException {
    - *     JsonWriter writer = JsonWriter.of(sink);
    - *     writer.setIndent("  ");
    - *     writeMessagesArray(writer, messages);
    - *     writer.close();
    - *   }
    + * ]
    + * }
    * - * public void writeMessagesArray(JsonWriter writer, List messages) throws IOException { - * writer.beginArray(); - * for (Message message : messages) { - * writeMessage(writer, message); - * } - * writer.endArray(); - * } + * This code encodes the above structure: * - * public void writeMessage(JsonWriter writer, Message message) throws IOException { - * writer.beginObject(); - * writer.name("id").value(message.getId()); - * writer.name("text").value(message.getText()); - * if (message.getGeo() != null) { - * writer.name("geo"); - * writeDoublesArray(writer, message.getGeo()); - * } else { - * writer.name("geo").nullValue(); - * } - * writer.name("user"); - * writeUser(writer, message.getUser()); - * writer.endObject(); + *
    {@code
    + * public void writeJsonStream(BufferedSink sink, List messages) throws IOException {
    + *   JsonWriter writer = JsonWriter.of(sink);
    + *   writer.setIndent("  ");
    + *   writeMessagesArray(writer, messages);
    + *   writer.close();
    + * }
    + *
    + * public void writeMessagesArray(JsonWriter writer, List messages) throws IOException {
    + *   writer.beginArray();
    + *   for (Message message : messages) {
    + *     writeMessage(writer, message);
      *   }
    + *   writer.endArray();
    + * }
      *
    - *   public void writeUser(JsonWriter writer, User user) throws IOException {
    - *     writer.beginObject();
    - *     writer.name("name").value(user.getName());
    - *     writer.name("followers_count").value(user.getFollowersCount());
    - *     writer.endObject();
    + * public void writeMessage(JsonWriter writer, Message message) throws IOException {
    + *   writer.beginObject();
    + *   writer.name("id").value(message.getId());
    + *   writer.name("text").value(message.getText());
    + *   if (message.getGeo() != null) {
    + *     writer.name("geo");
    + *     writeDoublesArray(writer, message.getGeo());
    + *   } else {
    + *     writer.name("geo").nullValue();
      *   }
    + *   writer.name("user");
    + *   writeUser(writer, message.getUser());
    + *   writer.endObject();
    + * }
      *
    - *   public void writeDoublesArray(JsonWriter writer, List doubles) throws IOException {
    - *     writer.beginArray();
    - *     for (Double value : doubles) {
    - *       writer.value(value);
    - *     }
    - *     writer.endArray();
    - *   }}
    + * public void writeUser(JsonWriter writer, User user) throws IOException { + * writer.beginObject(); + * writer.name("name").value(user.getName()); + * writer.name("followers_count").value(user.getFollowersCount()); + * writer.endObject(); + * } * - *

    Each {@code JsonWriter} may be used to write a single JSON stream. - * Instances of this class are not thread safe. Calls that would result in a - * malformed JSON string will fail with an {@link IllegalStateException}. + * public void writeDoublesArray(JsonWriter writer, List doubles) throws IOException { + * writer.beginArray(); + * for (Double value : doubles) { + * writer.value(value); + * } + * writer.endArray(); + * } + * }

    + * + *

    Each {@code JsonWriter} may be used to write a single JSON stream. Instances of this class are + * not thread safe. Calls that would result in a malformed JSON string will fail with an {@link + * IllegalStateException}. */ public abstract class JsonWriter implements Closeable, Flushable { // The nesting stack. Using a manual array rather than an ArrayList saves 20%. This stack will @@ -140,6 +146,7 @@ public abstract class JsonWriter implements Closeable, Flushable { * pretty printing. */ String indent; + boolean lenient; boolean serializeNulls; boolean promoteValueToName; @@ -148,11 +155,11 @@ public abstract class JsonWriter implements Closeable, Flushable { * Controls the deepest stack size that has begin/end pairs flattened: * *

      - *
    • If -1, no begin/end pairs are being suppressed. - *
    • If positive, this is the deepest stack size whose begin/end pairs are eligible to be - * flattened. - *
    • If negative, it is the bitwise inverse (~) of the deepest stack size whose begin/end - * pairs have been flattened. + *
    • If -1, no begin/end pairs are being suppressed. + *
    • If positive, this is the deepest stack size whose begin/end pairs are eligible to be + * flattened. + *
    • If negative, it is the bitwise inverse (~) of the deepest stack size whose begin/end + * pairs have been flattened. *
    * *

    We differentiate between what layer would be flattened (positive) from what layer is being @@ -165,7 +172,8 @@ public abstract class JsonWriter implements Closeable, Flushable { int flattenStackSize = -1; /** Returns a new instance that writes UTF-8 encoded JSON to {@code sink}. */ - @CheckReturnValue public static JsonWriter of(BufferedSink sink) { + @CheckReturnValue + public static JsonWriter of(BufferedSink sink) { return new JsonUtf8Writer(sink); } @@ -210,10 +218,9 @@ final void replaceTop(int topOfStack) { } /** - * Sets the indentation string to be repeated for each level of indentation - * in the encoded document. If {@code indent.isEmpty()} the encoded document - * will be compact. Otherwise the encoded document will be more - * human-readable. + * Sets the indentation string to be repeated for each level of indentation in the encoded + * document. If {@code indent.isEmpty()} the encoded document will be compact. Otherwise the + * encoded document will be more human-readable. * * @param indent a string containing only whitespace. */ @@ -222,55 +229,56 @@ public void setIndent(String indent) { } /** - * Returns a string containing only whitespace, used for each level of - * indentation. If empty, the encoded document will be compact. + * Returns a string containing only whitespace, used for each level of indentation. If empty, the + * encoded document will be compact. */ - @CheckReturnValue public final String getIndent() { + @CheckReturnValue + public final String getIndent() { return indent != null ? indent : ""; } /** - * Configure this writer to relax its syntax rules. By default, this writer - * only emits well-formed JSON as specified by RFC 7159. Setting the writer - * to lenient permits the following: + * Configure this writer to relax its syntax rules. By default, this writer only emits well-formed + * JSON as specified by RFC 7159. Setting the + * writer to lenient permits the following: + * *

      - *
    • Top-level values of any type. With strict writing, the top-level - * value must be an object or an array. - *
    • Numbers may be {@linkplain Double#isNaN() NaNs} or {@linkplain - * Double#isInfinite() infinities}. + *
    • Top-level values of any type. With strict writing, the top-level value must be an object + * or an array. + *
    • Numbers may be {@linkplain Double#isNaN() NaNs} or {@linkplain Double#isInfinite() + * infinities}. *
    */ public final void setLenient(boolean lenient) { this.lenient = lenient; } - /** - * Returns true if this writer has relaxed syntax rules. - */ - @CheckReturnValue public final boolean isLenient() { + /** Returns true if this writer has relaxed syntax rules. */ + @CheckReturnValue + public final boolean isLenient() { return lenient; } /** - * Sets whether object members are serialized when their value is null. - * This has no impact on array elements. The default is false. + * Sets whether object members are serialized when their value is null. This has no impact on + * array elements. The default is false. */ public final void setSerializeNulls(boolean serializeNulls) { this.serializeNulls = serializeNulls; } /** - * Returns true if object members are serialized when their value is null. - * This has no impact on array elements. The default is false. + * Returns true if object members are serialized when their value is null. This has no impact on + * array elements. The default is false. */ - @CheckReturnValue public final boolean getSerializeNulls() { + @CheckReturnValue + public final boolean getSerializeNulls() { return serializeNulls; } /** - * Begins encoding a new array. Each call to this method must be paired with - * a call to {@link #endArray}. + * Begins encoding a new array. Each call to this method must be paired with a call to {@link + * #endArray}. * * @return this writer. */ @@ -284,8 +292,8 @@ public final void setSerializeNulls(boolean serializeNulls) { public abstract JsonWriter endArray() throws IOException; /** - * Begins encoding a new object. Each call to this method must be paired - * with a call to {@link #endObject}. + * Begins encoding a new object. Each call to this method must be paired with a call to {@link + * #endObject}. * * @return this writer. */ @@ -338,8 +346,8 @@ public final void setSerializeNulls(boolean serializeNulls) { /** * Encodes {@code value}. * - * @param value a finite value. May not be {@linkplain Double#isNaN() NaNs} or - * {@linkplain Double#isInfinite() infinities}. + * @param value a finite value. May not be {@linkplain Double#isNaN() NaNs} or {@linkplain + * Double#isInfinite() infinities}. * @return this writer. */ public abstract JsonWriter value(double value) throws IOException; @@ -354,15 +362,15 @@ public final void setSerializeNulls(boolean serializeNulls) { /** * Encodes {@code value}. * - * @param value a finite value. May not be {@linkplain Double#isNaN() NaNs} or - * {@linkplain Double#isInfinite() infinities}. + * @param value a finite value. May not be {@linkplain Double#isNaN() NaNs} or {@linkplain + * Double#isInfinite() infinities}. * @return this writer. */ public abstract JsonWriter value(@Nullable Number value) throws IOException; /** - * Writes {@code source} directly without encoding its contents. Equivalent to - * {@code try (BufferedSink sink = writer.valueSink()) { source.readAll(sink): }} + * Writes {@code source} directly without encoding its contents. Equivalent to {@code try + * (BufferedSink sink = writer.valueSink()) { source.readAll(sink): }} * * @see #valueSink() */ @@ -379,10 +387,10 @@ public final JsonWriter value(BufferedSource source) throws IOException { /** * Returns a {@link BufferedSink} into which arbitrary data can be written without any additional - * encoding. You must call {@link BufferedSink#close()} before interacting with this - * {@code JsonWriter} instance again. - *

    - * Since no validation is performed, options like {@link #setSerializeNulls} and other writer + * encoding. You must call {@link BufferedSink#close()} before interacting with this {@code + * JsonWriter} instance again. + * + *

    Since no validation is performed, options like {@link #setSerializeNulls} and other writer * configurations are not respected. */ @CheckReturnValue @@ -400,9 +408,10 @@ public final JsonWriter jsonValue(@Nullable Object value) throws IOException { 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()); + 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()); @@ -446,14 +455,14 @@ public final JsonWriter jsonValue(@Nullable Object value) throws IOException { * *

    In this example, calling this method allows two sequential calls to {@link #value(String)} * to produce the object, {@code {"a": "b"}}. - *

     {@code
    -   *
    -   *     JsonWriter writer = JsonWriter.of(...);
    -   *     writer.beginObject();
    -   *     writer.promoteValueToName();
    -   *     writer.value("a");
    -   *     writer.value("b");
    -   *     writer.endObject();
    +   *
    +   * 
    {@code
    +   * JsonWriter writer = JsonWriter.of(...);
    +   * writer.beginObject();
    +   * writer.promoteValueToName();
    +   * writer.value("a");
    +   * writer.value("b");
    +   * writer.endObject();
        * }
    */ public final void promoteValueToName() throws IOException { @@ -472,68 +481,66 @@ public final void promoteValueToName() throws IOException { *

    For example, the following creates JSON with nested arrays: {@code [1,[2,3,4],5]}. * *

    {@code
    -   *
    -   *   JsonAdapter> integersAdapter = ...
    -   *
    -   *   public void writeNumbers(JsonWriter writer) {
    -   *     writer.beginArray();
    -   *     writer.value(1);
    -   *     integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
    -   *     writer.value(5);
    -   *     writer.endArray();
    -   *   }
    +   * JsonAdapter> integersAdapter = ...
    +   *
    +   * public void writeNumbers(JsonWriter writer) {
    +   *   writer.beginArray();
    +   *   writer.value(1);
    +   *   integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
    +   *   writer.value(5);
    +   *   writer.endArray();
    +   * }
        * }
    * *

    With flattening we can create JSON with a single array {@code [1,2,3,4,5]}: * *

    {@code
    -   *
    -   *   JsonAdapter> integersAdapter = ...
    -   *
    -   *   public void writeNumbers(JsonWriter writer) {
    -   *     writer.beginArray();
    -   *     int token = writer.beginFlatten();
    -   *     writer.value(1);
    -   *     integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
    -   *     writer.value(5);
    -   *     writer.endFlatten(token);
    -   *     writer.endArray();
    -   *   }
    +   * JsonAdapter> integersAdapter = ...
    +   *
    +   * public void writeNumbers(JsonWriter writer) {
    +   *   writer.beginArray();
    +   *   int token = writer.beginFlatten();
    +   *   writer.value(1);
    +   *   integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
    +   *   writer.value(5);
    +   *   writer.endFlatten(token);
    +   *   writer.endArray();
    +   * }
        * }
    * *

    This method flattens arrays within arrays: * *

    {@code
    -   *
    -   *   Emit:       [1, [2, 3, 4], 5]
    -   *   To produce: [1, 2, 3, 4, 5]
    +   * Emit:       [1, [2, 3, 4], 5]
    +   * To produce: [1, 2, 3, 4, 5]
        * }
    * * It also flattens objects within objects. Do not call {@link #name} before writing a flattened * object. * *
    {@code
    -   *
    -   *   Emit:       {"a": 1, {"b": 2}, "c": 3}
    -   *   To Produce: {"a": 1, "b": 2, "c": 3}
    +   * Emit:       {"a": 1, {"b": 2}, "c": 3}
    +   * To Produce: {"a": 1, "b": 2, "c": 3}
        * }
    * * Other combinations are permitted but do not perform flattening. For example, objects inside of * arrays are not flattened: * *
    {@code
    -   *
    -   *   Emit:       [1, {"b": 2}, 3, [4, 5], 6]
    -   *   To Produce: [1, {"b": 2}, 3, 4, 5, 6]
    +   * Emit:       [1, {"b": 2}, 3, [4, 5], 6]
    +   * To Produce: [1, {"b": 2}, 3, 4, 5, 6]
        * }
    * *

    This method returns an opaque token. Callers must match all calls to this method with a call * to {@link #endFlatten} with the matching token. */ - @CheckReturnValue public final int beginFlatten() { + @CheckReturnValue + public final int beginFlatten() { int context = peekScope(); - if (context != NONEMPTY_OBJECT && context != EMPTY_OBJECT - && context != NONEMPTY_ARRAY && context != EMPTY_ARRAY) { + if (context != NONEMPTY_OBJECT + && context != EMPTY_OBJECT + && context != NONEMPTY_ARRAY + && context != EMPTY_ARRAY) { throw new IllegalStateException("Nesting problem."); } int token = flattenStackSize; @@ -547,10 +554,11 @@ public final void endFlatten(int token) { } /** - * Returns a JsonPath to - * the current location in the JSON value. + * Returns a JsonPath to the current location + * in the JSON value. */ - @CheckReturnValue public final String getPath() { + @CheckReturnValue + public final String getPath() { return JsonScope.getPath(stackSize, scopes, pathNames, pathIndices); } } diff --git a/moshi/src/main/java/com/squareup/moshi/LinkedHashTreeMap.java b/moshi/src/main/java/com/squareup/moshi/LinkedHashTreeMap.java index 536afb8d7..01d657f86 100644 --- a/moshi/src/main/java/com/squareup/moshi/LinkedHashTreeMap.java +++ b/moshi/src/main/java/com/squareup/moshi/LinkedHashTreeMap.java @@ -29,20 +29,20 @@ import java.util.Set; /** - * A map of comparable keys to values. Unlike {@code TreeMap}, this class uses - * insertion order for iteration order. Comparison order is only used as an - * optimization for efficient insertion and removal. + * A map of comparable keys to values. Unlike {@code TreeMap}, this class uses insertion order for + * iteration order. Comparison order is only used as an optimization for efficient insertion and + * removal. * - *

    This implementation was derived from Android 4.1's TreeMap and - * LinkedHashMap classes. + *

    This implementation was derived from Android 4.1's TreeMap and LinkedHashMap classes. */ final class LinkedHashTreeMap extends AbstractMap implements Serializable { - @SuppressWarnings({ "unchecked", "rawtypes" }) // to avoid Comparable>> - private static final Comparator NATURAL_ORDER = new Comparator() { - public int compare(Comparable a, Comparable b) { - return a.compareTo(b); - } - }; + @SuppressWarnings({"unchecked", "rawtypes"}) // to avoid Comparable>> + private static final Comparator NATURAL_ORDER = + new Comparator() { + public int compare(Comparable a, Comparable b) { + return a.compareTo(b); + } + }; Comparator comparator; Node[] table; @@ -51,47 +51,47 @@ public int compare(Comparable a, Comparable b) { int modCount = 0; int threshold; - /** - * Create a natural order, empty tree map whose keys must be mutually - * comparable and non-null. - */ + /** Create a natural order, empty tree map whose keys must be mutually comparable and non-null. */ LinkedHashTreeMap() { this(null); } /** - * Create a tree map ordered by {@code comparator}. This map's keys may only - * be null if {@code comparator} permits. + * Create a tree map ordered by {@code comparator}. This map's keys may only be null if {@code + * comparator} permits. * - * @param comparator the comparator to order elements with, or {@code null} to - * use the natural ordering. + * @param comparator the comparator to order elements with, or {@code null} to use the natural + * ordering. */ @SuppressWarnings({ - "unchecked", "rawtypes" // Unsafe! if comparator is null, this assumes K is comparable. + "unchecked", + "rawtypes" // Unsafe! if comparator is null, this assumes K is comparable. }) LinkedHashTreeMap(Comparator comparator) { - this.comparator = comparator != null - ? comparator - : (Comparator) NATURAL_ORDER; + this.comparator = comparator != null ? comparator : (Comparator) NATURAL_ORDER; this.header = new Node<>(); this.table = new Node[16]; // TODO: sizing/resizing policies this.threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity } - @Override public int size() { + @Override + public int size() { return size; } - @Override public V get(Object key) { + @Override + public V get(Object key) { Node node = findByObject(key); return node != null ? node.value : null; } - @Override public boolean containsKey(Object key) { + @Override + public boolean containsKey(Object key) { return findByObject(key) != null; } - @Override public V put(K key, V value) { + @Override + public V put(K key, V value) { if (key == null) { throw new NullPointerException("key == null"); } @@ -101,7 +101,8 @@ public int compare(Comparable a, Comparable b) { return result; } - @Override public void clear() { + @Override + public void clear() { Arrays.fill(table, null); size = 0; modCount++; @@ -117,7 +118,8 @@ public int compare(Comparable a, Comparable b) { header.next = header.prev = header; } - @Override public V remove(Object key) { + @Override + public V remove(Object key) { Node node = removeInternalByKey(key); return node != null ? node.value : null; } @@ -125,8 +127,7 @@ public int compare(Comparable a, Comparable b) { /** * Returns the node at or adjacent to the given key, creating it if requested. * - * @throws ClassCastException if {@code key} and the tree's keys aren't - * mutually comparable. + * @throws ClassCastException if {@code key} and the tree's keys aren't mutually comparable. */ Node find(K key, boolean create) { Comparator comparator = this.comparator; @@ -139,14 +140,14 @@ Node find(K key, boolean create) { if (nearest != null) { // Micro-optimization: avoid polymorphic calls to Comparator.compare(). @SuppressWarnings("unchecked") // Throws a ClassCastException below if there's trouble. - Comparable comparableKey = (comparator == NATURAL_ORDER) - ? (Comparable) key - : null; + Comparable comparableKey = + (comparator == NATURAL_ORDER) ? (Comparable) key : null; while (true) { - comparison = (comparableKey != null) - ? comparableKey.compareTo(nearest.key) - : comparator.compare(key, nearest.key); + comparison = + (comparableKey != null) + ? comparableKey.compareTo(nearest.key) + : comparator.compare(key, nearest.key); // We found the requested key. if (comparison == 0) { @@ -206,13 +207,12 @@ Node findByObject(Object key) { } /** - * Returns this map's entry that has the same key and value as {@code - * entry}, or null if this map has no such entry. + * Returns this map's entry that has the same key and value as {@code entry}, or null if this map + * has no such entry. * - *

    This method uses the comparator for key equality rather than {@code - * equals}. If this map's comparator isn't consistent with equals (such as - * {@code String.CASE_INSENSITIVE_ORDER}), then {@code remove()} and {@code - * contains()} will violate the collections API. + *

    This method uses the comparator for key equality rather than {@code equals}. If this map's + * comparator isn't consistent with equals (such as {@code String.CASE_INSENSITIVE_ORDER}), then + * {@code remove()} and {@code contains()} will violate the collections API. */ Node findByEntry(Entry entry) { Node mine = findByObject(entry.getKey()); @@ -225,10 +225,9 @@ private boolean equal(Object a, Object b) { } /** - * Applies a supplemental hash function to a given hashCode, which defends - * against poor quality hash functions. This is critical because HashMap - * uses power-of-two length hash tables, that otherwise encounter collisions - * for hashCodes that do not differ in lower or upper bits. + * Applies a supplemental hash function to a given hashCode, which defends against poor quality + * hash functions. This is critical because HashMap uses power-of-two length hash tables, that + * otherwise encounter collisions for hashCodes that do not differ in lower or upper bits. */ private static int secondaryHash(int h) { // Doug Lea's supplemental hash function @@ -237,8 +236,7 @@ private static int secondaryHash(int h) { } /** - * Removes {@code node} from this tree, rearranging the tree's structure as - * necessary. + * Removes {@code node} from this tree, rearranging the tree's structure as necessary. * * @param unlink true to also unlink this node from the iteration linked list. */ @@ -329,11 +327,10 @@ private void replaceInParent(Node node, Node replacement) { } /** - * Rebalances the tree by making any AVL rotations necessary between the - * newly-unbalanced node and the tree's root. + * Rebalances the tree by making any AVL rotations necessary between the newly-unbalanced node and + * the tree's root. * - * @param insert true if the node was unbalanced by an insert; false if it - * was by a removal. + * @param insert true if the node was unbalanced by an insert; false if it was by a removal. */ private void rebalance(Node unbalanced, boolean insert) { for (Node node = unbalanced; node != null; node = node.parent) { @@ -395,9 +392,7 @@ private void rebalance(Node unbalanced, boolean insert) { } } - /** - * Rotates the subtree so that its root's right child is the new root. - */ + /** Rotates the subtree so that its root's right child is the new root. */ private void rotateLeft(Node root) { Node left = root.left; Node pivot = root.right; @@ -417,15 +412,12 @@ private void rotateLeft(Node root) { root.parent = pivot; // fix heights - root.height = Math.max(left != null ? left.height : 0, - pivotLeft != null ? pivotLeft.height : 0) + 1; - pivot.height = Math.max(root.height, - pivotRight != null ? pivotRight.height : 0) + 1; + root.height = + Math.max(left != null ? left.height : 0, pivotLeft != null ? pivotLeft.height : 0) + 1; + pivot.height = Math.max(root.height, pivotRight != null ? pivotRight.height : 0) + 1; } - /** - * Rotates the subtree so that its root's left child is the new root. - */ + /** Rotates the subtree so that its root's left child is the new root. */ private void rotateRight(Node root) { Node pivot = root.left; Node right = root.right; @@ -445,21 +437,22 @@ private void rotateRight(Node root) { root.parent = pivot; // fixup heights - root.height = Math.max(right != null ? right.height : 0, - pivotRight != null ? pivotRight.height : 0) + 1; - pivot.height = Math.max(root.height, - pivotLeft != null ? pivotLeft.height : 0) + 1; + root.height = + Math.max(right != null ? right.height : 0, pivotRight != null ? pivotRight.height : 0) + 1; + pivot.height = Math.max(root.height, pivotLeft != null ? pivotLeft.height : 0) + 1; } private EntrySet entrySet; private KeySet keySet; - @Override public Set> entrySet() { + @Override + public Set> entrySet() { EntrySet result = entrySet; return result != null ? result : (entrySet = new EntrySet()); } - @Override public Set keySet() { + @Override + public Set keySet() { KeySet result = keySet; return result != null ? result : (keySet = new KeySet()); } @@ -509,7 +502,8 @@ public V setValue(V value) { } @SuppressWarnings("rawtypes") - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (o instanceof Entry) { Entry other = (Entry) o; return (key == null ? other.getKey() == null : key.equals(other.getKey())) @@ -518,18 +512,17 @@ public V setValue(V value) { return false; } - @Override public int hashCode() { - return (key == null ? 0 : key.hashCode()) - ^ (value == null ? 0 : value.hashCode()); + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } - @Override public String toString() { + @Override + public String toString() { return key + "=" + value; } - /** - * Returns the first node in this subtree. - */ + /** Returns the first node in this subtree. */ public Node first() { Node node = this; Node child = node.left; @@ -540,9 +533,7 @@ public Node first() { return node; } - /** - * Returns the last node in this subtree. - */ + /** Returns the last node in this subtree. */ public Node last() { Node node = this; Node child = node.right; @@ -560,14 +551,14 @@ private void doubleCapacity() { } /** - * Returns a new array containing the same nodes as {@code oldTable}, but with - * twice as many trees, each of (approximately) half the previous size. + * Returns a new array containing the same nodes as {@code oldTable}, but with twice as many + * trees, each of (approximately) half the previous size. */ static Node[] doubleCapacity(Node[] oldTable) { // TODO: don't do anything if we're already at MAX_CAPACITY int oldCapacity = oldTable.length; @SuppressWarnings("unchecked") // Arrays and generics don't get along. - Node[] newTable = new Node[oldCapacity * 2]; + Node[] newTable = new Node[oldCapacity * 2]; AvlIterator iterator = new AvlIterator<>(); AvlBuilder leftBuilder = new AvlBuilder<>(); AvlBuilder rightBuilder = new AvlBuilder<>(); @@ -611,13 +602,12 @@ static Node[] doubleCapacity(Node[] oldTable) { } /** - * Walks an AVL tree in iteration order. Once a node has been returned, its - * left, right and parent links are no longer used. For this - * reason it is safe to transform these links as you walk a tree. + * Walks an AVL tree in iteration order. Once a node has been returned, its left, right and parent + * links are no longer used. For this reason it is safe to transform these links + * as you walk a tree. * - *

    Warning: this iterator is destructive. It clears the - * parent node of all nodes in the tree. It is an error to make a partial - * iteration of a tree. + *

    Warning: this iterator is destructive. It clears the parent node of all + * nodes in the tree. It is an error to make a partial iteration of a tree. */ static class AvlIterator { /** This stack is a singly linked list, linked by the 'parent' field. */ @@ -650,26 +640,25 @@ public Node next() { } /** - * Builds AVL trees of a predetermined size by accepting nodes of increasing - * value. To use: + * Builds AVL trees of a predetermined size by accepting nodes of increasing value. To use: + * *

      *
    1. Call {@link #reset} to initialize the target size size. *
    2. Call {@link #add} size times with increasing values. *
    3. Call {@link #root} to get the root of the balanced tree. *
    * - *

    The returned tree will satisfy the AVL constraint: for every node - * N, the height of N.left and N.right is different by at - * most 1. It accomplishes this by omitting deepest-level leaf nodes when - * building trees whose size isn't a power of 2 minus 1. + *

    The returned tree will satisfy the AVL constraint: for every node N, the height of + * N.left and N.right is different by at most 1. It accomplishes this by omitting + * deepest-level leaf nodes when building trees whose size isn't a power of 2 minus 1. * - *

    Unlike rebuilding a tree from scratch, this approach requires no value - * comparisons. Using this class to create a tree of size S is - * {@code O(S)}. + *

    Unlike rebuilding a tree from scratch, this approach requires no value comparisons. Using + * this class to create a tree of size S is {@code O(S)}. */ static final class AvlBuilder { /** This stack is a singly linked list, linked by the 'parent' field. */ private Node stack; + private int leavesToSkip; private int leavesSkipped; private int size; @@ -789,11 +778,13 @@ public final void remove() { } final class EntrySet extends AbstractSet> { - @Override public int size() { + @Override + public int size() { return size; } - @Override public Iterator> iterator() { + @Override + public Iterator> iterator() { return new LinkedTreeMapIterator>() { public Entry next() { return nextNode(); @@ -801,11 +792,13 @@ public Entry next() { }; } - @Override public boolean contains(Object o) { + @Override + public boolean contains(Object o) { return o instanceof Entry && findByEntry((Entry) o) != null; } - @Override public boolean remove(Object o) { + @Override + public boolean remove(Object o) { if (!(o instanceof Entry)) { return false; } @@ -818,17 +811,20 @@ public Entry next() { return true; } - @Override public void clear() { + @Override + public void clear() { LinkedHashTreeMap.this.clear(); } } final class KeySet extends AbstractSet { - @Override public int size() { + @Override + public int size() { return size; } - @Override public Iterator iterator() { + @Override + public Iterator iterator() { return new LinkedTreeMapIterator() { public K next() { return nextNode().key; @@ -836,24 +832,26 @@ public K next() { }; } - @Override public boolean contains(Object o) { + @Override + public boolean contains(Object o) { return containsKey(o); } - @Override public boolean remove(Object key) { + @Override + public boolean remove(Object key) { return removeInternalByKey(key) != null; } - @Override public void clear() { + @Override + public void clear() { LinkedHashTreeMap.this.clear(); } } /** - * If somebody is unlucky enough to have to serialize one of these, serialize - * it as a LinkedHashMap so that they won't need Gson on the other side to - * deserialize it. Using serialization defeats our DoS defence, so most apps - * shouldn't use it. + * If somebody is unlucky enough to have to serialize one of these, serialize it as a + * LinkedHashMap so that they won't need Gson on the other side to deserialize it. Using + * serialization defeats our DoS defence, so most apps shouldn't use it. */ private Object writeReplace() throws ObjectStreamException { return new LinkedHashMap<>(this); diff --git a/moshi/src/main/java/com/squareup/moshi/MapJsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/MapJsonAdapter.java index 598b0e001..362ea8de7 100644 --- a/moshi/src/main/java/com/squareup/moshi/MapJsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/MapJsonAdapter.java @@ -25,19 +25,21 @@ /** * Converts maps with string keys to JSON objects. * - * TODO: support maps with other key types and convert to/from strings. + *

    TODO: support maps with other key types and convert to/from strings. */ final class MapJsonAdapter extends JsonAdapter> { - public static final Factory FACTORY = new Factory() { - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - if (!annotations.isEmpty()) return null; - Class rawType = Types.getRawType(type); - if (rawType != Map.class) return null; - Type[] keyAndValue = Types.mapKeyAndValueTypes(type, rawType); - return new MapJsonAdapter<>(moshi, keyAndValue[0], keyAndValue[1]).nullSafe(); - } - }; + public static final Factory FACTORY = + new Factory() { + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + if (!annotations.isEmpty()) return null; + Class rawType = Types.getRawType(type); + if (rawType != Map.class) return null; + Type[] keyAndValue = Types.mapKeyAndValueTypes(type, rawType); + return new MapJsonAdapter<>(moshi, keyAndValue[0], keyAndValue[1]).nullSafe(); + } + }; private final JsonAdapter keyAdapter; private final JsonAdapter valueAdapter; @@ -47,7 +49,8 @@ final class MapJsonAdapter extends JsonAdapter> { this.valueAdapter = moshi.adapter(valueType); } - @Override public void toJson(JsonWriter writer, Map map) throws IOException { + @Override + public void toJson(JsonWriter writer, Map map) throws IOException { writer.beginObject(); for (Map.Entry entry : map.entrySet()) { if (entry.getKey() == null) { @@ -60,7 +63,8 @@ final class MapJsonAdapter extends JsonAdapter> { writer.endObject(); } - @Override public Map fromJson(JsonReader reader) throws IOException { + @Override + public Map fromJson(JsonReader reader) throws IOException { LinkedHashTreeMap result = new LinkedHashTreeMap<>(); reader.beginObject(); while (reader.hasNext()) { @@ -69,15 +73,23 @@ final class MapJsonAdapter extends JsonAdapter> { V value = valueAdapter.fromJson(reader); V replaced = result.put(name, value); if (replaced != null) { - throw new JsonDataException("Map key '" + name + "' has multiple values at path " - + reader.getPath() + ": " + replaced + " and " + value); + throw new JsonDataException( + "Map key '" + + name + + "' has multiple values at path " + + reader.getPath() + + ": " + + replaced + + " and " + + value); } } reader.endObject(); return result; } - @Override public String toString() { + @Override + public String toString() { return "JsonAdapter(" + keyAdapter + "=" + valueAdapter + ")"; } } diff --git a/moshi/src/main/java/com/squareup/moshi/Moshi.java b/moshi/src/main/java/com/squareup/moshi/Moshi.java index f42d1d12c..96079393c 100644 --- a/moshi/src/main/java/com/squareup/moshi/Moshi.java +++ b/moshi/src/main/java/com/squareup/moshi/Moshi.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.internal.Util.canonicalize; +import static com.squareup.moshi.internal.Util.removeSubtypeWildcard; +import static com.squareup.moshi.internal.Util.typeAnnotatedWithAnnotations; + import com.squareup.moshi.internal.Util; import java.io.IOException; import java.lang.annotation.Annotation; @@ -33,10 +37,6 @@ import javax.annotation.CheckReturnValue; import javax.annotation.Nullable; -import static com.squareup.moshi.internal.Util.canonicalize; -import static com.squareup.moshi.internal.Util.removeSubtypeWildcard; -import static com.squareup.moshi.internal.Util.typeAnnotatedWithAnnotations; - /** * Coordinates binding between JSON values and Java objects. * @@ -59,19 +59,21 @@ public final class Moshi { private final Map> adapterCache = new LinkedHashMap<>(); Moshi(Builder builder) { - List factories = new ArrayList<>( - builder.factories.size() + BUILT_IN_FACTORIES.size()); + List factories = + new ArrayList<>(builder.factories.size() + BUILT_IN_FACTORIES.size()); factories.addAll(builder.factories); factories.addAll(BUILT_IN_FACTORIES); this.factories = Collections.unmodifiableList(factories); } /** Returns a JSON adapter for {@code type}, creating it if necessary. */ - @CheckReturnValue public JsonAdapter adapter(Type type) { + @CheckReturnValue + public JsonAdapter adapter(Type type) { return adapter(type, Util.NO_ANNOTATIONS); } - @CheckReturnValue public JsonAdapter adapter(Class type) { + @CheckReturnValue + public JsonAdapter adapter(Class type) { return adapter(type, Util.NO_ANNOTATIONS); } @@ -80,8 +82,8 @@ public JsonAdapter adapter(Type type, Class annotat if (annotationType == null) { throw new NullPointerException("annotationType == null"); } - return adapter(type, - Collections.singleton(Types.createJsonQualifierImplementation(annotationType))); + return adapter( + type, Collections.singleton(Types.createJsonQualifierImplementation(annotationType))); } @CheckReturnValue @@ -103,12 +105,12 @@ public JsonAdapter adapter(Type type, Set annotatio /** * @param fieldName An optional field name associated with this type. The field name is used as a - * hint for better adapter lookup error messages for nested structures. + * hint for better adapter lookup error messages for nested structures. */ @CheckReturnValue @SuppressWarnings("unchecked") // Factories are required to return only matching JsonAdapters. - public JsonAdapter adapter(Type type, Set annotations, - @Nullable String fieldName) { + public JsonAdapter adapter( + Type type, Set annotations, @Nullable String fieldName) { if (type == null) { throw new NullPointerException("type == null"); } @@ -158,8 +160,8 @@ public JsonAdapter adapter(Type type, Set annotatio @CheckReturnValue @SuppressWarnings("unchecked") // Factories are required to return only matching JsonAdapters. - public JsonAdapter nextAdapter(JsonAdapter.Factory skipPast, Type type, - Set annotations) { + public JsonAdapter nextAdapter( + JsonAdapter.Factory skipPast, Type type, Set annotations) { if (annotations == null) throw new NullPointerException("annotations == null"); type = removeSubtypeWildcard(canonicalize(type)); @@ -172,12 +174,13 @@ public JsonAdapter nextAdapter(JsonAdapter.Factory skipPast, Type type, JsonAdapter result = (JsonAdapter) factories.get(i).create(type, annotations, this); if (result != null) return result; } - throw new IllegalArgumentException("No next JsonAdapter for " - + typeAnnotatedWithAnnotations(type, annotations)); + throw new IllegalArgumentException( + "No next JsonAdapter for " + typeAnnotatedWithAnnotations(type, annotations)); } /** Returns a new builder containing all custom factories used by the current instance. */ - @CheckReturnValue public Moshi.Builder newBuilder() { + @CheckReturnValue + public Moshi.Builder newBuilder() { int fullSize = factories.size(); int tailSize = BUILT_IN_FACTORIES.size(); List customFactories = factories.subList(0, fullSize - tailSize); @@ -197,15 +200,21 @@ public Builder add(final Type type, final JsonAdapter jsonAdapter) { if (type == null) throw new IllegalArgumentException("type == null"); if (jsonAdapter == null) throw new IllegalArgumentException("jsonAdapter == null"); - return add(new JsonAdapter.Factory() { - @Override public @Nullable JsonAdapter create( - Type targetType, Set annotations, Moshi moshi) { - return annotations.isEmpty() && Util.typesMatch(type, targetType) ? jsonAdapter : null; - } - }); + return add( + new JsonAdapter.Factory() { + @Override + public @Nullable JsonAdapter create( + Type targetType, Set annotations, Moshi moshi) { + return annotations.isEmpty() && Util.typesMatch(type, targetType) + ? jsonAdapter + : null; + } + }); } - public Builder add(final Type type, final Class annotation, + public Builder add( + final Type type, + final Class annotation, final JsonAdapter jsonAdapter) { if (type == null) throw new IllegalArgumentException("type == null"); if (annotation == null) throw new IllegalArgumentException("annotation == null"); @@ -217,17 +226,19 @@ public Builder add(final Type type, final Class annota throw new IllegalArgumentException("Use JsonAdapter.Factory for annotations with elements"); } - return add(new JsonAdapter.Factory() { - @Override public @Nullable JsonAdapter create( - Type targetType, Set annotations, Moshi moshi) { - if (Util.typesMatch(type, targetType) - && annotations.size() == 1 - && Util.isAnnotationPresent(annotations, annotation)) { - return jsonAdapter; - } - return null; - } - }); + return add( + new JsonAdapter.Factory() { + @Override + public @Nullable JsonAdapter create( + Type targetType, Set annotations, Moshi moshi) { + if (Util.typesMatch(type, targetType) + && annotations.size() == 1 + && Util.isAnnotationPresent(annotations, annotation)) { + return jsonAdapter; + } + return null; + } + }); } public Builder add(JsonAdapter.Factory factory) { @@ -246,7 +257,8 @@ Builder addAll(List factories) { return this; } - @CheckReturnValue public Moshi build() { + @CheckReturnValue + public Moshi build() { return new Moshi(this); } } @@ -260,10 +272,10 @@ Builder addAll(List factories) { * with all of the lookups. * *

    Sometimes a JSON adapter factory depends on its own product; either directly or indirectly. - * To make this work, we offer a JSON adapter stub while the final adapter is being computed. - * When it is ready, we wire the stub to that finished adapter. This is necessary in - * self-referential object models, such as an {@code Employee} class that has a {@code - * List} field for an organization's management hierarchy. + * To make this work, we offer a JSON adapter stub while the final adapter is being computed. When + * it is ready, we wire the stub to that finished adapter. This is necessary in self-referential + * object models, such as an {@code Employee} class that has a {@code List} field for an + * organization's management hierarchy. * *

    This class defers putting any JSON adapters in the cache until the topmost JSON adapter has * successfully been computed. That way we don't pollute the cache with incomplete stubs, or @@ -339,13 +351,9 @@ IllegalArgumentException exceptionWithLookupStack(IllegalArgumentException e) { StringBuilder errorMessageBuilder = new StringBuilder(e.getMessage()); for (Iterator> i = stack.descendingIterator(); i.hasNext(); ) { Lookup lookup = i.next(); - errorMessageBuilder - .append("\nfor ") - .append(lookup.type); + errorMessageBuilder.append("\nfor ").append(lookup.type); if (lookup.fieldName != null) { - errorMessageBuilder - .append(' ') - .append(lookup.fieldName); + errorMessageBuilder.append(' ').append(lookup.fieldName); } } @@ -366,17 +374,20 @@ static final class Lookup extends JsonAdapter { this.cacheKey = cacheKey; } - @Override public T fromJson(JsonReader reader) throws IOException { + @Override + public T fromJson(JsonReader reader) throws IOException { if (adapter == null) throw new IllegalStateException("JsonAdapter isn't ready"); return adapter.fromJson(reader); } - @Override public void toJson(JsonWriter writer, T value) throws IOException { + @Override + public void toJson(JsonWriter writer, T value) throws IOException { if (adapter == null) throw new IllegalStateException("JsonAdapter isn't ready"); adapter.toJson(writer, value); } - @Override public String toString() { + @Override + public String toString() { return adapter != null ? adapter.toString() : super.toString(); } } diff --git a/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java b/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java index 6b83279c0..c61aae48a 100644 --- a/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java +++ b/moshi/src/main/java/com/squareup/moshi/StandardJsonAdapters.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.internal.Util.generatedAdapter; + import com.squareup.moshi.internal.Util; import java.io.IOException; import java.lang.annotation.Annotation; @@ -26,49 +28,48 @@ import java.util.Set; import javax.annotation.Nullable; -import static com.squareup.moshi.internal.Util.generatedAdapter; - final class StandardJsonAdapters { - private StandardJsonAdapters() { - } - - public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() { - @Override public JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - if (!annotations.isEmpty()) return null; - if (type == boolean.class) return BOOLEAN_JSON_ADAPTER; - if (type == byte.class) return BYTE_JSON_ADAPTER; - if (type == char.class) return CHARACTER_JSON_ADAPTER; - if (type == double.class) return DOUBLE_JSON_ADAPTER; - if (type == float.class) return FLOAT_JSON_ADAPTER; - if (type == int.class) return INTEGER_JSON_ADAPTER; - if (type == long.class) return LONG_JSON_ADAPTER; - if (type == short.class) return SHORT_JSON_ADAPTER; - if (type == Boolean.class) return BOOLEAN_JSON_ADAPTER.nullSafe(); - if (type == Byte.class) return BYTE_JSON_ADAPTER.nullSafe(); - if (type == Character.class) return CHARACTER_JSON_ADAPTER.nullSafe(); - if (type == Double.class) return DOUBLE_JSON_ADAPTER.nullSafe(); - if (type == Float.class) return FLOAT_JSON_ADAPTER.nullSafe(); - if (type == Integer.class) return INTEGER_JSON_ADAPTER.nullSafe(); - if (type == Long.class) return LONG_JSON_ADAPTER.nullSafe(); - if (type == Short.class) return SHORT_JSON_ADAPTER.nullSafe(); - if (type == String.class) return STRING_JSON_ADAPTER.nullSafe(); - if (type == Object.class) return new ObjectJsonAdapter(moshi).nullSafe(); - - Class rawType = Types.getRawType(type); - - @Nullable JsonAdapter generatedAdapter = generatedAdapter(moshi, type, rawType); - if (generatedAdapter != null) { - return generatedAdapter; - } - - if (rawType.isEnum()) { - //noinspection unchecked - return new EnumJsonAdapter<>((Class) rawType).nullSafe(); - } - return null; - } - }; + private StandardJsonAdapters() {} + + public static final JsonAdapter.Factory FACTORY = + new JsonAdapter.Factory() { + @Override + public JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + if (!annotations.isEmpty()) return null; + if (type == boolean.class) return BOOLEAN_JSON_ADAPTER; + if (type == byte.class) return BYTE_JSON_ADAPTER; + if (type == char.class) return CHARACTER_JSON_ADAPTER; + if (type == double.class) return DOUBLE_JSON_ADAPTER; + if (type == float.class) return FLOAT_JSON_ADAPTER; + if (type == int.class) return INTEGER_JSON_ADAPTER; + if (type == long.class) return LONG_JSON_ADAPTER; + if (type == short.class) return SHORT_JSON_ADAPTER; + if (type == Boolean.class) return BOOLEAN_JSON_ADAPTER.nullSafe(); + if (type == Byte.class) return BYTE_JSON_ADAPTER.nullSafe(); + if (type == Character.class) return CHARACTER_JSON_ADAPTER.nullSafe(); + if (type == Double.class) return DOUBLE_JSON_ADAPTER.nullSafe(); + if (type == Float.class) return FLOAT_JSON_ADAPTER.nullSafe(); + if (type == Integer.class) return INTEGER_JSON_ADAPTER.nullSafe(); + if (type == Long.class) return LONG_JSON_ADAPTER.nullSafe(); + if (type == Short.class) return SHORT_JSON_ADAPTER.nullSafe(); + if (type == String.class) return STRING_JSON_ADAPTER.nullSafe(); + if (type == Object.class) return new ObjectJsonAdapter(moshi).nullSafe(); + + Class rawType = Types.getRawType(type); + + @Nullable JsonAdapter generatedAdapter = generatedAdapter(moshi, type, rawType); + if (generatedAdapter != null) { + return generatedAdapter; + } + + if (rawType.isEnum()) { + //noinspection unchecked + return new EnumJsonAdapter<>((Class) rawType).nullSafe(); + } + return null; + } + }; private static final String ERROR_FORMAT = "Expected %s but was %s at path %s"; @@ -82,147 +83,183 @@ static int rangeCheckNextInt(JsonReader reader, String typeMessage, int min, int return value; } - static final JsonAdapter BOOLEAN_JSON_ADAPTER = new JsonAdapter() { - @Override public Boolean fromJson(JsonReader reader) throws IOException { - return reader.nextBoolean(); - } + static final JsonAdapter BOOLEAN_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Boolean fromJson(JsonReader reader) throws IOException { + return reader.nextBoolean(); + } - @Override public void toJson(JsonWriter writer, Boolean value) throws IOException { - writer.value(value.booleanValue()); - } + @Override + public void toJson(JsonWriter writer, Boolean value) throws IOException { + writer.value(value.booleanValue()); + } - @Override public String toString() { - return "JsonAdapter(Boolean)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(Boolean)"; + } + }; - static final JsonAdapter BYTE_JSON_ADAPTER = new JsonAdapter() { - @Override public Byte fromJson(JsonReader reader) throws IOException { - return (byte) rangeCheckNextInt(reader, "a byte", Byte.MIN_VALUE, 0xff); - } + static final JsonAdapter BYTE_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Byte fromJson(JsonReader reader) throws IOException { + return (byte) rangeCheckNextInt(reader, "a byte", Byte.MIN_VALUE, 0xff); + } - @Override public void toJson(JsonWriter writer, Byte value) throws IOException { - writer.value(value.intValue() & 0xff); - } + @Override + public void toJson(JsonWriter writer, Byte value) throws IOException { + writer.value(value.intValue() & 0xff); + } - @Override public String toString() { - return "JsonAdapter(Byte)"; - } - }; - - static final JsonAdapter CHARACTER_JSON_ADAPTER = new JsonAdapter() { - @Override public Character fromJson(JsonReader reader) throws IOException { - String value = reader.nextString(); - if (value.length() > 1) { - throw new JsonDataException( - String.format(ERROR_FORMAT, "a char", '"' + value + '"', reader.getPath())); - } - return value.charAt(0); - } + @Override + public String toString() { + return "JsonAdapter(Byte)"; + } + }; + + static final JsonAdapter CHARACTER_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Character fromJson(JsonReader reader) throws IOException { + String value = reader.nextString(); + if (value.length() > 1) { + throw new JsonDataException( + String.format(ERROR_FORMAT, "a char", '"' + value + '"', reader.getPath())); + } + return value.charAt(0); + } - @Override public void toJson(JsonWriter writer, Character value) throws IOException { - writer.value(value.toString()); - } + @Override + public void toJson(JsonWriter writer, Character value) throws IOException { + writer.value(value.toString()); + } - @Override public String toString() { - return "JsonAdapter(Character)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(Character)"; + } + }; - static final JsonAdapter DOUBLE_JSON_ADAPTER = new JsonAdapter() { - @Override public Double fromJson(JsonReader reader) throws IOException { - return reader.nextDouble(); - } + static final JsonAdapter DOUBLE_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Double fromJson(JsonReader reader) throws IOException { + return reader.nextDouble(); + } - @Override public void toJson(JsonWriter writer, Double value) throws IOException { - writer.value(value.doubleValue()); - } + @Override + public void toJson(JsonWriter writer, Double value) throws IOException { + writer.value(value.doubleValue()); + } - @Override public String toString() { - return "JsonAdapter(Double)"; - } - }; - - static final JsonAdapter FLOAT_JSON_ADAPTER = new JsonAdapter() { - @Override public Float fromJson(JsonReader reader) throws IOException { - float value = (float) reader.nextDouble(); - // Double check for infinity after float conversion; many doubles > Float.MAX - if (!reader.isLenient() && Float.isInfinite(value)) { - throw new JsonDataException("JSON forbids NaN and infinities: " + value - + " at path " + reader.getPath()); - } - return value; - } + @Override + public String toString() { + return "JsonAdapter(Double)"; + } + }; + + static final JsonAdapter FLOAT_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Float fromJson(JsonReader reader) throws IOException { + float value = (float) reader.nextDouble(); + // Double check for infinity after float conversion; many doubles > Float.MAX + if (!reader.isLenient() && Float.isInfinite(value)) { + throw new JsonDataException( + "JSON forbids NaN and infinities: " + value + " at path " + reader.getPath()); + } + return value; + } - @Override public void toJson(JsonWriter writer, Float value) throws IOException { - // Manual null pointer check for the float.class adapter. - if (value == null) { - throw new NullPointerException(); - } - // Use the Number overload so we write out float precision instead of double precision. - writer.value(value); - } + @Override + public void toJson(JsonWriter writer, Float value) throws IOException { + // Manual null pointer check for the float.class adapter. + if (value == null) { + throw new NullPointerException(); + } + // Use the Number overload so we write out float precision instead of double precision. + writer.value(value); + } - @Override public String toString() { - return "JsonAdapter(Float)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(Float)"; + } + }; - static final JsonAdapter INTEGER_JSON_ADAPTER = new JsonAdapter() { - @Override public Integer fromJson(JsonReader reader) throws IOException { - return reader.nextInt(); - } + static final JsonAdapter INTEGER_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Integer fromJson(JsonReader reader) throws IOException { + return reader.nextInt(); + } - @Override public void toJson(JsonWriter writer, Integer value) throws IOException { - writer.value(value.intValue()); - } + @Override + public void toJson(JsonWriter writer, Integer value) throws IOException { + writer.value(value.intValue()); + } - @Override public String toString() { - return "JsonAdapter(Integer)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(Integer)"; + } + }; - static final JsonAdapter LONG_JSON_ADAPTER = new JsonAdapter() { - @Override public Long fromJson(JsonReader reader) throws IOException { - return reader.nextLong(); - } + static final JsonAdapter LONG_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Long fromJson(JsonReader reader) throws IOException { + return reader.nextLong(); + } - @Override public void toJson(JsonWriter writer, Long value) throws IOException { - writer.value(value.longValue()); - } + @Override + public void toJson(JsonWriter writer, Long value) throws IOException { + writer.value(value.longValue()); + } - @Override public String toString() { - return "JsonAdapter(Long)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(Long)"; + } + }; - static final JsonAdapter SHORT_JSON_ADAPTER = new JsonAdapter() { - @Override public Short fromJson(JsonReader reader) throws IOException { - return (short) rangeCheckNextInt(reader, "a short", Short.MIN_VALUE, Short.MAX_VALUE); - } + static final JsonAdapter SHORT_JSON_ADAPTER = + new JsonAdapter() { + @Override + public Short fromJson(JsonReader reader) throws IOException { + return (short) rangeCheckNextInt(reader, "a short", Short.MIN_VALUE, Short.MAX_VALUE); + } - @Override public void toJson(JsonWriter writer, Short value) throws IOException { - writer.value(value.intValue()); - } + @Override + public void toJson(JsonWriter writer, Short value) throws IOException { + writer.value(value.intValue()); + } - @Override public String toString() { - return "JsonAdapter(Short)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(Short)"; + } + }; - static final JsonAdapter STRING_JSON_ADAPTER = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - return reader.nextString(); - } + static final JsonAdapter STRING_JSON_ADAPTER = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + return reader.nextString(); + } - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value(value); - } + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value(value); + } - @Override public String toString() { - return "JsonAdapter(String)"; - } - }; + @Override + public String toString() { + return "JsonAdapter(String)"; + } + }; static final class EnumJsonAdapter> extends JsonAdapter { private final Class enumType; @@ -247,22 +284,30 @@ static final class EnumJsonAdapter> extends JsonAdapter { } } - @Override public T fromJson(JsonReader reader) throws IOException { + @Override + public T fromJson(JsonReader reader) throws IOException { int index = reader.selectString(options); if (index != -1) return constants[index]; // We can consume the string safely, we are terminating anyway. String path = reader.getPath(); 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); } - @Override public void toJson(JsonWriter writer, T value) throws IOException { + @Override + public void toJson(JsonWriter writer, T value) throws IOException { writer.value(nameStrings[value.ordinal()]); } - @Override public String toString() { + @Override + public String toString() { return "JsonAdapter(" + enumType.getName() + ")"; } } @@ -292,7 +337,8 @@ static final class ObjectJsonAdapter extends JsonAdapter { this.booleanAdapter = moshi.adapter(Boolean.class); } - @Override public Object fromJson(JsonReader reader) throws IOException { + @Override + public Object fromJson(JsonReader reader) throws IOException { switch (reader.peek()) { case BEGIN_ARRAY: return listJsonAdapter.fromJson(reader); @@ -318,7 +364,8 @@ static final class ObjectJsonAdapter extends JsonAdapter { } } - @Override public void toJson(JsonWriter writer, Object value) throws IOException { + @Override + public void toJson(JsonWriter writer, Object value) throws IOException { Class valueClass = value.getClass(); if (valueClass == Object.class) { // Don't recurse infinitely when the runtime type is also Object.class. @@ -342,7 +389,8 @@ private Class toJsonType(Class valueClass) { return valueClass; } - @Override public String toString() { + @Override + public String toString() { return "JsonAdapter(Object)"; } } diff --git a/moshi/src/main/java/com/squareup/moshi/ToJson.java b/moshi/src/main/java/com/squareup/moshi/ToJson.java index 1d8d6e48e..38fc46e29 100644 --- a/moshi/src/main/java/com/squareup/moshi/ToJson.java +++ b/moshi/src/main/java/com/squareup/moshi/ToJson.java @@ -22,5 +22,4 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface ToJson { -} +public @interface ToJson {} diff --git a/moshi/src/main/java/com/squareup/moshi/Types.java b/moshi/src/main/java/com/squareup/moshi/Types.java index 40829e37a..cb56c89bd 100644 --- a/moshi/src/main/java/com/squareup/moshi/Types.java +++ b/moshi/src/main/java/com/squareup/moshi/Types.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.internal.Util.EMPTY_TYPE_ARRAY; +import static com.squareup.moshi.internal.Util.getGenericSupertype; +import static com.squareup.moshi.internal.Util.resolve; + import com.squareup.moshi.internal.Util.GenericArrayTypeImpl; import com.squareup.moshi.internal.Util.ParameterizedTypeImpl; import com.squareup.moshi.internal.Util.WildcardTypeImpl; @@ -39,25 +43,20 @@ import javax.annotation.CheckReturnValue; import javax.annotation.Nullable; -import static com.squareup.moshi.internal.Util.EMPTY_TYPE_ARRAY; -import static com.squareup.moshi.internal.Util.getGenericSupertype; -import static com.squareup.moshi.internal.Util.resolve; - /** Factory methods for types. */ @CheckReturnValue public final class Types { - private Types() { - } + private Types() {} /** - * Resolves the generated {@link JsonAdapter} fully qualified class name for a given - * {@link JsonClass JsonClass-annotated} {@code clazz}. This is the same lookup logic used by - * both the Moshi code generation as well as lookup for any JsonClass-annotated classes. This can - * be useful if generating your own JsonAdapters without using Moshi's first party code gen. + * Resolves the generated {@link JsonAdapter} fully qualified class name for a given {@link + * JsonClass JsonClass-annotated} {@code clazz}. This is the same lookup logic used by both the + * Moshi code generation as well as lookup for any JsonClass-annotated classes. This can be useful + * if generating your own JsonAdapters without using Moshi's first party code gen. * * @param clazz the class to calculate a generated JsonAdapter name for. * @return the resolved fully qualified class name to the expected generated JsonAdapter class. - * Note that this name will always be a top-level class name and not a nested class. + * Note that this name will always be a top-level class name and not a nested class. */ public static String generatedJsonAdapterName(Class clazz) { if (clazz.getAnnotation(JsonClass.class) == null) { @@ -67,27 +66,26 @@ public static String generatedJsonAdapterName(Class clazz) { } /** - * Resolves the generated {@link JsonAdapter} fully qualified class name for a given - * {@link JsonClass JsonClass-annotated} {@code className}. This is the same lookup logic used by - * both the Moshi code generation as well as lookup for any JsonClass-annotated classes. This can - * be useful if generating your own JsonAdapters without using Moshi's first party code gen. + * Resolves the generated {@link JsonAdapter} fully qualified class name for a given {@link + * JsonClass JsonClass-annotated} {@code className}. This is the same lookup logic used by both + * the Moshi code generation as well as lookup for any JsonClass-annotated classes. This can be + * useful if generating your own JsonAdapters without using Moshi's first party code gen. * * @param className the fully qualified class to calculate a generated JsonAdapter name for. * @return the resolved fully qualified class name to the expected generated JsonAdapter class. - * Note that this name will always be a top-level class name and not a nested class. + * Note that this name will always be a top-level class name and not a nested class. */ public static String generatedJsonAdapterName(String className) { return className.replace("$", "_") + "JsonAdapter"; } /** - * Checks if {@code annotations} contains {@code jsonQualifier}. - * Returns the subset of {@code annotations} without {@code jsonQualifier}, or null if {@code - * annotations} does not contain {@code jsonQualifier}. + * Checks if {@code annotations} contains {@code jsonQualifier}. Returns the subset of {@code + * annotations} without {@code jsonQualifier}, or null if {@code annotations} does not contain + * {@code jsonQualifier}. */ public static @Nullable Set nextAnnotations( - Set annotations, - Class jsonQualifier) { + Set annotations, Class jsonQualifier) { if (!jsonQualifier.isAnnotationPresent(JsonQualifier.class)) { throw new IllegalArgumentException(jsonQualifier + " is not a JsonQualifier."); } @@ -135,15 +133,15 @@ public static GenericArrayType arrayOf(Type componentType) { /** * Returns a type that represents an unknown type that extends {@code bound}. For example, if * {@code bound} is {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If - * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code - * ? extends Object}. + * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code ? + * extends Object}. */ public static WildcardType subtypeOf(Type bound) { Type[] upperBounds; if (bound instanceof WildcardType) { upperBounds = ((WildcardType) bound).getUpperBounds(); } else { - upperBounds = new Type[] { bound }; + upperBounds = new Type[] {bound}; } return new WildcardTypeImpl(upperBounds, EMPTY_TYPE_ARRAY); } @@ -157,9 +155,9 @@ public static WildcardType supertypeOf(Type bound) { if (bound instanceof WildcardType) { lowerBounds = ((WildcardType) bound).getLowerBounds(); } else { - lowerBounds = new Type[] { bound }; + lowerBounds = new Type[] {bound}; } - return new WildcardTypeImpl(new Type[] { Object.class }, lowerBounds); + return new WildcardTypeImpl(new Type[] {Object.class}, lowerBounds); } public static Class getRawType(Type type) { @@ -189,13 +187,18 @@ public static Class getRawType(Type type) { } else { String className = type == null ? "null" : type.getClass().getName(); - throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " - + "GenericArrayType, but <" + type + "> is of type " + className); + throw new IllegalArgumentException( + "Expected a Class, ParameterizedType, or " + + "GenericArrayType, but <" + + type + + "> is of type " + + className); } } /** * Returns the element type of this collection type. + * * @throws IllegalArgumentException if this type is not a collection. */ public static Type collectionElementType(Type context, Class contextRawType) { @@ -217,8 +220,8 @@ public static boolean equals(@Nullable Type a, @Nullable Type b) { } else if (a instanceof Class) { if (b instanceof GenericArrayType) { - return equals(((Class) a).getComponentType(), - ((GenericArrayType) b).getGenericComponentType()); + return equals( + ((Class) a).getComponentType(), ((GenericArrayType) b).getGenericComponentType()); } return a.equals(b); // Class already specifies equals(). @@ -226,20 +229,22 @@ public static boolean equals(@Nullable Type a, @Nullable Type b) { if (!(b instanceof ParameterizedType)) return false; ParameterizedType pa = (ParameterizedType) a; ParameterizedType pb = (ParameterizedType) b; - Type[] aTypeArguments = pa instanceof ParameterizedTypeImpl - ? ((ParameterizedTypeImpl) pa).typeArguments - : pa.getActualTypeArguments(); - Type[] bTypeArguments = pb instanceof ParameterizedTypeImpl - ? ((ParameterizedTypeImpl) pb).typeArguments - : pb.getActualTypeArguments(); + Type[] aTypeArguments = + pa instanceof ParameterizedTypeImpl + ? ((ParameterizedTypeImpl) pa).typeArguments + : pa.getActualTypeArguments(); + Type[] bTypeArguments = + pb instanceof ParameterizedTypeImpl + ? ((ParameterizedTypeImpl) pb).typeArguments + : pb.getActualTypeArguments(); return equals(pa.getOwnerType(), pb.getOwnerType()) && pa.getRawType().equals(pb.getRawType()) && Arrays.equals(aTypeArguments, bTypeArguments); } else if (a instanceof GenericArrayType) { if (b instanceof Class) { - return equals(((Class) b).getComponentType(), - ((GenericArrayType) a).getGenericComponentType()); + return equals( + ((Class) b).getComponentType(), ((GenericArrayType) a).getGenericComponentType()); } if (!(b instanceof GenericArrayType)) return false; GenericArrayType ga = (GenericArrayType) a; @@ -270,10 +275,10 @@ public static boolean equals(@Nullable Type a, @Nullable Type b) { * @param clazz the target class to read the {@code fieldName} field annotations from. * @param fieldName the target field name on {@code clazz}. * @return a set of {@link JsonQualifier}-annotated {@link Annotation} instances retrieved from - * the targeted field. Can be empty if none are found. + * the targeted field. Can be empty if none are found. */ - public static Set getFieldJsonQualifierAnnotations(Class clazz, - String fieldName) { + public static Set getFieldJsonQualifierAnnotations( + Class clazz, String fieldName) { try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); @@ -286,11 +291,8 @@ public static Set getFieldJsonQualifierAnnotations(Class T createJsonQualifierImplementation(final Class if (annotationType.getDeclaredMethods().length != 0) { throw new IllegalArgumentException(annotationType + " must not declare methods."); } - return (T) Proxy.newProxyInstance(annotationType.getClassLoader(), - new Class[] { annotationType }, new InvocationHandler() { - @Override public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { - String methodName = method.getName(); - switch (methodName) { - case "annotationType": - return annotationType; - case "equals": - Object o = args[0]; - return annotationType.isInstance(o); - case "hashCode": - return 0; - case "toString": - return "@" + annotationType.getName() + "()"; - default: - return method.invoke(proxy, args); - } - } - }); + return (T) + Proxy.newProxyInstance( + annotationType.getClassLoader(), + new Class[] {annotationType}, + new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + switch (methodName) { + case "annotationType": + return annotationType; + case "equals": + Object o = args[0]; + return annotationType.isInstance(o); + case "hashCode": + return 0; + case "toString": + return "@" + annotationType.getName() + "()"; + default: + return method.invoke(proxy, args); + } + } + }); } /** @@ -334,14 +339,14 @@ static T createJsonQualifierImplementation(final Class static Type[] mapKeyAndValueTypes(Type context, Class contextRawType) { // Work around a problem with the declaration of java.util.Properties. That class should extend // Hashtable, but it's declared to extend Hashtable. - if (context == Properties.class) return new Type[] { String.class, String.class }; + if (context == Properties.class) return new Type[] {String.class, String.class}; Type mapType = getSupertype(context, contextRawType, Map.class); if (mapType instanceof ParameterizedType) { ParameterizedType mapParameterizedType = (ParameterizedType) mapType; return mapParameterizedType.getActualTypeArguments(); } - return new Type[] { Object.class, Object.class }; + return new Type[] {Object.class, Object.class}; } /** @@ -353,8 +358,8 @@ static Type[] mapKeyAndValueTypes(Type context, Class contextRawType) { */ static Type getSupertype(Type context, Class contextRawType, Class supertype) { if (!supertype.isAssignableFrom(contextRawType)) throw new IllegalArgumentException(); - return resolve(context, contextRawType, - getGenericSupertype(context, contextRawType, supertype)); + return resolve( + context, contextRawType, getGenericSupertype(context, contextRawType, supertype)); } static Type getGenericSuperclass(Type type) { @@ -363,8 +368,8 @@ static Type getGenericSuperclass(Type type) { } /** - * Returns the element type of {@code type} if it is an array type, or null if it is not an - * array type. + * Returns the element type of {@code type} if it is an array type, or null if it is not an array + * type. */ static Type arrayComponentType(Type type) { if (type instanceof GenericArrayType) { diff --git a/moshi/src/main/java/com/squareup/moshi/internal/NullSafeJsonAdapter.java b/moshi/src/main/java/com/squareup/moshi/internal/NullSafeJsonAdapter.java index 569571afd..48e7a53cf 100644 --- a/moshi/src/main/java/com/squareup/moshi/internal/NullSafeJsonAdapter.java +++ b/moshi/src/main/java/com/squareup/moshi/internal/NullSafeJsonAdapter.java @@ -33,7 +33,8 @@ public JsonAdapter delegate() { return delegate; } - @Override public @Nullable T fromJson(JsonReader reader) throws IOException { + @Override + public @Nullable T fromJson(JsonReader reader) throws IOException { if (reader.peek() == JsonReader.Token.NULL) { return reader.nextNull(); } else { @@ -41,7 +42,8 @@ public JsonAdapter delegate() { } } - @Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException { + @Override + public void toJson(JsonWriter writer, @Nullable T value) throws IOException { if (value == null) { writer.nullValue(); } else { @@ -49,7 +51,8 @@ public JsonAdapter delegate() { } } - @Override public String toString() { + @Override + public String toString() { return delegate + ".nullSafe()"; } } diff --git a/moshi/src/main/java/com/squareup/moshi/internal/Util.java b/moshi/src/main/java/com/squareup/moshi/internal/Util.java index 05fe663cd..04ad427a5 100644 --- a/moshi/src/main/java/com/squareup/moshi/internal/Util.java +++ b/moshi/src/main/java/com/squareup/moshi/internal/Util.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi.internal; +import static com.squareup.moshi.Types.arrayOf; +import static com.squareup.moshi.Types.subtypeOf; +import static com.squareup.moshi.Types.supertypeOf; + import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.JsonClass; import com.squareup.moshi.JsonDataException; @@ -40,10 +44,6 @@ import java.util.Set; import javax.annotation.Nullable; -import static com.squareup.moshi.Types.arrayOf; -import static com.squareup.moshi.Types.subtypeOf; -import static com.squareup.moshi.Types.supertypeOf; - public final class Util { public static final Set NO_ANNOTATIONS = Collections.emptySet(); public static final Type[] EMPTY_TYPE_ARRAY = new Type[] {}; @@ -74,8 +74,7 @@ private static String getKotlinMetadataClassName() { return "kotlin.Metadata"; } - private Util() { - } + private Util() {} public static boolean typesMatch(Type pattern, Type candidate) { // TODO: permit raw types (like Set.class) to match non-raw candidates (like Set). @@ -151,8 +150,8 @@ public static Type canonicalize(Type type) { } else if (type instanceof ParameterizedType) { if (type instanceof ParameterizedTypeImpl) return type; ParameterizedType p = (ParameterizedType) type; - return new ParameterizedTypeImpl(p.getOwnerType(), - p.getRawType(), p.getActualTypeArguments()); + return new ParameterizedTypeImpl( + p.getOwnerType(), p.getRawType(), p.getActualTypeArguments()); } else if (type instanceof GenericArrayType) { if (type instanceof GenericArrayTypeImpl) return type; @@ -169,9 +168,7 @@ public static Type canonicalize(Type type) { } } - /** - * If type is a "? extends X" wildcard, returns X; otherwise returns type unchanged. - */ + /** If type is a "? extends X" wildcard, returns X; otherwise returns type unchanged. */ public static Type removeSubtypeWildcard(Type type) { if (!(type instanceof WildcardType)) return type; @@ -188,7 +185,10 @@ public static Type resolve(Type context, Class contextRawType, Type toResolve return resolve(context, contextRawType, toResolve, new LinkedHashSet()); } - private static Type resolve(Type context, Class contextRawType, Type toResolve, + private static Type resolve( + Type context, + Class contextRawType, + Type toResolve, Collection visitedTypeVariables) { // This implementation is made a little more complicated in an attempt to avoid object-creation. while (true) { @@ -206,20 +206,16 @@ private static Type resolve(Type context, Class contextRawType, Type toResolv } else if (toResolve instanceof Class && ((Class) toResolve).isArray()) { Class original = (Class) toResolve; Type componentType = original.getComponentType(); - Type newComponentType = resolve(context, contextRawType, componentType, - visitedTypeVariables); - return componentType == newComponentType - ? original - : arrayOf(newComponentType); + Type newComponentType = + resolve(context, contextRawType, componentType, visitedTypeVariables); + return componentType == newComponentType ? original : arrayOf(newComponentType); } else if (toResolve instanceof GenericArrayType) { GenericArrayType original = (GenericArrayType) toResolve; Type componentType = original.getGenericComponentType(); - Type newComponentType = resolve(context, contextRawType, componentType, - visitedTypeVariables); - return componentType == newComponentType - ? original - : arrayOf(newComponentType); + Type newComponentType = + resolve(context, contextRawType, componentType, visitedTypeVariables); + return componentType == newComponentType ? original : arrayOf(newComponentType); } else if (toResolve instanceof ParameterizedType) { ParameterizedType original = (ParameterizedType) toResolve; @@ -229,8 +225,8 @@ private static Type resolve(Type context, Class contextRawType, Type toResolv Type[] args = original.getActualTypeArguments(); for (int t = 0, length = args.length; t < length; t++) { - Type resolvedTypeArgument = resolve(context, contextRawType, args[t], - visitedTypeVariables); + Type resolvedTypeArgument = + resolve(context, contextRawType, args[t], visitedTypeVariables); if (resolvedTypeArgument != args[t]) { if (!changed) { args = args.clone(); @@ -250,14 +246,14 @@ private static Type resolve(Type context, Class contextRawType, Type toResolv Type[] originalUpperBound = original.getUpperBounds(); if (originalLowerBound.length == 1) { - Type lowerBound = resolve(context, contextRawType, originalLowerBound[0], - visitedTypeVariables); + Type lowerBound = + resolve(context, contextRawType, originalLowerBound[0], visitedTypeVariables); if (lowerBound != originalLowerBound[0]) { return supertypeOf(lowerBound); } } else if (originalUpperBound.length == 1) { - Type upperBound = resolve(context, contextRawType, originalUpperBound[0], - visitedTypeVariables); + Type upperBound = + resolve(context, contextRawType, originalUpperBound[0], visitedTypeVariables); if (upperBound != originalUpperBound[0]) { return subtypeOf(upperBound); } @@ -369,8 +365,7 @@ public ParameterizedTypeImpl(@Nullable Type ownerType, Type rawType, Type... typ "unexpected owner type for " + rawType + ": " + ownerType); } } else if (enclosingClass != null) { - throw new IllegalArgumentException( - "unexpected owner type for " + rawType + ": null"); + throw new IllegalArgumentException("unexpected owner type for " + rawType + ": null"); } } @@ -384,30 +379,33 @@ public ParameterizedTypeImpl(@Nullable Type ownerType, Type rawType, Type... typ } } - @Override public Type[] getActualTypeArguments() { + @Override + public Type[] getActualTypeArguments() { return typeArguments.clone(); } - @Override public Type getRawType() { + @Override + public Type getRawType() { return rawType; } - @Override public @Nullable Type getOwnerType() { + @Override + public @Nullable Type getOwnerType() { return ownerType; } - @Override public boolean equals(Object other) { - return other instanceof ParameterizedType - && Types.equals(this, (ParameterizedType) other); + @Override + public boolean equals(Object other) { + return other instanceof ParameterizedType && Types.equals(this, (ParameterizedType) other); } - @Override public int hashCode() { - return Arrays.hashCode(typeArguments) - ^ rawType.hashCode() - ^ hashCodeOrZero(ownerType); + @Override + public int hashCode() { + return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType); } - @Override public String toString() { + @Override + public String toString() { StringBuilder result = new StringBuilder(30 * (typeArguments.length + 1)); result.append(typeToString(rawType)); @@ -430,20 +428,23 @@ public GenericArrayTypeImpl(Type componentType) { this.componentType = canonicalize(componentType); } - @Override public Type getGenericComponentType() { + @Override + public Type getGenericComponentType() { return componentType; } - @Override public boolean equals(Object o) { - return o instanceof GenericArrayType - && Types.equals(this, (GenericArrayType) o); + @Override + public boolean equals(Object o) { + return o instanceof GenericArrayType && Types.equals(this, (GenericArrayType) o); } - @Override public int hashCode() { + @Override + public int hashCode() { return componentType.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return typeToString(componentType) + "[]"; } } @@ -476,26 +477,29 @@ public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { } } - @Override public Type[] getUpperBounds() { - return new Type[] { upperBound }; + @Override + public Type[] getUpperBounds() { + return new Type[] {upperBound}; } - @Override public Type[] getLowerBounds() { - return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY; + @Override + public Type[] getLowerBounds() { + return lowerBound != null ? new Type[] {lowerBound} : EMPTY_TYPE_ARRAY; } - @Override public boolean equals(Object other) { - return other instanceof WildcardType - && Types.equals(this, (WildcardType) other); + @Override + public boolean equals(Object other) { + return other instanceof WildcardType && Types.equals(this, (WildcardType) other); } - @Override public int hashCode() { + @Override + public int hashCode() { // This equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds()). - return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) - ^ (31 + upperBound.hashCode()); + return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode()); } - @Override public String toString() { + @Override + public String toString() { if (lowerBound != null) { return "? super " + typeToString(lowerBound); } else if (upperBound == Object.class) { @@ -506,8 +510,8 @@ public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { } } - public static String typeAnnotatedWithAnnotations(Type type, - Set annotations) { + public static String typeAnnotatedWithAnnotations( + Type type, Set annotations) { return type + (annotations.isEmpty() ? " (with no annotations)" : " annotated " + annotations); } @@ -515,8 +519,8 @@ public static String typeAnnotatedWithAnnotations(Type type, * Loads the generated JsonAdapter for classes annotated {@link JsonClass}. This works because it * uses the same naming conventions as {@code JsonClassCodeGenProcessor}. */ - public static @Nullable JsonAdapter generatedAdapter(Moshi moshi, Type type, - Class rawType) { + public static @Nullable JsonAdapter generatedAdapter( + Moshi moshi, Type type, Class rawType) { JsonClass jsonClass = rawType.getAnnotation(JsonClass.class); if (jsonClass == null || !jsonClass.generateAdapter()) { return null; @@ -525,8 +529,9 @@ public static String typeAnnotatedWithAnnotations(Type type, Class> adapterClass = null; try { //noinspection unchecked - We generate types to match. - adapterClass = (Class>) - Class.forName(adapterClassName, true, rawType.getClassLoader()); + adapterClass = + (Class>) + Class.forName(adapterClassName, true, rawType.getClassLoader()); Constructor> constructor; Object[] args; if (type instanceof ParameterizedType) { @@ -534,16 +539,16 @@ public static String typeAnnotatedWithAnnotations(Type type, try { // Common case first constructor = adapterClass.getDeclaredConstructor(Moshi.class, Type[].class); - args = new Object[] { moshi, typeArgs }; + args = new Object[] {moshi, typeArgs}; } catch (NoSuchMethodException e) { constructor = adapterClass.getDeclaredConstructor(Type[].class); - args = new Object[] { typeArgs }; + args = new Object[] {typeArgs}; } } else { try { // Common case first constructor = adapterClass.getDeclaredConstructor(Moshi.class); - args = new Object[] { moshi }; + args = new Object[] {moshi}; } catch (NoSuchMethodException e) { constructor = adapterClass.getDeclaredConstructor(); args = new Object[0]; @@ -552,25 +557,25 @@ public static String typeAnnotatedWithAnnotations(Type type, constructor.setAccessible(true); return constructor.newInstance(args).nullSafe(); } catch (ClassNotFoundException e) { - throw new RuntimeException( - "Failed to find the generated JsonAdapter class for " + type, e); + throw new RuntimeException("Failed to find the generated JsonAdapter class for " + type, e); } catch (NoSuchMethodException e) { if (!(type instanceof ParameterizedType) && adapterClass.getTypeParameters().length != 0) { throw new RuntimeException( - "Failed to find the generated JsonAdapter constructor for '" + type - + "'. Suspiciously, the type was not parameterized but the target class '" - + adapterClass.getCanonicalName() + "' is generic. Consider using " - + "Types#newParameterizedType() to define these missing type variables.", e); + "Failed to find the generated JsonAdapter constructor for '" + + type + + "'. Suspiciously, the type was not parameterized but the target class '" + + adapterClass.getCanonicalName() + + "' is generic. Consider using " + + "Types#newParameterizedType() to define these missing type variables.", + e); } else { throw new RuntimeException( "Failed to find the generated JsonAdapter constructor for " + type, e); } } catch (IllegalAccessException e) { - throw new RuntimeException( - "Failed to access the generated JsonAdapter for " + type, e); + throw new RuntimeException("Failed to access the generated JsonAdapter for " + type, e); } catch (InstantiationException e) { - throw new RuntimeException( - "Failed to instantiate the generated JsonAdapter for " + type, e); + throw new RuntimeException("Failed to instantiate the generated JsonAdapter for " + type, e); } catch (InvocationTargetException e) { throw rethrowCause(e); } @@ -589,8 +594,9 @@ public static boolean isKotlin(Class targetClass) { */ public static Constructor lookupDefaultsConstructor(Class targetClass) { if (DEFAULT_CONSTRUCTOR_MARKER == null) { - throw new IllegalStateException("DefaultConstructorMarker not on classpath. Make sure the " - + "Kotlin stdlib is on the classpath."); + throw new IllegalStateException( + "DefaultConstructorMarker not on classpath. Make sure the " + + "Kotlin stdlib is on the classpath."); } Constructor defaultConstructor = findConstructor(targetClass); defaultConstructor.setAccessible(true); @@ -611,33 +617,29 @@ private static Constructor findConstructor(Class targetClass) { } public static JsonDataException missingProperty( - String propertyName, - String jsonName, - JsonReader reader - ) { + String propertyName, String jsonName, JsonReader reader) { String path = reader.getPath(); String message; if (jsonName.equals(propertyName)) { message = String.format("Required value '%s' missing at %s", propertyName, path); } else { - message = String.format("Required value '%s' (JSON name '%s') missing at %s", - propertyName, jsonName, path); + message = + String.format( + "Required value '%s' (JSON name '%s') missing at %s", propertyName, jsonName, path); } return new JsonDataException(message); } public static JsonDataException unexpectedNull( - String propertyName, - String jsonName, - JsonReader reader - ) { + String propertyName, String jsonName, JsonReader reader) { String path = reader.getPath(); String message; if (jsonName.equals(propertyName)) { message = String.format("Non-null value '%s' was null at %s", propertyName, path); } else { - message = String.format("Non-null value '%s' (JSON name '%s') was null at %s", - propertyName, jsonName, path); + message = + String.format( + "Non-null value '%s' (JSON name '%s') was null at %s", propertyName, jsonName, path); } return new JsonDataException(message); } diff --git a/moshi/src/test/java/android/util/Pair.java b/moshi/src/test/java/android/util/Pair.java index ad0902d18..2e0ae8750 100644 --- a/moshi/src/test/java/android/util/Pair.java +++ b/moshi/src/test/java/android/util/Pair.java @@ -1,4 +1,3 @@ package android.util; -public final class Pair { -} +public final class Pair {} diff --git a/moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java b/moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java index afd246909..13505eb01 100644 --- a/moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java +++ b/moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import com.squareup.moshi.MoshiTest.Uppercase; import com.squareup.moshi.MoshiTest.UppercaseAdapterFactory; import java.io.IOException; @@ -32,49 +36,47 @@ import okio.ByteString; import org.junit.Test; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class AdapterMethodsTest { - @Test public void toAndFromJsonViaListOfIntegers() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointAsListOfIntegersJsonAdapter()) - .build(); + @Test + public void toAndFromJsonViaListOfIntegers() throws Exception { + Moshi moshi = new Moshi.Builder().add(new PointAsListOfIntegersJsonAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class); assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("[5,8]"); assertThat(pointAdapter.fromJson("[5,8]")).isEqualTo(new Point(5, 8)); } static class PointAsListOfIntegersJsonAdapter { - @ToJson List pointToJson(Point point) { + @ToJson + List pointToJson(Point point) { return Arrays.asList(point.x, point.y); } - @FromJson Point pointFromJson(List o) throws Exception { + @FromJson + Point pointFromJson(List o) throws Exception { if (o.size() != 2) throw new Exception("Expected 2 elements but was " + o); return new Point(o.get(0), o.get(1)); } } - @Test public void toAndFromJsonWithWriterAndReader() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointWriterAndReaderJsonAdapter()) - .build(); + @Test + public void toAndFromJsonWithWriterAndReader() throws Exception { + Moshi moshi = new Moshi.Builder().add(new PointWriterAndReaderJsonAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class); assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("[5,8]"); assertThat(pointAdapter.fromJson("[5,8]")).isEqualTo(new Point(5, 8)); } static class PointWriterAndReaderJsonAdapter { - @ToJson void pointToJson(JsonWriter writer, Point point) throws IOException { + @ToJson + void pointToJson(JsonWriter writer, Point point) throws IOException { writer.beginArray(); writer.value(point.x); writer.value(point.y); writer.endArray(); } - @FromJson Point pointFromJson(JsonReader reader) throws Exception { + @FromJson + Point pointFromJson(JsonReader reader) throws Exception { reader.beginArray(); int x = reader.nextInt(); int y = reader.nextInt(); @@ -84,15 +86,16 @@ static class PointWriterAndReaderJsonAdapter { } private static final class PointJsonAdapterWithDelegate { - @FromJson Point fromJson(JsonReader reader, JsonAdapter delegate) throws IOException { + @FromJson + Point fromJson(JsonReader reader, JsonAdapter delegate) throws IOException { reader.beginArray(); Point value = delegate.fromJson(reader); reader.endArray(); return value; } - @ToJson void toJson(JsonWriter writer, Point value, JsonAdapter delegate) - throws IOException { + @ToJson + void toJson(JsonWriter writer, Point value, JsonAdapter delegate) throws IOException { writer.beginArray(); delegate.toJson(writer, value); writer.endArray(); @@ -100,16 +103,17 @@ private static final class PointJsonAdapterWithDelegate { } private static final class PointJsonAdapterWithDelegateWithQualifier { - @FromJson @WithParens Point fromJson(JsonReader reader, @WithParens JsonAdapter delegate) - throws IOException { + @FromJson + @WithParens + Point fromJson(JsonReader reader, @WithParens JsonAdapter delegate) throws IOException { reader.beginArray(); Point value = delegate.fromJson(reader); reader.endArray(); return value; } - @ToJson void toJson(JsonWriter writer, @WithParens Point value, - @WithParens JsonAdapter delegate) + @ToJson + void toJson(JsonWriter writer, @WithParens Point value, @WithParens JsonAdapter delegate) throws IOException { writer.beginArray(); delegate.toJson(writer, value); @@ -117,103 +121,122 @@ private static final class PointJsonAdapterWithDelegateWithQualifier { } } - @Test public void toAndFromWithDelegate() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointJsonAdapterWithDelegate()) - .build(); + @Test + public void toAndFromWithDelegate() throws Exception { + Moshi moshi = new Moshi.Builder().add(new PointJsonAdapterWithDelegate()).build(); JsonAdapter adapter = moshi.adapter(Point.class); Point point = new Point(5, 8); assertThat(adapter.toJson(point)).isEqualTo("[{\"x\":5,\"y\":8}]"); assertThat(adapter.fromJson("[{\"x\":5,\"y\":8}]")).isEqualTo(point); } - @Test public void toAndFromWithDelegateWithQualifier() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointJsonAdapterWithDelegateWithQualifier()) - .add(new PointWithParensJsonAdapter()) - .build(); + @Test + public void toAndFromWithDelegateWithQualifier() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new PointJsonAdapterWithDelegateWithQualifier()) + .add(new PointWithParensJsonAdapter()) + .build(); JsonAdapter adapter = moshi.adapter(Point.class, WithParens.class); Point point = new Point(5, 8); assertThat(adapter.toJson(point)).isEqualTo("[\"(5 8)\"]"); assertThat(adapter.fromJson("[\"(5 8)\"]")).isEqualTo(point); } - @Test public void toAndFromWithIntermediate() throws Exception { - Moshi moshi = new Moshi.Builder().add(new Object() { - @FromJson String fromJson(String string) { - return string.substring(1, string.length() - 1); - } - - @ToJson String toJson(String value) { - return "|" + value + "|"; - } - }).build(); + @Test + public void toAndFromWithIntermediate() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add( + new Object() { + @FromJson + String fromJson(String string) { + return string.substring(1, string.length() - 1); + } + + @ToJson + String toJson(String value) { + return "|" + value + "|"; + } + }) + .build(); JsonAdapter adapter = moshi.adapter(String.class); assertThat(adapter.toJson("pizza")).isEqualTo("\"|pizza|\""); assertThat(adapter.fromJson("\"|pizza|\"")).isEqualTo("pizza"); } - @Test public void toAndFromWithIntermediateWithQualifier() throws Exception { - Moshi moshi = new Moshi.Builder().add(new Object() { - @FromJson @Uppercase String fromJson(@Uppercase String string) { - return string.substring(1, string.length() - 1); - } - - @ToJson @Uppercase String toJson(@Uppercase String value) { - return "|" + value + "|"; - } - }).add(new UppercaseAdapterFactory()).build(); + @Test + public void toAndFromWithIntermediateWithQualifier() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add( + new Object() { + @FromJson + @Uppercase + String fromJson(@Uppercase String string) { + return string.substring(1, string.length() - 1); + } + + @ToJson + @Uppercase + String toJson(@Uppercase String value) { + return "|" + value + "|"; + } + }) + .add(new UppercaseAdapterFactory()) + .build(); JsonAdapter adapter = moshi.adapter(String.class, Uppercase.class); assertThat(adapter.toJson("pizza")).isEqualTo("\"|PIZZA|\""); assertThat(adapter.fromJson("\"|pizza|\"")).isEqualTo("PIZZA"); } - @Test public void toJsonOnly() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointAsListOfIntegersToAdapter()) - .build(); + @Test + public void toJsonOnly() throws Exception { + Moshi moshi = new Moshi.Builder().add(new PointAsListOfIntegersToAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class); assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("[5,8]"); assertThat(pointAdapter.fromJson("{\"x\":5,\"y\":8}")).isEqualTo(new Point(5, 8)); } static class PointAsListOfIntegersToAdapter { - @ToJson List pointToJson(Point point) { + @ToJson + List pointToJson(Point point) { return Arrays.asList(point.x, point.y); } } - @Test public void fromJsonOnly() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointAsListOfIntegersFromAdapter()) - .build(); + @Test + public void fromJsonOnly() throws Exception { + Moshi moshi = new Moshi.Builder().add(new PointAsListOfIntegersFromAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class); assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("{\"x\":5,\"y\":8}"); assertThat(pointAdapter.fromJson("[5,8]")).isEqualTo(new Point(5, 8)); } static class PointAsListOfIntegersFromAdapter { - @FromJson Point pointFromJson(List o) throws Exception { + @FromJson + Point pointFromJson(List o) throws Exception { if (o.size() != 2) throw new Exception("Expected 2 elements but was " + o); return new Point(o.get(0), o.get(1)); } } - @Test public void multipleLayersOfAdapters() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new MultipleLayersJsonAdapter()) - .build(); + @Test + public void multipleLayersOfAdapters() throws Exception { + Moshi moshi = new Moshi.Builder().add(new MultipleLayersJsonAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class).lenient(); assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("\"5 8\""); assertThat(pointAdapter.fromJson("\"5 8\"")).isEqualTo(new Point(5, 8)); } static class MultipleLayersJsonAdapter { - @ToJson List pointToJson(Point point) { + @ToJson + List pointToJson(Point point) { return Arrays.asList(point.x, point.y); } - @ToJson String integerListToJson(List list) { + @ToJson + String integerListToJson(List list) { StringBuilder result = new StringBuilder(); for (Integer i : list) { if (result.length() != 0) result.append(" "); @@ -222,12 +245,14 @@ static class MultipleLayersJsonAdapter { return result.toString(); } - @FromJson Point pointFromJson(List o) throws Exception { + @FromJson + Point pointFromJson(List o) throws Exception { if (o.size() != 2) throw new Exception("Expected 2 elements but was " + o); return new Point(o.get(0), o.get(1)); } - @FromJson List listOfIntegersFromJson(String list) throws Exception { + @FromJson + List listOfIntegersFromJson(String list) throws Exception { List result = new ArrayList<>(); for (String part : list.split(" ")) { result.add(Integer.parseInt(part)); @@ -236,147 +261,161 @@ static class MultipleLayersJsonAdapter { } } - @Test public void conflictingToAdapters() throws Exception { + @Test + public void conflictingToAdapters() throws Exception { Moshi.Builder builder = new Moshi.Builder(); try { builder.add(new ConflictingsToJsonAdapter()); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).contains( - "Conflicting @ToJson methods:", "pointToJson1", "pointToJson2"); + assertThat(expected.getMessage()) + .contains("Conflicting @ToJson methods:", "pointToJson1", "pointToJson2"); } } static class ConflictingsToJsonAdapter { - @ToJson List pointToJson1(Point point) { + @ToJson + List pointToJson1(Point point) { throw new AssertionError(); } - @ToJson String pointToJson2(Point point) { + @ToJson + String pointToJson2(Point point) { throw new AssertionError(); } } - @Test public void conflictingFromAdapters() throws Exception { + @Test + public void conflictingFromAdapters() throws Exception { Moshi.Builder builder = new Moshi.Builder(); try { builder.add(new ConflictingsFromJsonAdapter()); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).contains( - "Conflicting @FromJson methods:", "pointFromJson1", "pointFromJson2"); + assertThat(expected.getMessage()) + .contains("Conflicting @FromJson methods:", "pointFromJson1", "pointFromJson2"); } } static class ConflictingsFromJsonAdapter { - @FromJson Point pointFromJson1(List point) { + @FromJson + Point pointFromJson1(List point) { throw new AssertionError(); } - @FromJson Point pointFromJson2(String point) { + @FromJson + Point pointFromJson2(String point) { throw new AssertionError(); } } - @Test public void emptyAdapters() throws Exception { + @Test + public void emptyAdapters() throws Exception { Moshi.Builder builder = new Moshi.Builder(); try { builder.add(new EmptyJsonAdapter()).build(); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage( - "Expected at least one @ToJson or @FromJson method on " - + "com.squareup.moshi.AdapterMethodsTest$EmptyJsonAdapter"); + assertThat(expected) + .hasMessage( + "Expected at least one @ToJson or @FromJson method on " + + "com.squareup.moshi.AdapterMethodsTest$EmptyJsonAdapter"); } } - static class EmptyJsonAdapter { - } + static class EmptyJsonAdapter {} - @Test public void unexpectedSignatureToAdapters() throws Exception { + @Test + public void unexpectedSignatureToAdapters() throws Exception { Moshi.Builder builder = new Moshi.Builder(); try { builder.add(new UnexpectedSignatureToJsonAdapter()).build(); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Unexpected signature for void " - + "com.squareup.moshi.AdapterMethodsTest$UnexpectedSignatureToJsonAdapter.pointToJson" - + "(com.squareup.moshi.AdapterMethodsTest$Point).\n" - + "@ToJson method signatures may have one of the following structures:\n" - + " void toJson(JsonWriter writer, T value) throws ;\n" - + " void toJson(JsonWriter writer, T value," - + " JsonAdapter delegate, ) throws ;\n" - + " R toJson(T value) throws ;\n"); + assertThat(expected) + .hasMessage( + "Unexpected signature for void " + + "com.squareup.moshi.AdapterMethodsTest$UnexpectedSignatureToJsonAdapter.pointToJson" + + "(com.squareup.moshi.AdapterMethodsTest$Point).\n" + + "@ToJson method signatures may have one of the following structures:\n" + + " void toJson(JsonWriter writer, T value) throws ;\n" + + " void toJson(JsonWriter writer, T value," + + " JsonAdapter delegate, ) throws ;\n" + + " R toJson(T value) throws ;\n"); } } static class UnexpectedSignatureToJsonAdapter { - @ToJson void pointToJson(Point point) { - } + @ToJson + void pointToJson(Point point) {} } - @Test public void unexpectedSignatureFromAdapters() throws Exception { + @Test + public void unexpectedSignatureFromAdapters() throws Exception { Moshi.Builder builder = new Moshi.Builder(); try { builder.add(new UnexpectedSignatureFromJsonAdapter()).build(); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Unexpected signature for void " - + "com.squareup.moshi.AdapterMethodsTest$UnexpectedSignatureFromJsonAdapter.pointFromJson" - + "(java.lang.String).\n" - + "@FromJson method signatures may have one of the following structures:\n" - + " R fromJson(JsonReader jsonReader) throws ;\n" - + " R fromJson(JsonReader jsonReader," - + " JsonAdapter delegate, ) throws ;\n" - + " R fromJson(T value) throws ;\n"); + assertThat(expected) + .hasMessage( + "Unexpected signature for void " + + "com.squareup.moshi.AdapterMethodsTest$UnexpectedSignatureFromJsonAdapter.pointFromJson" + + "(java.lang.String).\n" + + "@FromJson method signatures may have one of the following structures:\n" + + " R fromJson(JsonReader jsonReader) throws ;\n" + + " R fromJson(JsonReader jsonReader," + + " JsonAdapter delegate, ) throws ;\n" + + " R fromJson(T value) throws ;\n"); } } static class UnexpectedSignatureFromJsonAdapter { - @FromJson void pointFromJson(String point) { - } + @FromJson + void pointFromJson(String point) {} } /** - * Simple adapter methods are not invoked for null values unless they're annotated {@code - * @Nullable}. (The specific annotation class doesn't matter; just its simple name.) + * Simple adapter methods are not invoked for null values unless they're annotated + * {@code @Nullable}. (The specific annotation class doesn't matter; just its simple name.) */ - @Test public void toAndFromNullNotNullable() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new NotNullablePointAsListOfIntegersJsonAdapter()) - .build(); + @Test + public void toAndFromNullNotNullable() throws Exception { + Moshi moshi = + new Moshi.Builder().add(new NotNullablePointAsListOfIntegersJsonAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class).lenient(); assertThat(pointAdapter.toJson(null)).isEqualTo("null"); assertThat(pointAdapter.fromJson("null")).isNull(); } static class NotNullablePointAsListOfIntegersJsonAdapter { - @ToJson List pointToJson(Point point) { + @ToJson + List pointToJson(Point point) { throw new AssertionError(); } - @FromJson Point pointFromJson(List o) throws Exception { + @FromJson + Point pointFromJson(List o) throws Exception { throw new AssertionError(); } } - @Test public void toAndFromNullNullable() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new NullablePointAsListOfIntegersJsonAdapter()) - .build(); + @Test + public void toAndFromNullNullable() throws Exception { + Moshi moshi = new Moshi.Builder().add(new NullablePointAsListOfIntegersJsonAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class).lenient(); assertThat(pointAdapter.toJson(null)).isEqualTo("[0,0]"); assertThat(pointAdapter.fromJson("null")).isEqualTo(new Point(0, 0)); } static class NullablePointAsListOfIntegersJsonAdapter { - @ToJson List pointToJson(@Nullable Point point) { - return point != null - ? Arrays.asList(point.x, point.y) - : Arrays.asList(0, 0); + @ToJson + List pointToJson(@Nullable Point point) { + return point != null ? Arrays.asList(point.x, point.y) : Arrays.asList(0, 0); } - @FromJson Point pointFromJson(@Nullable List o) throws Exception { + @FromJson + Point pointFromJson(@Nullable List o) throws Exception { if (o == null) return new Point(0, 0); if (o.size() == 2) return new Point(o.get(0), o.get(1)); throw new Exception("Expected null or 2 elements but was " + o); @@ -384,20 +423,19 @@ static class NullablePointAsListOfIntegersJsonAdapter { } @Retention(RetentionPolicy.RUNTIME) - @interface Nullable { - } + @interface Nullable {} - @Test public void toAndFromNullJsonWithWriterAndReader() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new NullableIntToJsonAdapter()) - .build(); + @Test + public void toAndFromNullJsonWithWriterAndReader() throws Exception { + Moshi moshi = new Moshi.Builder().add(new NullableIntToJsonAdapter()).build(); JsonAdapter pointAdapter = moshi.adapter(Point.class); assertThat(pointAdapter.fromJson("{\"x\":null,\"y\":3}")).isEqualTo(new Point(-1, 3)); assertThat(pointAdapter.toJson(new Point(-1, 3))).isEqualTo("{\"y\":3}"); } static class NullableIntToJsonAdapter { - @FromJson int jsonToInt(JsonReader reader) throws IOException { + @FromJson + int jsonToInt(JsonReader reader) throws IOException { if (reader.peek() == JsonReader.Token.NULL) { reader.nextNull(); return -1; @@ -405,7 +443,8 @@ static class NullableIntToJsonAdapter { return reader.nextInt(); } - @ToJson void intToJson(JsonWriter writer, int value) throws IOException { + @ToJson + void intToJson(JsonWriter writer, int value) throws IOException { if (value == -1) { writer.nullValue(); } else { @@ -414,17 +453,15 @@ static class NullableIntToJsonAdapter { } } - @Test public void adapterThrows() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new ExceptionThrowingPointJsonAdapter()) - .build(); + @Test + public void adapterThrows() throws Exception { + Moshi moshi = new Moshi.Builder().add(new ExceptionThrowingPointJsonAdapter()).build(); JsonAdapter arrayOfPointAdapter = moshi.adapter(Point[].class).lenient(); try { - arrayOfPointAdapter.toJson(new Point[] { null, null, new Point(0, 0) }); + arrayOfPointAdapter.toJson(new Point[] {null, null, new Point(0, 0)}); fail(); } catch (JsonDataException expected) { - assertThat(expected.getMessage()) - .isEqualTo("java.lang.Exception: pointToJson fail! at $[2]"); + assertThat(expected.getMessage()).isEqualTo("java.lang.Exception: pointToJson fail! at $[2]"); } try { arrayOfPointAdapter.fromJson("[null,null,[0,0]]"); @@ -436,58 +473,70 @@ static class NullableIntToJsonAdapter { } static class ExceptionThrowingPointJsonAdapter { - @ToJson void pointToJson(JsonWriter writer, Point point) throws Exception { + @ToJson + void pointToJson(JsonWriter writer, Point point) throws Exception { if (point != null) throw new Exception("pointToJson fail!"); writer.nullValue(); } - @FromJson Point pointFromJson(JsonReader reader) throws Exception { + @FromJson + Point pointFromJson(JsonReader reader) throws Exception { if (reader.peek() == JsonReader.Token.NULL) return reader.nextNull(); throw new Exception("pointFromJson fail!"); } } - @Test public void adapterDoesToJsonOnly() throws Exception { - Object shapeToJsonAdapter = new Object() { - @ToJson String shapeToJson(Shape shape) { - throw new AssertionError(); - } - }; + @Test + public void adapterDoesToJsonOnly() throws Exception { + Object shapeToJsonAdapter = + new Object() { + @ToJson + String shapeToJson(Shape shape) { + throw new AssertionError(); + } + }; - Moshi toJsonMoshi = new Moshi.Builder() - .add(shapeToJsonAdapter) - .build(); + Moshi toJsonMoshi = new Moshi.Builder().add(shapeToJsonAdapter).build(); try { toJsonMoshi.adapter(Shape.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("No @FromJson adapter for interface " - + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); + assertThat(e) + .hasMessage( + "No @FromJson adapter for interface " + + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); assertThat(e).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(e.getCause()).hasMessage("No next JsonAdapter for interface " - + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); + assertThat(e.getCause()) + .hasMessage( + "No next JsonAdapter for interface " + + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); } } - @Test public void adapterDoesFromJsonOnly() throws Exception { - Object shapeFromJsonAdapter = new Object() { - @FromJson Shape shapeFromJson(String shape) { - throw new AssertionError(); - } - }; + @Test + public void adapterDoesFromJsonOnly() throws Exception { + Object shapeFromJsonAdapter = + new Object() { + @FromJson + Shape shapeFromJson(String shape) { + throw new AssertionError(); + } + }; - Moshi fromJsonMoshi = new Moshi.Builder() - .add(shapeFromJsonAdapter) - .build(); + Moshi fromJsonMoshi = new Moshi.Builder().add(shapeFromJsonAdapter).build(); try { fromJsonMoshi.adapter(Shape.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("No @ToJson adapter for interface " - + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); + assertThat(e) + .hasMessage( + "No @ToJson adapter for interface " + + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); assertThat(e).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(e.getCause()).hasMessage("No next JsonAdapter for interface " - + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); + assertThat(e.getCause()) + .hasMessage( + "No next JsonAdapter for interface " + + "com.squareup.moshi.AdapterMethodsTest$Shape (with no annotations)"); } } @@ -495,10 +544,9 @@ static class ExceptionThrowingPointJsonAdapter { * Unfortunately in some versions of Android the implementations of {@link ParameterizedType} * doesn't implement equals and hashCode. Confirm that we work around that. */ - @Test public void parameterizedTypeEqualsNotUsed() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new ListOfStringJsonAdapter()) - .build(); + @Test + public void parameterizedTypeEqualsNotUsed() throws Exception { + Moshi moshi = new Moshi.Builder().add(new ListOfStringJsonAdapter()).build(); // This class doesn't implement equals() and hashCode() as it should. ParameterizedType listOfStringType = brokenParameterizedType(0, List.class, String.class); @@ -509,7 +557,8 @@ static class ExceptionThrowingPointJsonAdapter { } static class ListOfStringJsonAdapter { - @ToJson String listOfStringToJson(List list) { + @ToJson + String listOfStringToJson(List list) { StringBuilder result = new StringBuilder(); for (int i = 0; i < list.size(); i++) { if (i > 0) result.append('|'); @@ -518,7 +567,8 @@ static class ListOfStringJsonAdapter { return result.toString(); } - @FromJson List listOfStringFromJson(String string) { + @FromJson + List listOfStringFromJson(String string) { return Arrays.asList(string.split("\\|")); } } @@ -527,7 +577,8 @@ static class ListOfStringJsonAdapter { * Even when the types we use to look up JSON adapters are not equal, if they're equivalent they * should return the same JsonAdapter instance. */ - @Test public void parameterizedTypeCacheKey() throws Exception { + @Test + public void parameterizedTypeCacheKey() throws Exception { Moshi moshi = new Moshi.Builder().build(); Type a = brokenParameterizedType(0, List.class, String.class); @@ -538,11 +589,13 @@ static class ListOfStringJsonAdapter { assertThat(moshi.adapter(c)).isSameAs(moshi.adapter(a)); } - @Test public void writerAndReaderTakingJsonAdapterParameter() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointWriterAndReaderJsonAdapter()) - .add(new JsonAdapterWithWriterAndReaderTakingJsonAdapterParameter()) - .build(); + @Test + public void writerAndReaderTakingJsonAdapterParameter() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new PointWriterAndReaderJsonAdapter()) + .add(new JsonAdapterWithWriterAndReaderTakingJsonAdapterParameter()) + .build(); JsonAdapter lineAdapter = moshi.adapter(Line.class); Line line = new Line(new Point(5, 8), new Point(3, 2)); assertThat(lineAdapter.toJson(line)).isEqualTo("[[5,8],[3,2]]"); @@ -550,16 +603,17 @@ static class ListOfStringJsonAdapter { } static class JsonAdapterWithWriterAndReaderTakingJsonAdapterParameter { - @ToJson void lineToJson( - JsonWriter writer, Line line, JsonAdapter pointAdapter) throws IOException { + @ToJson + void lineToJson(JsonWriter writer, Line line, JsonAdapter pointAdapter) + throws IOException { writer.beginArray(); pointAdapter.toJson(writer, line.a); pointAdapter.toJson(writer, line.b); writer.endArray(); } - @FromJson Line lineFromJson( - JsonReader reader, JsonAdapter pointAdapter) throws Exception { + @FromJson + Line lineFromJson(JsonReader reader, JsonAdapter pointAdapter) throws Exception { reader.beginArray(); Point a = pointAdapter.fromJson(reader); Point b = pointAdapter.fromJson(reader); @@ -568,23 +622,28 @@ static class JsonAdapterWithWriterAndReaderTakingJsonAdapterParameter { } } - @Test public void writerAndReaderTakingAnnotatedJsonAdapterParameter() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointWithParensJsonAdapter()) - .add(new JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterParameter()) - .build(); + @Test + public void writerAndReaderTakingAnnotatedJsonAdapterParameter() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new PointWithParensJsonAdapter()) + .add(new JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterParameter()) + .build(); JsonAdapter lineAdapter = moshi.adapter(Line.class); Line line = new Line(new Point(5, 8), new Point(3, 2)); assertThat(lineAdapter.toJson(line)).isEqualTo("[\"(5 8)\",\"(3 2)\"]"); assertThat(lineAdapter.fromJson("[\"(5 8)\",\"(3 2)\"]")).isEqualTo(line); } - static class PointWithParensJsonAdapter{ - @ToJson String pointToJson(@WithParens Point point) throws IOException { + static class PointWithParensJsonAdapter { + @ToJson + String pointToJson(@WithParens Point point) throws IOException { return String.format("(%s %s)", point.x, point.y); } - @FromJson @WithParens Point pointFromJson(String string) throws Exception { + @FromJson + @WithParens + Point pointFromJson(String string) throws Exception { Matcher matcher = Pattern.compile("\\((\\d+) (\\d+)\\)").matcher(string); if (!matcher.matches()) throw new JsonDataException(); return new Point(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2))); @@ -592,16 +651,18 @@ static class PointWithParensJsonAdapter{ } static class JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterParameter { - @ToJson void lineToJson(JsonWriter writer, Line line, - @WithParens JsonAdapter pointAdapter) throws IOException { + @ToJson + void lineToJson(JsonWriter writer, Line line, @WithParens JsonAdapter pointAdapter) + throws IOException { writer.beginArray(); pointAdapter.toJson(writer, line.a); pointAdapter.toJson(writer, line.b); writer.endArray(); } - @FromJson Line lineFromJson( - JsonReader reader, @WithParens JsonAdapter pointAdapter) throws Exception { + @FromJson + Line lineFromJson(JsonReader reader, @WithParens JsonAdapter pointAdapter) + throws Exception { reader.beginArray(); Point a = pointAdapter.fromJson(reader); Point b = pointAdapter.fromJson(reader); @@ -610,12 +671,14 @@ static class JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterParameter { } } - @Test public void writerAndReaderTakingMultipleJsonAdapterParameters() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PointWriterAndReaderJsonAdapter()) - .add(new PointWithParensJsonAdapter()) - .add(new JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterParameters()) - .build(); + @Test + public void writerAndReaderTakingMultipleJsonAdapterParameters() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new PointWriterAndReaderJsonAdapter()) + .add(new PointWithParensJsonAdapter()) + .add(new JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterParameters()) + .build(); JsonAdapter lineAdapter = moshi.adapter(Line.class); Line line = new Line(new Point(5, 8), new Point(3, 2)); assertThat(lineAdapter.toJson(line)).isEqualTo("[[5,8],\"(3 2)\"]"); @@ -623,16 +686,23 @@ static class JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterParameter { } static class JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterParameters { - @ToJson void lineToJson(JsonWriter writer, Line line, - JsonAdapter aAdapter, @WithParens JsonAdapter bAdapter) throws IOException { + @ToJson + void lineToJson( + JsonWriter writer, + Line line, + JsonAdapter aAdapter, + @WithParens JsonAdapter bAdapter) + throws IOException { writer.beginArray(); aAdapter.toJson(writer, line.a); bAdapter.toJson(writer, line.b); writer.endArray(); } - @FromJson Line lineFromJson(JsonReader reader, - JsonAdapter aAdapter, @WithParens JsonAdapter bAdapter) throws Exception { + @FromJson + Line lineFromJson( + JsonReader reader, JsonAdapter aAdapter, @WithParens JsonAdapter bAdapter) + throws Exception { reader.beginArray(); Point a = aAdapter.fromJson(reader); Point b = bAdapter.fromJson(reader); @@ -643,10 +713,10 @@ static class JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterParameters { @Retention(RUNTIME) @JsonQualifier - public @interface WithParens { - } + public @interface WithParens {} - @Test public void noToJsonAdapterTakingJsonAdapterParameter() throws Exception { + @Test + public void noToJsonAdapterTakingJsonAdapterParameter() throws Exception { try { new Moshi.Builder().add(new ToJsonAdapterTakingJsonAdapterParameter()); fail(); @@ -656,12 +726,14 @@ static class JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterParameters { } static class ToJsonAdapterTakingJsonAdapterParameter { - @ToJson String lineToJson(Line line, JsonAdapter pointAdapter) throws IOException { + @ToJson + String lineToJson(Line line, JsonAdapter pointAdapter) throws IOException { throw new AssertionError(); } } - @Test public void noFromJsonAdapterTakingJsonAdapterParameter() throws Exception { + @Test + public void noFromJsonAdapterTakingJsonAdapterParameter() throws Exception { try { new Moshi.Builder().add(new FromJsonAdapterTakingJsonAdapterParameter()); fail(); @@ -671,17 +743,18 @@ static class ToJsonAdapterTakingJsonAdapterParameter { } static class FromJsonAdapterTakingJsonAdapterParameter { - @FromJson Line lineFromJson(String value, JsonAdapter pointAdapter) throws Exception { + @FromJson + Line lineFromJson(String value, JsonAdapter pointAdapter) throws Exception { throw new AssertionError(); } } - @Test public void adaptedTypeIsEnclosedParameterizedType() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new EnclosedParameterizedTypeJsonAdapter()) - .build(); - JsonAdapter> boxAdapter = moshi.adapter(Types.newParameterizedTypeWithOwner( - AdapterMethodsTest.class, Box.class, Point.class)); + @Test + public void adaptedTypeIsEnclosedParameterizedType() throws Exception { + Moshi moshi = new Moshi.Builder().add(new EnclosedParameterizedTypeJsonAdapter()).build(); + JsonAdapter> boxAdapter = + moshi.adapter( + Types.newParameterizedTypeWithOwner(AdapterMethodsTest.class, Box.class, Point.class)); Box box = new Box<>(new Point(5, 8)); String json = "[{\"x\":5,\"y\":8}]"; assertThat(boxAdapter.toJson(box)).isEqualTo(json); @@ -689,11 +762,13 @@ static class FromJsonAdapterTakingJsonAdapterParameter { } static class EnclosedParameterizedTypeJsonAdapter { - @FromJson Box boxFromJson(List points) { + @FromJson + Box boxFromJson(List points) { return new Box<>(points.get(0)); } - @ToJson List boxToJson(Box box) throws Exception { + @ToJson + List boxToJson(Box box) throws Exception { return Collections.singletonList(box.data); } } @@ -705,23 +780,24 @@ public Box(T data) { this.data = data; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof Box && ((Box) o).data.equals(data); } - @Override public int hashCode() { + @Override + public int hashCode() { return data.hashCode(); } } - @Test public void genericArrayTypes() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new ByteArrayJsonAdapter()) - .build(); + @Test + public void genericArrayTypes() throws Exception { + Moshi moshi = new Moshi.Builder().add(new ByteArrayJsonAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(MapOfByteArrays.class); - MapOfByteArrays mapOfByteArrays = new MapOfByteArrays( - Collections.singletonMap("a", new byte[] { 0, -1})); + MapOfByteArrays mapOfByteArrays = + new MapOfByteArrays(Collections.singletonMap("a", new byte[] {0, -1})); String json = "{\"map\":{\"a\":\"00ff\"}}"; assertThat(jsonAdapter.toJson(mapOfByteArrays)).isEqualTo(json); @@ -729,11 +805,13 @@ public Box(T data) { } static class ByteArrayJsonAdapter { - @ToJson String byteArrayToJson(byte[] b) { + @ToJson + String byteArrayToJson(byte[] b) { return ByteString.of(b).hex(); } - @FromJson byte[] byteArrayFromJson(String s) throws Exception { + @FromJson + byte[] byteArrayFromJson(String s) throws Exception { return ByteString.decodeHex(s).toByteArray(); } } @@ -745,21 +823,22 @@ public MapOfByteArrays(Map map) { this.map = map; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof MapOfByteArrays && o.toString().equals(toString()); } - @Override public int hashCode() { + @Override + public int hashCode() { return toString().hashCode(); } - @Override public String toString() { + @Override + public String toString() { StringBuilder result = new StringBuilder(); for (Map.Entry entry : map.entrySet()) { if (result.length() > 0) result.append(", "); - result.append(entry.getKey()) - .append(":") - .append(Arrays.toString(entry.getValue())); + result.append(entry.getKey()).append(":").append(Arrays.toString(entry.getValue())); } return result.toString(); } @@ -774,11 +853,13 @@ public Point(int x, int y) { this.y = y; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof Point && ((Point) o).x == x && ((Point) o).y == y; } - @Override public int hashCode() { + @Override + public int hashCode() { return x * 37 + y; } } @@ -792,11 +873,13 @@ public Line(Point a, Point b) { this.b = b; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof Line && ((Line) o).a.equals(a) && ((Line) o).b.equals(b); } - @Override public int hashCode() { + @Override + public int hashCode() { return a.hashCode() * 37 + b.hashCode(); } } @@ -813,23 +896,28 @@ interface Shape { ParameterizedType brokenParameterizedType( final int hashCode, final Class rawType, final Type... typeArguments) { return new ParameterizedType() { - @Override public Type[] getActualTypeArguments() { + @Override + public Type[] getActualTypeArguments() { return typeArguments; } - @Override public Type getRawType() { + @Override + public Type getRawType() { return rawType; } - @Override public Type getOwnerType() { + @Override + public Type getOwnerType() { return null; } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other == this; } - @Override public int hashCode() { + @Override + public int hashCode() { return hashCode; } }; diff --git a/moshi/src/test/java/com/squareup/moshi/CircularAdaptersTest.java b/moshi/src/test/java/com/squareup/moshi/CircularAdaptersTest.java index 00f036396..7e21a385b 100644 --- a/moshi/src/test/java/com/squareup/moshi/CircularAdaptersTest.java +++ b/moshi/src/test/java/com/squareup/moshi/CircularAdaptersTest.java @@ -15,6 +15,9 @@ */ package com.squareup.moshi; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.assertj.core.api.Assertions.assertThat; + import com.squareup.moshi.internal.Util; import java.io.IOException; import java.lang.annotation.Annotation; @@ -23,9 +26,6 @@ import java.util.Set; import org.junit.Test; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.assertj.core.api.Assertions.assertThat; - public final class CircularAdaptersTest { static class Team { final String lead; @@ -47,17 +47,22 @@ static class Project { } } - @Test public void circularAdapters() throws Exception { + @Test + public void circularAdapters() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter teamAdapter = moshi.adapter(Team.class); - Team team = new Team("Alice", new Project("King", new Team("Charlie", - new Project("Delivery", null)))); - assertThat(teamAdapter.toJson(team)).isEqualTo("{\"lead\":\"Alice\",\"projects\":[{\"name\":" - + "\"King\",\"teams\":[{\"lead\":\"Charlie\",\"projects\":[{\"name\":\"Delivery\"}]}]}]}"); - - Team fromJson = teamAdapter.fromJson("{\"lead\":\"Alice\",\"projects\":[{\"name\":" - + "\"King\",\"teams\":[{\"lead\":\"Charlie\",\"projects\":[{\"name\":\"Delivery\"}]}]}]}"); + Team team = + new Team("Alice", new Project("King", new Team("Charlie", new Project("Delivery", null)))); + assertThat(teamAdapter.toJson(team)) + .isEqualTo( + "{\"lead\":\"Alice\",\"projects\":[{\"name\":" + + "\"King\",\"teams\":[{\"lead\":\"Charlie\",\"projects\":[{\"name\":\"Delivery\"}]}]}]}"); + + Team fromJson = + teamAdapter.fromJson( + "{\"lead\":\"Alice\",\"projects\":[{\"name\":" + + "\"King\",\"teams\":[{\"lead\":\"Charlie\",\"projects\":[{\"name\":\"Delivery\"}]}]}]}"); assertThat(fromJson.lead).isEqualTo("Alice"); assertThat(fromJson.projects[0].name).isEqualTo("King"); assertThat(fromJson.projects[0].teams[0].lead).isEqualTo("Charlie"); @@ -66,13 +71,11 @@ static class Project { @Retention(RUNTIME) @JsonQualifier - public @interface Left { - } + public @interface Left {} @Retention(RUNTIME) @JsonQualifier - public @interface Right { - } + public @interface Right {} static class Node { final String name; @@ -101,8 +104,8 @@ Node minusPrefix(String prefix) { * work. */ static class PrefixingNodeFactory implements JsonAdapter.Factory { - @Override public JsonAdapter create( - Type type, Set annotations, Moshi moshi) { + @Override + public JsonAdapter create(Type type, Set annotations, Moshi moshi) { if (type != Node.class) return null; final String prefix; @@ -117,11 +120,13 @@ static class PrefixingNodeFactory implements JsonAdapter.Factory { final JsonAdapter delegate = moshi.nextAdapter(this, Node.class, Util.NO_ANNOTATIONS); return new JsonAdapter() { - @Override public void toJson(JsonWriter writer, Node value) throws IOException { + @Override + public void toJson(JsonWriter writer, Node value) throws IOException { delegate.toJson(writer, value.plusPrefix(prefix)); } - @Override public Node fromJson(JsonReader reader) throws IOException { + @Override + public Node fromJson(JsonReader reader) throws IOException { Node result = delegate.fromJson(reader); return result.minusPrefix(prefix); } @@ -129,26 +134,31 @@ static class PrefixingNodeFactory implements JsonAdapter.Factory { } } - @Test public void circularAdaptersAndAnnotations() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new PrefixingNodeFactory()) - .build(); + @Test + public void circularAdaptersAndAnnotations() throws Exception { + Moshi moshi = new Moshi.Builder().add(new PrefixingNodeFactory()).build(); JsonAdapter nodeAdapter = moshi.adapter(Node.class); - Node tree = new Node("C", - new Node("A", null, new Node("B", null, null)), - new Node("D", null, new Node("E", null, null))); - assertThat(nodeAdapter.toJson(tree)).isEqualTo("{" - + "\"left\":{\"name\":\"L A\",\"right\":{\"name\":\"R B\"}}," - + "\"name\":\"C\"," - + "\"right\":{\"name\":\"R D\",\"right\":{\"name\":\"R E\"}}" - + "}"); - - Node fromJson = nodeAdapter.fromJson("{" - + "\"left\":{\"name\":\"L A\",\"right\":{\"name\":\"R B\"}}," - + "\"name\":\"C\"," - + "\"right\":{\"name\":\"R D\",\"right\":{\"name\":\"R E\"}}" - + "}"); + Node tree = + new Node( + "C", + new Node("A", null, new Node("B", null, null)), + new Node("D", null, new Node("E", null, null))); + assertThat(nodeAdapter.toJson(tree)) + .isEqualTo( + "{" + + "\"left\":{\"name\":\"L A\",\"right\":{\"name\":\"R B\"}}," + + "\"name\":\"C\"," + + "\"right\":{\"name\":\"R D\",\"right\":{\"name\":\"R E\"}}" + + "}"); + + Node fromJson = + nodeAdapter.fromJson( + "{" + + "\"left\":{\"name\":\"L A\",\"right\":{\"name\":\"R B\"}}," + + "\"name\":\"C\"," + + "\"right\":{\"name\":\"R D\",\"right\":{\"name\":\"R E\"}}" + + "}"); assertThat(fromJson.name).isEqualTo("C"); assertThat(fromJson.left.name).isEqualTo("A"); assertThat(fromJson.left.right.name).isEqualTo("B"); diff --git a/moshi/src/test/java/com/squareup/moshi/ClassJsonAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/ClassJsonAdapterTest.java index b6f5d7e36..50c7420c7 100644 --- a/moshi/src/test/java/com/squareup/moshi/ClassJsonAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/ClassJsonAdapterTest.java @@ -15,6 +15,11 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.TestUtil.newReader; +import static com.squareup.moshi.internal.Util.NO_ANNOTATIONS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; @@ -24,11 +29,6 @@ import okio.Buffer; import org.junit.Test; -import static com.squareup.moshi.TestUtil.newReader; -import static com.squareup.moshi.internal.Util.NO_ANNOTATIONS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class ClassJsonAdapterTest { private final Moshi moshi = new Moshi.Builder().build(); @@ -37,7 +37,8 @@ static class BasicPizza { boolean extraCheese; } - @Test public void basicClassAdapter() throws Exception { + @Test + public void basicClassAdapter() throws Exception { BasicPizza value = new BasicPizza(); value.diameter = 13; value.extraCheese = true; @@ -53,14 +54,15 @@ static class PrivateFieldsPizza { private String secretIngredient; } - @Test public void privateFields() throws Exception { + @Test + public void privateFields() throws Exception { PrivateFieldsPizza value = new PrivateFieldsPizza(); value.secretIngredient = "vodka"; String toJson = toJson(PrivateFieldsPizza.class, value); assertThat(toJson).isEqualTo("{\"secretIngredient\":\"vodka\"}"); - PrivateFieldsPizza fromJson = fromJson( - PrivateFieldsPizza.class, "{\"secretIngredient\":\"vodka\"}"); + PrivateFieldsPizza fromJson = + fromJson(PrivateFieldsPizza.class, "{\"secretIngredient\":\"vodka\"}"); assertThat(fromJson.secretIngredient).isEqualTo("vodka"); } @@ -72,7 +74,8 @@ static class DessertPizza extends BasePizza { boolean chocolate; } - @Test public void typeHierarchy() throws Exception { + @Test + public void typeHierarchy() throws Exception { DessertPizza value = new DessertPizza(); value.diameter = 13; value.chocolate = true; @@ -95,7 +98,8 @@ static class ExtendsBaseAbcde extends BaseAbcde { int e; } - @Test public void fieldsAreAlphabeticalAcrossFlattenedHierarchy() throws Exception { + @Test + public void fieldsAreAlphabeticalAcrossFlattenedHierarchy() throws Exception { ExtendsBaseAbcde value = new ExtendsBaseAbcde(); value.a = 4; value.b = 5; @@ -105,8 +109,8 @@ static class ExtendsBaseAbcde extends BaseAbcde { String toJson = toJson(ExtendsBaseAbcde.class, value); assertThat(toJson).isEqualTo("{\"a\":4,\"b\":5,\"c\":6,\"d\":7,\"e\":8}"); - ExtendsBaseAbcde fromJson = fromJson( - ExtendsBaseAbcde.class, "{\"a\":4,\"b\":5,\"c\":6,\"d\":7,\"e\":8}"); + ExtendsBaseAbcde fromJson = + fromJson(ExtendsBaseAbcde.class, "{\"a\":4,\"b\":5,\"c\":6,\"d\":7,\"e\":8}"); assertThat(fromJson.a).isEqualTo(4); assertThat(fromJson.b).isEqualTo(5); assertThat(fromJson.c).isEqualTo(6); @@ -119,7 +123,8 @@ static class StaticFields { int b; } - @Test public void staticFieldsOmitted() throws Exception { + @Test + public void staticFieldsOmitted() throws Exception { StaticFields value = new StaticFields(); value.b = 12; String toJson = toJson(StaticFields.class, value); @@ -135,7 +140,8 @@ static class TransientFields { int b; } - @Test public void transientFieldsOmitted() throws Exception { + @Test + public void transientFieldsOmitted() throws Exception { TransientFields value = new TransientFields(); value.a = 11; value.b = 12; @@ -155,30 +161,38 @@ static class ExtendsBaseA extends BaseA { int a; } - @Test public void fieldNameCollision() throws Exception { + @Test + public void fieldNameCollision() throws Exception { try { ClassJsonAdapter.FACTORY.create(ExtendsBaseA.class, NO_ANNOTATIONS, moshi); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Conflicting fields:\n" - + " int com.squareup.moshi.ClassJsonAdapterTest$ExtendsBaseA.a\n" - + " int com.squareup.moshi.ClassJsonAdapterTest$BaseA.a"); + assertThat(expected) + .hasMessage( + "Conflicting fields:\n" + + " int com.squareup.moshi.ClassJsonAdapterTest$ExtendsBaseA.a\n" + + " int com.squareup.moshi.ClassJsonAdapterTest$BaseA.a"); } } static class NameCollision { String foo; - @Json(name = "foo") String bar; + + @Json(name = "foo") + String bar; } - @Test public void jsonAnnotationNameCollision() throws Exception { + @Test + public void jsonAnnotationNameCollision() throws Exception { try { ClassJsonAdapter.FACTORY.create(NameCollision.class, NO_ANNOTATIONS, moshi); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Conflicting fields:\n" - + " java.lang.String com.squareup.moshi.ClassJsonAdapterTest$NameCollision.foo\n" - + " java.lang.String com.squareup.moshi.ClassJsonAdapterTest$NameCollision.bar"); + assertThat(expected) + .hasMessage( + "Conflicting fields:\n" + + " java.lang.String com.squareup.moshi.ClassJsonAdapterTest$NameCollision.foo\n" + + " java.lang.String com.squareup.moshi.ClassJsonAdapterTest$NameCollision.bar"); } } @@ -190,7 +204,8 @@ static class ExtendsTransientBaseA extends TransientBaseA { int a; } - @Test public void fieldNameCollisionWithTransientFieldIsOkay() throws Exception { + @Test + public void fieldNameCollisionWithTransientFieldIsOkay() throws Exception { ExtendsTransientBaseA value = new ExtendsTransientBaseA(); value.a = 11; ((TransientBaseA) value).a = 12; @@ -211,7 +226,8 @@ static class NoArgConstructor { } } - @Test public void noArgConstructor() throws Exception { + @Test + public void noArgConstructor() throws Exception { NoArgConstructor fromJson = fromJson(NoArgConstructor.class, "{\"b\":8}"); assertThat(fromJson.a).isEqualTo(5); assertThat(fromJson.b).isEqualTo(8); @@ -223,7 +239,8 @@ static class NoArgConstructorThrowsCheckedException { } } - @Test public void noArgConstructorThrowsCheckedException() throws Exception { + @Test + public void noArgConstructorThrowsCheckedException() throws Exception { try { fromJson(NoArgConstructorThrowsCheckedException.class, "{}"); fail(); @@ -238,7 +255,8 @@ static class NoArgConstructorThrowsUncheckedException { } } - @Test public void noArgConstructorThrowsUncheckedException() throws Exception { + @Test + public void noArgConstructorThrowsUncheckedException() throws Exception { try { fromJson(NoArgConstructorThrowsUncheckedException.class, "{}"); fail(); @@ -252,9 +270,10 @@ static class NoArgConstructorWithDefaultField { int b; } - @Test public void noArgConstructorFieldDefaultsHonored() throws Exception { - NoArgConstructorWithDefaultField fromJson = fromJson( - NoArgConstructorWithDefaultField.class, "{\"b\":8}"); + @Test + public void noArgConstructorFieldDefaultsHonored() throws Exception { + NoArgConstructorWithDefaultField fromJson = + fromJson(NoArgConstructorWithDefaultField.class, "{\"b\":8}"); assertThat(fromJson.a).isEqualTo(5); assertThat(fromJson.b).isEqualTo(8); } @@ -267,7 +286,8 @@ public MagicConstructor(Void argument) { } } - @Test public void magicConstructor() throws Exception { + @Test + public void magicConstructor() throws Exception { MagicConstructor fromJson = fromJson(MagicConstructor.class, "{\"a\":8}"); assertThat(fromJson.a).isEqualTo(8); } @@ -281,9 +301,10 @@ public MagicConstructorWithDefaultField(Void argument) { } } - @Test public void magicConstructorFieldDefaultsNotHonored() throws Exception { - MagicConstructorWithDefaultField fromJson = fromJson( - MagicConstructorWithDefaultField.class, "{\"b\":3}"); + @Test + public void magicConstructorFieldDefaultsNotHonored() throws Exception { + MagicConstructorWithDefaultField fromJson = + fromJson(MagicConstructorWithDefaultField.class, "{\"b\":3}"); assertThat(fromJson.a).isEqualTo(0); // Surprising! No value is assigned. assertThat(fromJson.b).isEqualTo(3); } @@ -292,7 +313,8 @@ static class NullRootObject { int a; } - @Test public void nullRootObject() throws Exception { + @Test + public void nullRootObject() throws Exception { String toJson = toJson(PrivateFieldsPizza.class, null); assertThat(toJson).isEqualTo("null"); @@ -304,7 +326,8 @@ static class NullFieldValue { String a = "not null"; } - @Test public void nullFieldValues() throws Exception { + @Test + public void nullFieldValues() throws Exception { NullFieldValue value = new NullFieldValue(); value.a = null; String toJson = toJson(NullFieldValue.class, value); @@ -314,25 +337,30 @@ static class NullFieldValue { assertThat(fromJson.a).isNull(); } - class NonStatic { - } + class NonStatic {} - @Test public void nonStaticNestedClassNotSupported() throws Exception { + @Test + public void nonStaticNestedClassNotSupported() throws Exception { try { ClassJsonAdapter.FACTORY.create(NonStatic.class, NO_ANNOTATIONS, moshi); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Cannot serialize non-static nested class " - + "com.squareup.moshi.ClassJsonAdapterTest$NonStatic"); + assertThat(expected) + .hasMessage( + "Cannot serialize non-static nested class " + + "com.squareup.moshi.ClassJsonAdapterTest$NonStatic"); } } - @Test public void anonymousClassNotSupported() throws Exception { - Comparator c = new Comparator() { - @Override public int compare(Object a, Object b) { - return 0; - } - }; + @Test + public void anonymousClassNotSupported() throws Exception { + Comparator c = + new Comparator() { + @Override + public int compare(Object a, Object b) { + return 0; + } + }; try { ClassJsonAdapter.FACTORY.create(c.getClass(), NO_ANNOTATIONS, moshi); fail(); @@ -341,35 +369,38 @@ class NonStatic { } } - @Test public void localClassNotSupported() throws Exception { - class Local { - } + @Test + public void localClassNotSupported() throws Exception { + class Local {} try { ClassJsonAdapter.FACTORY.create(Local.class, NO_ANNOTATIONS, moshi); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Cannot serialize local class " - + "com.squareup.moshi.ClassJsonAdapterTest$1Local"); + assertThat(expected) + .hasMessage( + "Cannot serialize local class " + "com.squareup.moshi.ClassJsonAdapterTest$1Local"); } } - interface Interface { - } + interface Interface {} - @Test public void interfaceNotSupported() throws Exception { + @Test + public void interfaceNotSupported() throws Exception { assertThat(ClassJsonAdapter.FACTORY.create(Interface.class, NO_ANNOTATIONS, moshi)).isNull(); } - static abstract class Abstract { - } + abstract static class Abstract {} - @Test public void abstractClassNotSupported() throws Exception { + @Test + public void abstractClassNotSupported() throws Exception { try { ClassJsonAdapter.FACTORY.create(Abstract.class, NO_ANNOTATIONS, moshi); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("Cannot serialize abstract class " - + "com.squareup.moshi.ClassJsonAdapterTest$Abstract"); + assertThat(expected) + .hasMessage( + "Cannot serialize abstract class " + + "com.squareup.moshi.ClassJsonAdapterTest$Abstract"); } } @@ -381,14 +412,15 @@ public ExtendsPlatformClassWithPrivateField() { } } - @Test public void platformSuperclassPrivateFieldIsExcluded() throws Exception { + @Test + public void platformSuperclassPrivateFieldIsExcluded() throws Exception { ExtendsPlatformClassWithPrivateField value = new ExtendsPlatformClassWithPrivateField(); value.a = 4; String toJson = toJson(ExtendsPlatformClassWithPrivateField.class, value); assertThat(toJson).isEqualTo("{\"a\":4}"); - ExtendsPlatformClassWithPrivateField fromJson = fromJson( - ExtendsPlatformClassWithPrivateField.class, "{\"a\":4,\"ID\":\"BAR\"}"); + ExtendsPlatformClassWithPrivateField fromJson = + fromJson(ExtendsPlatformClassWithPrivateField.class, "{\"a\":4,\"ID\":\"BAR\"}"); assertThat(fromJson.a).isEqualTo(4); assertThat(fromJson.getID()).isEqualTo("FOO"); } @@ -401,7 +433,8 @@ public ExtendsPlatformClassWithProtectedField() { } } - @Test public void platformSuperclassProtectedFieldIsIncluded() throws Exception { + @Test + public void platformSuperclassProtectedFieldIsIncluded() throws Exception { ExtendsPlatformClassWithProtectedField value = new ExtendsPlatformClassWithProtectedField(); value.a = 4; value.write(5); @@ -409,36 +442,48 @@ public ExtendsPlatformClassWithProtectedField() { String toJson = toJson(ExtendsPlatformClassWithProtectedField.class, value); assertThat(toJson).isEqualTo("{\"a\":4,\"buf\":[5,6],\"count\":2}"); - ExtendsPlatformClassWithProtectedField fromJson = fromJson( - ExtendsPlatformClassWithProtectedField.class, "{\"a\":4,\"buf\":[5,6],\"count\":2}"); + ExtendsPlatformClassWithProtectedField fromJson = + fromJson( + ExtendsPlatformClassWithProtectedField.class, "{\"a\":4,\"buf\":[5,6],\"count\":2}"); assertThat(fromJson.a).isEqualTo(4); assertThat(fromJson.toByteArray()).contains((byte) 5, (byte) 6); } static class NamedFields { - @Json(name = "#") List phoneNumbers; - @Json(name = "@") String emailAddress; - @Json(name = "zip code") String zipCode; + @Json(name = "#") + List phoneNumbers; + + @Json(name = "@") + String emailAddress; + + @Json(name = "zip code") + String zipCode; } - @Test public void jsonAnnotationHonored() throws Exception { + @Test + public void jsonAnnotationHonored() throws Exception { NamedFields value = new NamedFields(); value.phoneNumbers = Arrays.asList("8005553333", "8005554444"); value.emailAddress = "cash@square.com"; value.zipCode = "94043"; String toJson = toJson(NamedFields.class, value); - assertThat(toJson).isEqualTo("{" - + "\"#\":[\"8005553333\",\"8005554444\"]," - + "\"@\":\"cash@square.com\"," - + "\"zip code\":\"94043\"" - + "}"); - - NamedFields fromJson = fromJson(NamedFields.class, "{" - + "\"#\":[\"8005553333\",\"8005554444\"]," - + "\"@\":\"cash@square.com\"," - + "\"zip code\":\"94043\"" - + "}"); + assertThat(toJson) + .isEqualTo( + "{" + + "\"#\":[\"8005553333\",\"8005554444\"]," + + "\"@\":\"cash@square.com\"," + + "\"zip code\":\"94043\"" + + "}"); + + NamedFields fromJson = + fromJson( + NamedFields.class, + "{" + + "\"#\":[\"8005553333\",\"8005554444\"]," + + "\"@\":\"cash@square.com\"," + + "\"zip code\":\"94043\"" + + "}"); assertThat(fromJson.phoneNumbers).isEqualTo(Arrays.asList("8005553333", "8005554444")); assertThat(fromJson.emailAddress).isEqualTo("cash@square.com"); assertThat(fromJson.zipCode).isEqualTo("94043"); @@ -452,19 +497,24 @@ static final class Box { } } - @Test public void parameterizedType() throws Exception { + @Test + public void parameterizedType() throws Exception { @SuppressWarnings("unchecked") - JsonAdapter> adapter = (JsonAdapter>) ClassJsonAdapter.FACTORY.create( - Types.newParameterizedTypeWithOwner(ClassJsonAdapterTest.class, Box.class, Integer.class), - NO_ANNOTATIONS, moshi); + JsonAdapter> adapter = + (JsonAdapter>) + ClassJsonAdapter.FACTORY.create( + Types.newParameterizedTypeWithOwner( + ClassJsonAdapterTest.class, Box.class, Integer.class), + NO_ANNOTATIONS, + moshi); assertThat(adapter.fromJson("{\"data\":5}").data).isEqualTo(5); assertThat(adapter.toJson(new Box<>(5))).isEqualTo("{\"data\":5}"); } private String toJson(Class type, T value) throws IOException { @SuppressWarnings("unchecked") // Factory.create returns an adapter that matches its argument. - JsonAdapter jsonAdapter = (JsonAdapter) ClassJsonAdapter.FACTORY.create( - type, NO_ANNOTATIONS, moshi); + JsonAdapter jsonAdapter = + (JsonAdapter) ClassJsonAdapter.FACTORY.create(type, NO_ANNOTATIONS, moshi); // Wrap in an array to avoid top-level object warnings without going completely lenient. Buffer buffer = new Buffer(); @@ -481,8 +531,8 @@ private String toJson(Class type, T value) throws IOException { private T fromJson(Class type, String json) throws IOException { @SuppressWarnings("unchecked") // Factory.create returns an adapter that matches its argument. - JsonAdapter jsonAdapter = (JsonAdapter) ClassJsonAdapter.FACTORY.create( - type, NO_ANNOTATIONS, moshi); + JsonAdapter jsonAdapter = + (JsonAdapter) ClassJsonAdapter.FACTORY.create(type, NO_ANNOTATIONS, moshi); // Wrap in an array to avoid top-level object warnings without going completely lenient. JsonReader jsonReader = newReader("[" + json + "]"); jsonReader.beginArray(); diff --git a/moshi/src/test/java/com/squareup/moshi/DeferredAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/DeferredAdapterTest.java index 4bfae0d09..e670bb517 100644 --- a/moshi/src/test/java/com/squareup/moshi/DeferredAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/DeferredAdapterTest.java @@ -15,6 +15,8 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; + import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.ArrayList; @@ -27,8 +29,6 @@ import javax.annotation.Nullable; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; - public final class DeferredAdapterTest { /** * When a type's JsonAdapter is circularly-dependent, Moshi creates a 'deferred adapter' to make @@ -36,41 +36,43 @@ public final class DeferredAdapterTest { * leak out until it's ready. * *

    This test sets up a circular dependency [BlueNode -> GreenNode -> BlueNode] and then tries - * to use a GreenNode JSON adapter before the BlueNode JSON adapter is built. It creates a - * similar cycle [BlueNode -> RedNode -> BlueNode] so the order adapters are retrieved is - * insignificant. + * to use a GreenNode JSON adapter before the BlueNode JSON adapter is built. It creates a similar + * cycle [BlueNode -> RedNode -> BlueNode] so the order adapters are retrieved is insignificant. * *

    This used to trigger a crash because we'd incorrectly put the GreenNode JSON adapter in the * cache even though it depended upon an incomplete BlueNode JSON adapter. */ - @Test public void concurrentSafe() { + @Test + public void concurrentSafe() { final List failures = new ArrayList<>(); - JsonAdapter.Factory factory = new JsonAdapter.Factory() { - int redAndGreenCount = 0; - - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, final Moshi moshi) { - if ((type == RedNode.class || type == GreenNode.class) && redAndGreenCount++ == 1) { - doInAnotherThread(new Runnable() { - @Override public void run() { - GreenNode greenBlue = new GreenNode(new BlueNode(null, null)); - assertThat(moshi.adapter(GreenNode.class).toJson(greenBlue)) - .isEqualTo("{\"blue\":{}}"); - - RedNode redBlue = new RedNode(new BlueNode(null, null)); - assertThat(moshi.adapter(RedNode.class).toJson(redBlue)) - .isEqualTo("{\"blue\":{}}"); + JsonAdapter.Factory factory = + new JsonAdapter.Factory() { + int redAndGreenCount = 0; + + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, final Moshi moshi) { + if ((type == RedNode.class || type == GreenNode.class) && redAndGreenCount++ == 1) { + doInAnotherThread( + new Runnable() { + @Override + public void run() { + GreenNode greenBlue = new GreenNode(new BlueNode(null, null)); + assertThat(moshi.adapter(GreenNode.class).toJson(greenBlue)) + .isEqualTo("{\"blue\":{}}"); + + RedNode redBlue = new RedNode(new BlueNode(null, null)); + assertThat(moshi.adapter(RedNode.class).toJson(redBlue)) + .isEqualTo("{\"blue\":{}}"); + } + }); } - }); - } - return null; - } - }; - - Moshi moshi = new Moshi.Builder() - .add(factory) - .build(); + return null; + } + }; + + Moshi moshi = new Moshi.Builder().add(factory).build(); JsonAdapter jsonAdapter = moshi.adapter(BlueNode.class); assertThat(jsonAdapter.toJson(new BlueNode(new GreenNode(new BlueNode(null, null)), null))) diff --git a/moshi/src/test/java/com/squareup/moshi/FlattenTest.java b/moshi/src/test/java/com/squareup/moshi/FlattenTest.java index d69e2fa75..2e3a1340d 100644 --- a/moshi/src/test/java/com/squareup/moshi/FlattenTest.java +++ b/moshi/src/test/java/com/squareup/moshi/FlattenTest.java @@ -15,6 +15,9 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.util.Arrays; import java.util.List; import org.junit.Test; @@ -23,9 +26,6 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - /** Note that this test makes heavy use of nested blocks, but these are for readability only. */ @RunWith(Parameterized.class) public final class FlattenTest { @@ -36,7 +36,8 @@ public static List parameters() { return JsonCodecFactory.factories(); } - @Test public void flattenExample() throws Exception { + @Test + public void flattenExample() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter> integersAdapter = moshi.adapter(Types.newParameterizedType(List.class, Integer.class)); @@ -53,7 +54,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[1,2,3,4,5]"); } - @Test public void flattenObject() throws Exception { + @Test + public void flattenObject() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); { @@ -76,7 +78,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":\"aaa\",\"b\":\"bbb\",\"c\":\"ccc\"}"); } - @Test public void flattenArray() throws Exception { + @Test + public void flattenArray() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -96,7 +99,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\"]"); } - @Test public void recursiveFlatten() throws Exception { + @Test + public void recursiveFlatten() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -126,7 +130,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\",\"d\",\"e\"]"); } - @Test public void flattenMultipleNested() throws Exception { + @Test + public void flattenMultipleNested() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -151,7 +156,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\",\"d\"]"); } - @Test public void flattenIsOnlyOneLevelDeep() throws Exception { + @Test + public void flattenIsOnlyOneLevelDeep() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -177,7 +183,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\",\"b\",[\"c\"],\"d\",\"e\"]"); } - @Test public void flattenOnlySomeChildren() throws Exception { + @Test + public void flattenOnlySomeChildren() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -202,7 +209,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\",\"b\",[\"c\"],\"d\"]"); } - @Test public void multipleCallsToFlattenSameNesting() throws Exception { + @Test + public void multipleCallsToFlattenSameNesting() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -236,7 +244,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\",\"d\",\"e\"]"); } - @Test public void deepFlatten() throws Exception { + @Test + public void deepFlatten() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { @@ -270,7 +279,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"a\"]"); } - @Test public void flattenTopLevel() { + @Test + public void flattenTopLevel() { JsonWriter writer = factory.newWriter(); try { writer.beginFlatten(); @@ -280,7 +290,8 @@ public static List parameters() { } } - @Test public void flattenDoesNotImpactOtherTypesInObjects() throws Exception { + @Test + public void flattenDoesNotImpactOtherTypesInObjects() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); { @@ -305,7 +316,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":[\"aaa\"],\"b\":\"bbb\",\"c\":[\"ccc\"]}"); } - @Test public void flattenDoesNotImpactOtherTypesInArrays() throws Exception { + @Test + public void flattenDoesNotImpactOtherTypesInArrays() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); { diff --git a/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java index 2fbfa6a20..8849186a4 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + import java.io.IOException; import java.util.Arrays; import java.util.Collections; @@ -28,10 +32,6 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeTrue; - @RunWith(Parameterized.class) public final class JsonAdapterTest { @Parameter public JsonCodecFactory factory; @@ -41,16 +41,20 @@ public static List parameters() { return JsonCodecFactory.factories(); } - @Test public void lenient() throws Exception { - JsonAdapter lenient = new JsonAdapter() { - @Override public Double fromJson(JsonReader reader) throws IOException { - return reader.nextDouble(); - } - - @Override public void toJson(JsonWriter writer, Double value) throws IOException { - writer.value(value); - } - }.lenient(); + @Test + public void lenient() throws Exception { + JsonAdapter lenient = + new JsonAdapter() { + @Override + public Double fromJson(JsonReader reader) throws IOException { + return reader.nextDouble(); + } + + @Override + public void toJson(JsonWriter writer, Double value) throws IOException { + writer.value(value); + } + }.lenient(); JsonReader reader = factory.newReader("[-Infinity, NaN, Infinity]"); reader.beginArray(); @@ -68,16 +72,20 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[-Infinity,NaN,Infinity]"); } - @Test public void nullSafe() throws Exception { - JsonAdapter toUpperCase = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - return reader.nextString().toUpperCase(Locale.US); - } - - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value(value.toUpperCase(Locale.US)); - } - }.nullSafe(); + @Test + public void nullSafe() throws Exception { + JsonAdapter toUpperCase = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + return reader.nextString().toUpperCase(Locale.US); + } + + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value(value.toUpperCase(Locale.US)); + } + }.nullSafe(); JsonReader reader = factory.newReader("[\"a\", null, \"c\"]"); reader.beginArray(); @@ -95,16 +103,20 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"A\",null,\"C\"]"); } - @Test public void nonNull() throws Exception { - JsonAdapter toUpperCase = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - return reader.nextString().toUpperCase(Locale.US); - } - - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value(value.toUpperCase(Locale.US)); - } - }.nonNull(); + @Test + public void nonNull() throws Exception { + JsonAdapter toUpperCase = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + return reader.nextString().toUpperCase(Locale.US); + } + + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value(value.toUpperCase(Locale.US)); + } + }.nonNull(); JsonReader reader = factory.newReader("[\"a\", null, \"c\"]"); reader.beginArray(); @@ -134,17 +146,21 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"A\",null,\"C\"]"); } - @Test public void failOnUnknown() throws Exception { - JsonAdapter alwaysSkip = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - reader.skipValue(); - throw new AssertionError(); - } - - @Override public void toJson(JsonWriter writer, String value) throws IOException { - throw new AssertionError(); - } - }.failOnUnknown(); + @Test + public void failOnUnknown() throws Exception { + JsonAdapter alwaysSkip = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + reader.skipValue(); + throw new AssertionError(); + } + + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + throw new AssertionError(); + } + }.failOnUnknown(); JsonReader reader = factory.newReader("[\"a\"]"); reader.beginArray(); @@ -158,43 +174,47 @@ public static List parameters() { reader.endArray(); } - @Test public void indent() throws Exception { + @Test + public void indent() throws Exception { assumeTrue(factory.encodesToBytes()); - JsonAdapter> indent = new JsonAdapter>() { - @Override public List fromJson(JsonReader reader) throws IOException { - throw new AssertionError(); - } - - @Override public void toJson(JsonWriter writer, List value) throws IOException { - writer.beginArray(); - for (String s : value) { - writer.value(s); - } - writer.endArray(); - } - }.indent("\t\t\t"); + JsonAdapter> indent = + new JsonAdapter>() { + @Override + public List fromJson(JsonReader reader) throws IOException { + throw new AssertionError(); + } + + @Override + public void toJson(JsonWriter writer, List value) throws IOException { + writer.beginArray(); + for (String s : value) { + writer.value(s); + } + writer.endArray(); + } + }.indent("\t\t\t"); JsonWriter writer = factory.newWriter(); indent.toJson(writer, Arrays.asList("a", "b", "c")); - assertThat(factory.json()).isEqualTo("" - + "[\n" - + "\t\t\t\"a\",\n" - + "\t\t\t\"b\",\n" - + "\t\t\t\"c\"\n" - + "]"); + assertThat(factory.json()) + .isEqualTo("" + "[\n" + "\t\t\t\"a\",\n" + "\t\t\t\"b\",\n" + "\t\t\t\"c\"\n" + "]"); } - @Test public void indentDisallowsNull() throws Exception { - JsonAdapter adapter = new JsonAdapter() { - @Override public Object fromJson(JsonReader reader) { - throw new AssertionError(); - } - - @Override public void toJson(JsonWriter writer, Object value) { - throw new AssertionError(); - } - }; + @Test + public void indentDisallowsNull() throws Exception { + JsonAdapter adapter = + new JsonAdapter() { + @Override + public Object fromJson(JsonReader reader) { + throw new AssertionError(); + } + + @Override + public void toJson(JsonWriter writer, Object value) { + throw new AssertionError(); + } + }; try { adapter.indent(null); fail(); @@ -203,36 +223,44 @@ public static List parameters() { } } - @Test public void serializeNulls() throws Exception { - JsonAdapter> serializeNulls = new JsonAdapter>() { - @Override public Map fromJson(JsonReader reader) throws IOException { - throw new AssertionError(); - } - - @Override public void toJson(JsonWriter writer, Map map) throws IOException { - writer.beginObject(); - for (Map.Entry entry : map.entrySet()) { - writer.name(entry.getKey()).value(entry.getValue()); - } - writer.endObject(); - } - }.serializeNulls(); + @Test + public void serializeNulls() throws Exception { + JsonAdapter> serializeNulls = + new JsonAdapter>() { + @Override + public Map fromJson(JsonReader reader) throws IOException { + throw new AssertionError(); + } + + @Override + public void toJson(JsonWriter writer, Map map) throws IOException { + writer.beginObject(); + for (Map.Entry entry : map.entrySet()) { + writer.name(entry.getKey()).value(entry.getValue()); + } + writer.endObject(); + } + }.serializeNulls(); JsonWriter writer = factory.newWriter(); serializeNulls.toJson(writer, Collections.singletonMap("a", null)); assertThat(factory.json()).isEqualTo("{\"a\":null}"); } - @Test public void stringDocumentMustBeFullyConsumed() throws IOException { - JsonAdapter brokenAdapter = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - return "Forgot to call reader.nextString()."; - } - - @Override public void toJson(JsonWriter writer, @Nullable String value) throws IOException { - throw new AssertionError(); - } - }; + @Test + public void stringDocumentMustBeFullyConsumed() throws IOException { + JsonAdapter brokenAdapter = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + return "Forgot to call reader.nextString()."; + } + + @Override + public void toJson(JsonWriter writer, @Nullable String value) throws IOException { + throw new AssertionError(); + } + }; try { brokenAdapter.fromJson("\"value\""); fail(); @@ -241,57 +269,71 @@ public static List parameters() { } } - @Test public void adapterFromJsonStringPeeksAtEnd() throws IOException { - JsonAdapter adapter = new JsonAdapter() { - @Override public Boolean fromJson(JsonReader reader) throws IOException { - return reader.nextBoolean(); - } - - @Override public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException { - throw new AssertionError(); - } - }; + @Test + public void adapterFromJsonStringPeeksAtEnd() throws IOException { + JsonAdapter adapter = + new JsonAdapter() { + @Override + public Boolean fromJson(JsonReader reader) throws IOException { + return reader.nextBoolean(); + } + + @Override + public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException { + throw new AssertionError(); + } + }; try { adapter.fromJson("true true"); fail(); } catch (JsonEncodingException e) { - assertThat(e).hasMessage( - "Use JsonReader.setLenient(true) to accept malformed JSON at path $"); + assertThat(e) + .hasMessage("Use JsonReader.setLenient(true) to accept malformed JSON at path $"); } } - @Test public void lenientAdapterFromJsonStringDoesNotPeekAtEnd() throws IOException { - JsonAdapter adapter = new JsonAdapter() { - @Override public Boolean fromJson(JsonReader reader) throws IOException { - return reader.nextBoolean(); - } - - @Override public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException { - throw new AssertionError(); - } - }.lenient(); + @Test + public void lenientAdapterFromJsonStringDoesNotPeekAtEnd() throws IOException { + JsonAdapter adapter = + new JsonAdapter() { + @Override + public Boolean fromJson(JsonReader reader) throws IOException { + return reader.nextBoolean(); + } + + @Override + public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException { + throw new AssertionError(); + } + }.lenient(); assertThat(adapter.fromJson("true true")).isEqualTo(true); } - @Test public void adaptersDelegateLeniency() throws IOException { - JsonAdapter adapter = new JsonAdapter() { - @Override public Boolean fromJson(JsonReader reader) throws IOException { - return reader.nextBoolean(); - } - - @Override public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException { - throw new AssertionError(); - } - }.lenient().serializeNulls(); + @Test + public void adaptersDelegateLeniency() throws IOException { + JsonAdapter adapter = + new JsonAdapter() { + @Override + public Boolean fromJson(JsonReader reader) throws IOException { + return reader.nextBoolean(); + } + + @Override + public void toJson(JsonWriter writer, @Nullable Boolean value) throws IOException { + throw new AssertionError(); + } + }.lenient().serializeNulls(); assertThat(adapter.fromJson("true true")).isEqualTo(true); } - @Test public void nullSafeDoesntDuplicate() { + @Test + public void nullSafeDoesntDuplicate() { JsonAdapter adapter = new Moshi.Builder().build().adapter(Boolean.class).nullSafe(); assertThat(adapter.nullSafe()).isSameAs(adapter); } - @Test public void nonNullDoesntDuplicate() { + @Test + public void nonNullDoesntDuplicate() { JsonAdapter adapter = new Moshi.Builder().build().adapter(Boolean.class).nonNull(); assertThat(adapter.nonNull()).isSameAs(adapter); } diff --git a/moshi/src/test/java/com/squareup/moshi/JsonCodecFactory.java b/moshi/src/test/java/com/squareup/moshi/JsonCodecFactory.java index a99974971..7ee139c1c 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonCodecFactory.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonCodecFactory.java @@ -25,109 +25,126 @@ abstract class JsonCodecFactory { private static final JsonAdapter OBJECT_ADAPTER = MOSHI.adapter(Object.class); static List factories() { - final JsonCodecFactory utf8 = new JsonCodecFactory() { - Buffer buffer; - - @Override public JsonReader newReader(String json) { - Buffer buffer = new Buffer().writeUtf8(json); - return JsonReader.of(buffer); - } - - @Override JsonWriter newWriter() { - buffer = new Buffer(); - return new JsonUtf8Writer(buffer); - } - - @Override String json() { - String result = buffer.readUtf8(); - buffer = null; - return result; - } - - @Override boolean encodesToBytes() { - return true; - } - - @Override public String toString() { - return "Utf8"; - } - }; - - final JsonCodecFactory value = new JsonCodecFactory() { - JsonValueWriter writer; - - @Override public JsonReader newReader(String json) throws IOException { - Moshi moshi = new Moshi.Builder().build(); - Object object = moshi.adapter(Object.class).lenient().fromJson(json); - return new JsonValueReader(object); - } - - // TODO(jwilson): fix precision checks and delete his method. - @Override boolean implementsStrictPrecision() { - return false; - } - - @Override JsonWriter newWriter() { - writer = new JsonValueWriter(); - return writer; - } - - @Override String json() { - // This writer writes a DOM. Use other Moshi features to serialize it as a string. - try { - Buffer buffer = new Buffer(); - JsonWriter bufferedSinkWriter = JsonWriter.of(buffer); - bufferedSinkWriter.setSerializeNulls(true); - bufferedSinkWriter.setLenient(true); - OBJECT_ADAPTER.toJson(bufferedSinkWriter, writer.root()); - return buffer.readUtf8(); - } catch (IOException e) { - throw new AssertionError(); - } - } - - // TODO(jwilson): support BigDecimal and BigInteger and delete his method. - @Override boolean supportsBigNumbers() { - return false; - } - - @Override public String toString() { - return "Value"; - } - }; - - final JsonCodecFactory valuePeek = new JsonCodecFactory() { - @Override public JsonReader newReader(String json) throws IOException { - return value.newReader(json).peekJson(); - } - - // TODO(jwilson): fix precision checks and delete his method. - @Override boolean implementsStrictPrecision() { - return false; - } - - @Override JsonWriter newWriter() { - return value.newWriter(); - } - - @Override String json() { - return value.json(); - } - - // TODO(jwilson): support BigDecimal and BigInteger and delete his method. - @Override boolean supportsBigNumbers() { - return false; - } - - @Override public String toString() { - return "ValuePeek"; - } - }; - - return Arrays.asList( - new Object[] { utf8 }, - new Object[] { value }, - new Object[] { valuePeek }); + final JsonCodecFactory utf8 = + new JsonCodecFactory() { + Buffer buffer; + + @Override + public JsonReader newReader(String json) { + Buffer buffer = new Buffer().writeUtf8(json); + return JsonReader.of(buffer); + } + + @Override + JsonWriter newWriter() { + buffer = new Buffer(); + return new JsonUtf8Writer(buffer); + } + + @Override + String json() { + String result = buffer.readUtf8(); + buffer = null; + return result; + } + + @Override + boolean encodesToBytes() { + return true; + } + + @Override + public String toString() { + return "Utf8"; + } + }; + + final JsonCodecFactory value = + new JsonCodecFactory() { + JsonValueWriter writer; + + @Override + public JsonReader newReader(String json) throws IOException { + Moshi moshi = new Moshi.Builder().build(); + Object object = moshi.adapter(Object.class).lenient().fromJson(json); + return new JsonValueReader(object); + } + + // TODO(jwilson): fix precision checks and delete his method. + @Override + boolean implementsStrictPrecision() { + return false; + } + + @Override + JsonWriter newWriter() { + writer = new JsonValueWriter(); + return writer; + } + + @Override + String json() { + // This writer writes a DOM. Use other Moshi features to serialize it as a string. + try { + Buffer buffer = new Buffer(); + JsonWriter bufferedSinkWriter = JsonWriter.of(buffer); + bufferedSinkWriter.setSerializeNulls(true); + bufferedSinkWriter.setLenient(true); + OBJECT_ADAPTER.toJson(bufferedSinkWriter, writer.root()); + return buffer.readUtf8(); + } catch (IOException e) { + throw new AssertionError(); + } + } + + // TODO(jwilson): support BigDecimal and BigInteger and delete his method. + @Override + boolean supportsBigNumbers() { + return false; + } + + @Override + public String toString() { + return "Value"; + } + }; + + final JsonCodecFactory valuePeek = + new JsonCodecFactory() { + @Override + public JsonReader newReader(String json) throws IOException { + return value.newReader(json).peekJson(); + } + + // TODO(jwilson): fix precision checks and delete his method. + @Override + boolean implementsStrictPrecision() { + return false; + } + + @Override + JsonWriter newWriter() { + return value.newWriter(); + } + + @Override + String json() { + return value.json(); + } + + // TODO(jwilson): support BigDecimal and BigInteger and delete his method. + @Override + boolean supportsBigNumbers() { + return false; + } + + @Override + public String toString() { + return "ValuePeek"; + } + }; + + return Arrays.asList(new Object[] {utf8}, new Object[] {value}, new Object[] {valuePeek}); } abstract JsonReader newReader(String json) throws IOException; diff --git a/moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java b/moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java index 2493328b0..1b0c2471c 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java @@ -15,20 +15,19 @@ */ package com.squareup.moshi; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.io.IOException; import java.lang.annotation.Retention; import java.util.Date; import org.junit.Test; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class JsonQualifiersTest { - @Test public void builtInTypes() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new BuiltInTypesJsonAdapter()) - .build(); + @Test + public void builtInTypes() throws Exception { + Moshi moshi = new Moshi.Builder().add(new BuiltInTypesJsonAdapter()).build(); JsonAdapter adapter = moshi.adapter(StringAndFooString.class); StringAndFooString v1 = new StringAndFooString(); @@ -42,20 +41,22 @@ public final class JsonQualifiersTest { } static class BuiltInTypesJsonAdapter { - @ToJson String fooPrefixStringToString(@FooPrefix String s) { + @ToJson + String fooPrefixStringToString(@FooPrefix String s) { return "foo" + s; } - @FromJson @FooPrefix String fooPrefixStringFromString(String s) throws Exception { + @FromJson + @FooPrefix + String fooPrefixStringFromString(String s) throws Exception { if (!s.startsWith("foo")) throw new JsonDataException(); return s.substring(3); } } - @Test public void readerWriterJsonAdapter() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new ReaderWriterJsonAdapter()) - .build(); + @Test + public void readerWriterJsonAdapter() throws Exception { + Moshi moshi = new Moshi.Builder().add(new ReaderWriterJsonAdapter()).build(); JsonAdapter adapter = moshi.adapter(StringAndFooString.class); StringAndFooString v1 = new StringAndFooString(); @@ -69,12 +70,14 @@ static class BuiltInTypesJsonAdapter { } static class ReaderWriterJsonAdapter { - @ToJson void fooPrefixStringToString(JsonWriter jsonWriter, @FooPrefix String s) - throws IOException { + @ToJson + void fooPrefixStringToString(JsonWriter jsonWriter, @FooPrefix String s) throws IOException { jsonWriter.value("foo" + s); } - @FromJson @FooPrefix String fooPrefixStringFromString(JsonReader reader) throws Exception { + @FromJson + @FooPrefix + String fooPrefixStringFromString(JsonReader reader) throws Exception { String s = reader.nextString(); if (!s.startsWith("foo")) throw new JsonDataException(); return s.substring(3); @@ -84,14 +87,12 @@ static class ReaderWriterJsonAdapter { /** Fields with this annotation get "foo" as a prefix in the JSON. */ @Retention(RUNTIME) @JsonQualifier - public @interface FooPrefix { - } + public @interface FooPrefix {} /** Fields with this annotation get "baz" as a suffix in the JSON. */ @Retention(RUNTIME) @JsonQualifier - public @interface BazSuffix { - } + public @interface BazSuffix {} static class StringAndFooString { String a; @@ -103,10 +104,10 @@ static class StringAndFooBazString { @FooPrefix @BazSuffix String b; } - @Test public void builtInTypesWithMultipleAnnotations() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new BuiltInTypesWithMultipleAnnotationsJsonAdapter()) - .build(); + @Test + public void builtInTypesWithMultipleAnnotations() throws Exception { + Moshi moshi = + new Moshi.Builder().add(new BuiltInTypesWithMultipleAnnotationsJsonAdapter()).build(); JsonAdapter adapter = moshi.adapter(StringAndFooBazString.class); StringAndFooBazString v1 = new StringAndFooBazString(); @@ -120,22 +121,25 @@ static class StringAndFooBazString { } static class BuiltInTypesWithMultipleAnnotationsJsonAdapter { - @ToJson String fooPrefixAndBazSuffixStringToString(@FooPrefix @BazSuffix String s) { + @ToJson + String fooPrefixAndBazSuffixStringToString(@FooPrefix @BazSuffix String s) { return "foo" + s + "baz"; } - @FromJson @FooPrefix @BazSuffix String fooPrefixAndBazSuffixStringFromString( - String s) throws Exception { + @FromJson + @FooPrefix + @BazSuffix + String fooPrefixAndBazSuffixStringFromString(String s) throws Exception { if (!s.startsWith("foo")) throw new JsonDataException(); if (!s.endsWith("baz")) throw new JsonDataException(); return s.substring(3, s.length() - 3); } } - @Test public void readerWriterWithMultipleAnnotations() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new ReaderWriterWithMultipleAnnotationsJsonAdapter()) - .build(); + @Test + public void readerWriterWithMultipleAnnotations() throws Exception { + Moshi moshi = + new Moshi.Builder().add(new ReaderWriterWithMultipleAnnotationsJsonAdapter()).build(); JsonAdapter adapter = moshi.adapter(StringAndFooBazString.class); StringAndFooBazString v1 = new StringAndFooBazString(); @@ -149,13 +153,16 @@ static class BuiltInTypesWithMultipleAnnotationsJsonAdapter { } static class ReaderWriterWithMultipleAnnotationsJsonAdapter { - @ToJson void fooPrefixAndBazSuffixStringToString( - JsonWriter jsonWriter, @FooPrefix @BazSuffix String s) throws IOException { + @ToJson + void fooPrefixAndBazSuffixStringToString(JsonWriter jsonWriter, @FooPrefix @BazSuffix String s) + throws IOException { jsonWriter.value("foo" + s + "baz"); } - @FromJson @FooPrefix @BazSuffix String fooPrefixAndBazSuffixStringFromString( - JsonReader reader) throws Exception { + @FromJson + @FooPrefix + @BazSuffix + String fooPrefixAndBazSuffixStringFromString(JsonReader reader) throws Exception { String s = reader.nextString(); if (!s.startsWith("foo")) throw new JsonDataException(); if (!s.endsWith("baz")) throw new JsonDataException(); @@ -163,11 +170,13 @@ static class ReaderWriterWithMultipleAnnotationsJsonAdapter { } } - @Test public void basicTypesAnnotationDelegating() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new BuiltInTypesDelegatingJsonAdapter()) - .add(new BuiltInTypesJsonAdapter()) - .build(); + @Test + public void basicTypesAnnotationDelegating() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new BuiltInTypesDelegatingJsonAdapter()) + .add(new BuiltInTypesJsonAdapter()) + .build(); JsonAdapter adapter = moshi.adapter(StringAndFooBazString.class); StringAndFooBazString v1 = new StringAndFooBazString(); @@ -181,22 +190,28 @@ static class ReaderWriterWithMultipleAnnotationsJsonAdapter { } static class BuiltInTypesDelegatingJsonAdapter { - @ToJson @FooPrefix String fooPrefixAndBazSuffixStringToString(@FooPrefix @BazSuffix String s) { + @ToJson + @FooPrefix + String fooPrefixAndBazSuffixStringToString(@FooPrefix @BazSuffix String s) { return s + "baz"; } - @FromJson @FooPrefix @BazSuffix String fooPrefixAndBazSuffixStringFromString( - @FooPrefix String s) throws Exception { + @FromJson + @FooPrefix + @BazSuffix + String fooPrefixAndBazSuffixStringFromString(@FooPrefix String s) throws Exception { if (!s.endsWith("baz")) throw new JsonDataException(); return s.substring(0, s.length() - 3); } } - @Test public void readerWriterAnnotationDelegating() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new BuiltInTypesDelegatingJsonAdapter()) - .add(new ReaderWriterJsonAdapter()) - .build(); + @Test + public void readerWriterAnnotationDelegating() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new BuiltInTypesDelegatingJsonAdapter()) + .add(new ReaderWriterJsonAdapter()) + .build(); JsonAdapter adapter = moshi.adapter(StringAndFooBazString.class); StringAndFooBazString v1 = new StringAndFooBazString(); @@ -209,22 +224,24 @@ static class BuiltInTypesDelegatingJsonAdapter { assertThat(v2.b).isEqualTo("bar"); } - @Test public void manualJsonAdapter() throws Exception { - JsonAdapter fooPrefixAdapter = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - String s = reader.nextString(); - if (!s.startsWith("foo")) throw new JsonDataException(); - return s.substring(3); - } - - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value("foo" + value); - } - }; - - Moshi moshi = new Moshi.Builder() - .add(String.class, FooPrefix.class, fooPrefixAdapter) - .build(); + @Test + public void manualJsonAdapter() throws Exception { + JsonAdapter fooPrefixAdapter = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + String s = reader.nextString(); + if (!s.startsWith("foo")) throw new JsonDataException(); + return s.substring(3); + } + + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value("foo" + value); + } + }; + + Moshi moshi = new Moshi.Builder().add(String.class, FooPrefix.class, fooPrefixAdapter).build(); JsonAdapter adapter = moshi.adapter(StringAndFooString.class); StringAndFooString v1 = new StringAndFooString(); @@ -237,7 +254,8 @@ static class BuiltInTypesDelegatingJsonAdapter { assertThat(v2.b).isEqualTo("bar"); } - @Test public void noJsonAdapterForAnnotatedType() throws Exception { + @Test + public void noJsonAdapterForAnnotatedType() throws Exception { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(StringAndFooString.class); @@ -246,10 +264,9 @@ static class BuiltInTypesDelegatingJsonAdapter { } } - @Test public void annotationWithoutJsonQualifierIsIgnoredByAdapterMethods() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new MissingJsonQualifierJsonAdapter()) - .build(); + @Test + public void annotationWithoutJsonQualifierIsIgnoredByAdapterMethods() throws Exception { + Moshi moshi = new Moshi.Builder().add(new MissingJsonQualifierJsonAdapter()).build(); JsonAdapter adapter = moshi.adapter(DateAndMillisDate.class); DateAndMillisDate v1 = new DateAndMillisDate(); @@ -264,46 +281,55 @@ static class BuiltInTypesDelegatingJsonAdapter { /** Despite the fact that these methods are annotated, they match all dates. */ static class MissingJsonQualifierJsonAdapter { - @ToJson long dateToJson(@Millis Date d) { + @ToJson + long dateToJson(@Millis Date d) { return d.getTime(); } - @FromJson @Millis Date jsonToDate(long value) throws Exception { + @FromJson + @Millis + Date jsonToDate(long value) throws Exception { return new Date(value); } } /** This annotation does nothing. */ @Retention(RUNTIME) - public @interface Millis { - } + public @interface Millis {} static class DateAndMillisDate { Date a; @Millis Date b; } - @Test public void annotationWithoutJsonQualifierIsRejectedOnRegistration() throws Exception { - JsonAdapter jsonAdapter = new JsonAdapter() { - @Override public Date fromJson(JsonReader reader) throws IOException { - throw new AssertionError(); - } - - @Override public void toJson(JsonWriter writer, Date value) throws IOException { - throw new AssertionError(); - } - }; + @Test + public void annotationWithoutJsonQualifierIsRejectedOnRegistration() throws Exception { + JsonAdapter jsonAdapter = + new JsonAdapter() { + @Override + public Date fromJson(JsonReader reader) throws IOException { + throw new AssertionError(); + } + + @Override + public void toJson(JsonWriter writer, Date value) throws IOException { + throw new AssertionError(); + } + }; try { new Moshi.Builder().add(Date.class, Millis.class, jsonAdapter); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("interface com.squareup.moshi.JsonQualifiersTest$Millis " - + "does not have @JsonQualifier"); + assertThat(expected) + .hasMessage( + "interface com.squareup.moshi.JsonQualifiersTest$Millis " + + "does not have @JsonQualifier"); } } - @Test public void annotationsConflict() throws Exception { + @Test + public void annotationsConflict() throws Exception { try { new Moshi.Builder().add(new AnnotationsConflictJsonAdapter()); fail(); @@ -313,69 +339,84 @@ static class DateAndMillisDate { } static class AnnotationsConflictJsonAdapter { - @ToJson String fooPrefixStringToString(@FooPrefix String s) { + @ToJson + String fooPrefixStringToString(@FooPrefix String s) { return "foo" + s; } - @ToJson String fooPrefixStringToString2(@FooPrefix String s) { + @ToJson + String fooPrefixStringToString2(@FooPrefix String s) { return "foo" + s; } } - @Test public void toButNoFromJson() throws Exception { + @Test + public void toButNoFromJson() throws Exception { // Building it is okay. - Moshi moshi = new Moshi.Builder() - .add(new ToButNoFromJsonAdapter()) - .build(); + Moshi moshi = new Moshi.Builder().add(new ToButNoFromJsonAdapter()).build(); try { moshi.adapter(StringAndFooString.class); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("No @FromJson adapter for class java.lang.String annotated " - + "[@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]" - + "\nfor class java.lang.String b" - + "\nfor class com.squareup.moshi.JsonQualifiersTest$StringAndFooString"); + assertThat(expected) + .hasMessage( + "No @FromJson adapter for class java.lang.String annotated " + + "[@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]" + + "\nfor class java.lang.String b" + + "\nfor class com.squareup.moshi.JsonQualifiersTest$StringAndFooString"); assertThat(expected).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(expected.getCause()).hasMessage("No @FromJson adapter for class java.lang.String " - + "annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); + assertThat(expected.getCause()) + .hasMessage( + "No @FromJson adapter for class java.lang.String " + + "annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); assertThat(expected.getCause()).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(expected.getCause().getCause()).hasMessage("No next JsonAdapter for class " - + "java.lang.String annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); + assertThat(expected.getCause().getCause()) + .hasMessage( + "No next JsonAdapter for class " + + "java.lang.String annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); } } static class ToButNoFromJsonAdapter { - @ToJson String fooPrefixStringToString(@FooPrefix String s) { + @ToJson + String fooPrefixStringToString(@FooPrefix String s) { return "foo" + s; } } - @Test public void fromButNoToJson() throws Exception { + @Test + public void fromButNoToJson() throws Exception { // Building it is okay. - Moshi moshi = new Moshi.Builder() - .add(new FromButNoToJsonAdapter()) - .build(); + Moshi moshi = new Moshi.Builder().add(new FromButNoToJsonAdapter()).build(); try { moshi.adapter(StringAndFooString.class); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("No @ToJson adapter for class java.lang.String annotated " - + "[@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]" - + "\nfor class java.lang.String b" - + "\nfor class com.squareup.moshi.JsonQualifiersTest$StringAndFooString"); + assertThat(expected) + .hasMessage( + "No @ToJson adapter for class java.lang.String annotated " + + "[@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]" + + "\nfor class java.lang.String b" + + "\nfor class com.squareup.moshi.JsonQualifiersTest$StringAndFooString"); assertThat(expected).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(expected.getCause()).hasMessage("No @ToJson adapter for class java.lang.String " - + "annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); + assertThat(expected.getCause()) + .hasMessage( + "No @ToJson adapter for class java.lang.String " + + "annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); assertThat(expected.getCause()).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(expected.getCause().getCause()).hasMessage("No next JsonAdapter for class " - + "java.lang.String annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); + assertThat(expected.getCause().getCause()) + .hasMessage( + "No next JsonAdapter for class " + + "java.lang.String annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]"); } } static class FromButNoToJsonAdapter { - @FromJson @FooPrefix String fooPrefixStringFromString(String s) throws Exception { + @FromJson + @FooPrefix + String fooPrefixStringFromString(String s) throws Exception { if (!s.startsWith("foo")) throw new JsonDataException(); return s.substring(3); } diff --git a/moshi/src/test/java/com/squareup/moshi/JsonReaderPathTest.java b/moshi/src/test/java/com/squareup/moshi/JsonReaderPathTest.java index 9950ccfcd..aa1c78886 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonReaderPathTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonReaderPathTest.java @@ -15,6 +15,9 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; + import java.io.IOException; import java.util.List; import org.junit.Test; @@ -23,9 +26,6 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assume.assumeTrue; - @RunWith(Parameterized.class) public final class JsonReaderPathTest { @Parameter public JsonCodecFactory factory; @@ -36,7 +36,8 @@ public static List parameters() { } @SuppressWarnings("CheckReturnValue") - @Test public void path() throws IOException { + @Test + public void path() throws IOException { JsonReader reader = factory.newReader("{\"a\":[2,true,false,null,\"b\",{\"c\":\"d\"},[3]]}"); assertThat(reader.getPath()).isEqualTo("$"); reader.beginObject(); @@ -75,7 +76,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void arrayOfObjects() throws IOException { + @Test + public void arrayOfObjects() throws IOException { JsonReader reader = factory.newReader("[{},{},{}]"); reader.beginArray(); assertThat(reader.getPath()).isEqualTo("$[0]"); @@ -95,7 +97,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void arrayOfArrays() throws IOException { + @Test + public void arrayOfArrays() throws IOException { JsonReader reader = factory.newReader("[[],[],[]]"); reader.beginArray(); assertThat(reader.getPath()).isEqualTo("$[0]"); @@ -116,7 +119,8 @@ public static List parameters() { } @SuppressWarnings("CheckReturnValue") - @Test public void objectPath() throws IOException { + @Test + public void objectPath() throws IOException { JsonReader reader = factory.newReader("{\"a\":1,\"b\":2}"); assertThat(reader.getPath()).isEqualTo("$"); @@ -157,7 +161,8 @@ public static List parameters() { } @SuppressWarnings("CheckReturnValue") - @Test public void arrayPath() throws IOException { + @Test + public void arrayPath() throws IOException { JsonReader reader = factory.newReader("[1,2]"); assertThat(reader.getPath()).isEqualTo("$"); @@ -187,7 +192,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void multipleTopLevelValuesInOneDocument() throws IOException { + @Test + public void multipleTopLevelValuesInOneDocument() throws IOException { assumeTrue(factory.encodesToBytes()); JsonReader reader = factory.newReader("[][]"); @@ -200,7 +206,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void skipArrayElements() throws IOException { + @Test + public void skipArrayElements() throws IOException { JsonReader reader = factory.newReader("[1,2,3]"); reader.beginArray(); reader.skipValue(); @@ -208,7 +215,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$[2]"); } - @Test public void skipObjectNames() throws IOException { + @Test + public void skipObjectNames() throws IOException { JsonReader reader = factory.newReader("{\"a\":1}"); reader.beginObject(); reader.skipValue(); @@ -216,7 +224,8 @@ public static List parameters() { } @SuppressWarnings("CheckReturnValue") - @Test public void skipObjectValues() throws IOException { + @Test + public void skipObjectValues() throws IOException { JsonReader reader = factory.newReader("{\"a\":1,\"b\":2}"); reader.beginObject(); reader.nextName(); @@ -226,7 +235,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$.b"); } - @Test public void skipNestedStructures() throws IOException { + @Test + public void skipNestedStructures() throws IOException { JsonReader reader = factory.newReader("[[1,2,3],4]"); reader.beginArray(); reader.skipValue(); diff --git a/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java index 3ed7dda46..5c360b260 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java @@ -15,17 +15,6 @@ */ package com.squareup.moshi; -import java.io.EOFException; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.junit.runners.Parameterized.Parameters; - import static com.squareup.moshi.JsonReader.Token.BEGIN_ARRAY; import static com.squareup.moshi.JsonReader.Token.BEGIN_OBJECT; import static com.squareup.moshi.JsonReader.Token.NAME; @@ -37,6 +26,17 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; +import java.io.EOFException; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + @RunWith(Parameterized.class) @SuppressWarnings("CheckReturnValue") public final class JsonReaderTest { @@ -51,7 +51,8 @@ JsonReader newReader(String json) throws IOException { return factory.newReader(json); } - @Test public void readArray() throws IOException { + @Test + public void readArray() throws IOException { JsonReader reader = newReader("[true, true]"); reader.beginArray(); assertThat(reader.nextBoolean()).isTrue(); @@ -60,7 +61,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void readEmptyArray() throws IOException { + @Test + public void readEmptyArray() throws IOException { JsonReader reader = newReader("[]"); reader.beginArray(); assertThat(reader.hasNext()).isFalse(); @@ -68,7 +70,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void readObject() throws IOException { + @Test + public void readObject() throws IOException { JsonReader reader = newReader("{\"a\": \"android\", \"b\": \"banana\"}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -79,7 +82,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void readEmptyObject() throws IOException { + @Test + public void readEmptyObject() throws IOException { JsonReader reader = newReader("{}"); reader.beginObject(); assertThat(reader.hasNext()).isFalse(); @@ -87,7 +91,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipArray() throws IOException { + @Test + public void skipArray() throws IOException { JsonReader reader = newReader("{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -98,7 +103,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipArrayAfterPeek() throws Exception { + @Test + public void skipArrayAfterPeek() throws Exception { JsonReader reader = newReader("{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -110,15 +116,17 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipTopLevelObject() throws Exception { + @Test + public void skipTopLevelObject() throws Exception { JsonReader reader = newReader("{\"a\": [\"one\", \"two\", \"three\"], \"b\": 123}"); reader.skipValue(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipObject() throws IOException { - JsonReader reader = newReader( - "{\"a\": { \"c\": [], \"d\": [true, true, {}] }, \"b\": \"banana\"}"); + @Test + public void skipObject() throws IOException { + JsonReader reader = + newReader("{\"a\": { \"c\": [], \"d\": [true, true, {}] }, \"b\": \"banana\"}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); reader.skipValue(); @@ -128,9 +136,14 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipObjectAfterPeek() throws Exception { - String json = "{" + " \"one\": { \"num\": 1 }" - + ", \"two\": { \"num\": 2 }" + ", \"three\": { \"num\": 3 }" + "}"; + @Test + public void skipObjectAfterPeek() throws Exception { + String json = + "{" + + " \"one\": { \"num\": 1 }" + + ", \"two\": { \"num\": 2 }" + + ", \"three\": { \"num\": 3 }" + + "}"; JsonReader reader = newReader(json); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("one"); @@ -145,7 +158,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipInteger() throws IOException { + @Test + public void skipInteger() throws IOException { JsonReader reader = newReader("{\"a\":123456789,\"b\":-123456789}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -156,7 +170,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipDouble() throws IOException { + @Test + public void skipDouble() throws IOException { JsonReader reader = newReader("{\"a\":-123.456e-789,\"b\":123456789.0}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -167,7 +182,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void failOnUnknownFailsOnUnknownObjectValue() throws IOException { + @Test + public void failOnUnknownFailsOnUnknownObjectValue() throws IOException { JsonReader reader = newReader("{\"a\": 123}"); reader.setFailOnUnknown(true); reader.beginObject(); @@ -185,7 +201,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void failOnUnknownFailsOnUnknownArrayElement() throws IOException { + @Test + public void failOnUnknownFailsOnUnknownArrayElement() throws IOException { JsonReader reader = newReader("[\"a\", 123]"); reader.setFailOnUnknown(true); reader.beginArray(); @@ -203,11 +220,9 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void helloWorld() throws IOException { - String json = "{\n" + - " \"hello\": true,\n" + - " \"foo\": [\"world\"]\n" + - "}"; + @Test + public void helloWorld() throws IOException { + String json = "{\n" + " \"hello\": true,\n" + " \"foo\": [\"world\"]\n" + "}"; JsonReader reader = newReader(json); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("hello"); @@ -220,7 +235,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void emptyString() throws Exception { + @Test + public void emptyString() throws Exception { try { newReader("").beginArray(); fail(); @@ -233,27 +249,29 @@ JsonReader newReader(String json) throws IOException { } } - @Test public void characterUnescaping() throws IOException { - String json = "[\"a\"," - + "\"a\\\"\"," - + "\"\\\"\"," - + "\":\"," - + "\",\"," - + "\"\\b\"," - + "\"\\f\"," - + "\"\\n\"," - + "\"\\r\"," - + "\"\\t\"," - + "\" \"," - + "\"\\\\\"," - + "\"{\"," - + "\"}\"," - + "\"[\"," - + "\"]\"," - + "\"\\u0000\"," - + "\"\\u0019\"," - + "\"\\u20AC\"" - + "]"; + @Test + public void characterUnescaping() throws IOException { + String json = + "[\"a\"," + + "\"a\\\"\"," + + "\"\\\"\"," + + "\":\"," + + "\",\"," + + "\"\\b\"," + + "\"\\f\"," + + "\"\\n\"," + + "\"\\r\"," + + "\"\\t\"," + + "\" \"," + + "\"\\\\\"," + + "\"{\"," + + "\"}\"," + + "\"[\"," + + "\"]\"," + + "\"\\u0000\"," + + "\"\\u0019\"," + + "\"\\u20AC\"" + + "]"; JsonReader reader = newReader(json); reader.beginArray(); assertThat(reader.nextString()).isEqualTo("a"); @@ -279,7 +297,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void integersWithFractionalPartSpecified() throws IOException { + @Test + public void integersWithFractionalPartSpecified() throws IOException { JsonReader reader = newReader("[1.0,1.0,1.0]"); reader.beginArray(); assertThat(reader.nextDouble()).isEqualTo(1.0); @@ -287,16 +306,18 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.nextLong()).isEqualTo(1L); } - @Test public void doubles() throws IOException { - String json = "[-0.0," - + "1.0," - + "1.7976931348623157E308," - + "4.9E-324," - + "0.0," - + "-0.5," - + "2.2250738585072014E-308," - + "3.141592653589793," - + "2.718281828459045]"; + @Test + public void doubles() throws IOException { + String json = + "[-0.0," + + "1.0," + + "1.7976931348623157E308," + + "4.9E-324," + + "0.0," + + "-0.5," + + "2.2250738585072014E-308," + + "3.141592653589793," + + "2.718281828459045]"; JsonReader reader = newReader(json); reader.beginArray(); assertThat(reader.nextDouble()).isEqualTo(-0.0); @@ -312,7 +333,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void strictNonFiniteDoubles() throws IOException { + @Test + public void strictNonFiniteDoubles() throws IOException { String json = "[NaN]"; JsonReader reader = newReader(json); reader.beginArray(); @@ -323,7 +345,8 @@ JsonReader newReader(String json) throws IOException { } } - @Test public void strictQuotedNonFiniteDoubles() throws IOException { + @Test + public void strictQuotedNonFiniteDoubles() throws IOException { String json = "[\"NaN\"]"; JsonReader reader = newReader(json); reader.beginArray(); @@ -335,7 +358,8 @@ JsonReader newReader(String json) throws IOException { } } - @Test public void lenientNonFiniteDoubles() throws IOException { + @Test + public void lenientNonFiniteDoubles() throws IOException { String json = "[NaN, -Infinity, Infinity]"; JsonReader reader = newReader(json); reader.setLenient(true); @@ -346,7 +370,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void lenientQuotedNonFiniteDoubles() throws IOException { + @Test + public void lenientQuotedNonFiniteDoubles() throws IOException { String json = "[\"NaN\", \"-Infinity\", \"Infinity\"]"; JsonReader reader = newReader(json); reader.setLenient(true); @@ -357,14 +382,12 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void longs() throws IOException { + @Test + public void longs() throws IOException { assumeTrue(factory.implementsStrictPrecision()); - String json = "[0,0,0," - + "1,1,1," - + "-1,-1,-1," - + "-9223372036854775808," - + "9223372036854775807]"; + String json = + "[0,0,0," + "1,1,1," + "-1,-1,-1," + "-9223372036854775808," + "9223372036854775807]"; JsonReader reader = newReader(json); reader.beginArray(); assertThat(reader.nextLong()).isEqualTo(0L); @@ -392,7 +415,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void booleans() throws IOException { + @Test + public void booleans() throws IOException { JsonReader reader = newReader("[true,false]"); reader.beginArray(); assertThat(reader.nextBoolean()).isTrue(); @@ -401,7 +425,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void nextFailuresDoNotAdvance() throws IOException { + @Test + public void nextFailuresDoNotAdvance() throws IOException { JsonReader reader = newReader("{\"a\":true}"); reader.beginObject(); try { @@ -461,7 +486,8 @@ JsonReader newReader(String json) throws IOException { reader.close(); } - @Test public void integerMismatchWithDoubleDoesNotAdvance() throws IOException { + @Test + public void integerMismatchWithDoubleDoesNotAdvance() throws IOException { assumeTrue(factory.implementsStrictPrecision()); JsonReader reader = newReader("[1.5]"); @@ -475,7 +501,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void integerMismatchWithLongDoesNotAdvance() throws IOException { + @Test + public void integerMismatchWithLongDoesNotAdvance() throws IOException { assumeTrue(factory.implementsStrictPrecision()); JsonReader reader = newReader("[9223372036854775807]"); @@ -489,7 +516,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void longMismatchWithDoubleDoesNotAdvance() throws IOException { + @Test + public void longMismatchWithDoubleDoesNotAdvance() throws IOException { assumeTrue(factory.implementsStrictPrecision()); JsonReader reader = newReader("[1.5]"); @@ -503,7 +531,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void stringNullIsNotNull() throws IOException { + @Test + public void stringNullIsNotNull() throws IOException { JsonReader reader = newReader("[\"null\"]"); reader.beginArray(); try { @@ -513,7 +542,8 @@ JsonReader newReader(String json) throws IOException { } } - @Test public void nullLiteralIsNotAString() throws IOException { + @Test + public void nullLiteralIsNotAString() throws IOException { JsonReader reader = newReader("[null]"); reader.beginArray(); try { @@ -523,7 +553,8 @@ JsonReader newReader(String json) throws IOException { } } - @Test public void topLevelValueTypes() throws IOException { + @Test + public void topLevelValueTypes() throws IOException { JsonReader reader1 = newReader("true"); assertThat(reader1.nextBoolean()).isTrue(); assertThat(reader1.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); @@ -549,26 +580,31 @@ JsonReader newReader(String json) throws IOException { assertThat(reader6.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void topLevelValueTypeWithSkipValue() throws IOException { + @Test + public void topLevelValueTypeWithSkipValue() throws IOException { JsonReader reader = newReader("true"); reader.skipValue(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void deeplyNestedArrays() throws IOException { + @Test + public void deeplyNestedArrays() throws IOException { JsonReader reader = newReader("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"); for (int i = 0; i < 31; i++) { reader.beginArray(); } - assertThat(reader.getPath()).isEqualTo("$[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]" - + "[0][0][0][0][0][0][0][0][0][0][0][0][0]"); + assertThat(reader.getPath()) + .isEqualTo( + "$[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]" + + "[0][0][0][0][0][0][0][0][0][0][0][0][0]"); for (int i = 0; i < 31; i++) { reader.endArray(); } assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void deeplyNestedObjects() throws IOException { + @Test + public void deeplyNestedObjects() throws IOException { // Build a JSON document structured like {"a":{"a":{"a":{"a":true}}}}, but 31 levels deep. String array = "{\"a\":%s}"; String json = "true"; @@ -590,7 +626,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipVeryLongUnquotedString() throws IOException { + @Test + public void skipVeryLongUnquotedString() throws IOException { JsonReader reader = newReader("[" + repeat('x', 8192) + "]"); reader.setLenient(true); reader.beginArray(); @@ -598,49 +635,56 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void skipTopLevelUnquotedString() throws IOException { + @Test + public void skipTopLevelUnquotedString() throws IOException { JsonReader reader = newReader(repeat('x', 8192)); reader.setLenient(true); reader.skipValue(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipVeryLongQuotedString() throws IOException { + @Test + public void skipVeryLongQuotedString() throws IOException { JsonReader reader = newReader("[\"" + repeat('x', 8192) + "\"]"); reader.beginArray(); reader.skipValue(); reader.endArray(); } - @Test public void skipTopLevelQuotedString() throws IOException { + @Test + public void skipTopLevelQuotedString() throws IOException { JsonReader reader = newReader("\"" + repeat('x', 8192) + "\""); reader.setLenient(true); reader.skipValue(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void stringAsNumberWithTruncatedExponent() throws IOException { + @Test + public void stringAsNumberWithTruncatedExponent() throws IOException { JsonReader reader = newReader("[123e]"); reader.setLenient(true); reader.beginArray(); assertThat(reader.peek()).isEqualTo(STRING); } - @Test public void stringAsNumberWithDigitAndNonDigitExponent() throws IOException { + @Test + public void stringAsNumberWithDigitAndNonDigitExponent() throws IOException { JsonReader reader = newReader("[123e4b]"); reader.setLenient(true); reader.beginArray(); assertThat(reader.peek()).isEqualTo(STRING); } - @Test public void stringAsNumberWithNonDigitExponent() throws IOException { + @Test + public void stringAsNumberWithNonDigitExponent() throws IOException { JsonReader reader = newReader("[123eb]"); reader.setLenient(true); reader.beginArray(); assertThat(reader.peek()).isEqualTo(STRING); } - @Test public void emptyStringName() throws IOException { + @Test + public void emptyStringName() throws IOException { JsonReader reader = newReader("{\"\":true}"); reader.setLenient(true); assertThat(reader.peek()).isEqualTo(BEGIN_OBJECT); @@ -654,13 +698,15 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void validEscapes() throws IOException { + @Test + public void validEscapes() throws IOException { JsonReader reader = newReader("[\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"]"); reader.beginArray(); assertThat(reader.nextString()).isEqualTo("\"\\/\b\f\n\r\t"); } - @Test public void selectName() throws IOException { + @Test + public void selectName() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); JsonReader reader = newReader("{\"a\": 5, \"b\": 5, \"c\": 5, \"d\": 5}"); @@ -696,7 +742,8 @@ JsonReader newReader(String json) throws IOException { } /** Select does match necessarily escaping. The decoded value is used in the path. */ - @Test public void selectNameNecessaryEscaping() throws IOException { + @Test + public void selectNameNecessaryEscaping() throws IOException { JsonReader.Options options = JsonReader.Options.of("\n", "\u0000", "\""); JsonReader reader = newReader("{\"\\n\": 5,\"\\u0000\": 5, \"\\\"\": 5}"); @@ -714,7 +761,8 @@ JsonReader newReader(String json) throws IOException { } /** Select removes unnecessary escaping from the source JSON. */ - @Test public void selectNameUnnecessaryEscaping() throws IOException { + @Test + public void selectNameUnnecessaryEscaping() throws IOException { JsonReader.Options options = JsonReader.Options.of("coffee", "tea"); JsonReader reader = newReader("{\"cof\\u0066ee\":5, \"\\u0074e\\u0061\":4, \"water\":3}"); @@ -737,7 +785,8 @@ JsonReader newReader(String json) throws IOException { reader.endObject(); } - @Test public void selectNameUnquoted() throws Exception { + @Test + public void selectNameUnquoted() throws Exception { JsonReader.Options options = JsonReader.Options.of("a", "b"); JsonReader reader = newReader("{a:2}"); @@ -752,7 +801,8 @@ JsonReader newReader(String json) throws IOException { reader.endObject(); } - @Test public void selectNameSingleQuoted() throws IOException { + @Test + public void selectNameSingleQuoted() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b"); JsonReader reader = newReader("{'a':5}"); @@ -767,7 +817,8 @@ JsonReader newReader(String json) throws IOException { reader.endObject(); } - @Test public void selectString() throws IOException { + @Test + public void selectString() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); JsonReader reader = newReader("[\"a\", \"b\", \"c\", \"d\"]"); @@ -794,7 +845,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void selectStringNecessaryEscaping() throws Exception { + @Test + public void selectStringNecessaryEscaping() throws Exception { JsonReader.Options options = JsonReader.Options.of("\n", "\u0000", "\""); JsonReader reader = newReader("[\"\\n\",\"\\u0000\", \"\\\"\"]"); @@ -806,7 +858,8 @@ JsonReader newReader(String json) throws IOException { } /** Select strips unnecessarily-escaped strings. */ - @Test public void selectStringUnnecessaryEscaping() throws IOException { + @Test + public void selectStringUnnecessaryEscaping() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); JsonReader reader = newReader("[\"\\u0061\", \"b\", \"\\u0063\"]"); @@ -817,7 +870,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void selectStringUnquoted() throws IOException { + @Test + public void selectStringUnquoted() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); JsonReader reader = newReader("[a, \"b\", c]"); @@ -829,7 +883,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void selectStringSingleQuoted() throws IOException { + @Test + public void selectStringSingleQuoted() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); JsonReader reader = newReader("['a', \"b\", c]"); @@ -841,7 +896,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void selectStringMaintainsReaderState() throws IOException { + @Test + public void selectStringMaintainsReaderState() throws IOException { JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); JsonReader reader = newReader("[\"\\u0061\", \"42\"]"); @@ -854,7 +910,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void selectStringWithoutString() throws IOException { + @Test + public void selectStringWithoutString() throws IOException { JsonReader.Options numbers = JsonReader.Options.of("1", "2.0", "true", "4"); JsonReader reader = newReader("[0, 2.0, true, \"4\"]"); @@ -869,7 +926,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void stringToNumberCoersion() throws Exception { + @Test + public void stringToNumberCoersion() throws Exception { JsonReader reader = newReader("[\"0\", \"9223372036854775807\", \"1.5\"]"); reader.beginArray(); assertThat(reader.nextInt()).isEqualTo(0); @@ -878,7 +936,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void unnecessaryPrecisionNumberCoersion() throws Exception { + @Test + public void unnecessaryPrecisionNumberCoersion() throws Exception { JsonReader reader = newReader("[\"0.0\", \"9223372036854775807.0\"]"); reader.beginArray(); assertThat(reader.nextInt()).isEqualTo(0); @@ -886,7 +945,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void nanInfinityDoubleCoersion() throws Exception { + @Test + public void nanInfinityDoubleCoersion() throws Exception { JsonReader reader = newReader("[\"NaN\", \"Infinity\", \"-Infinity\"]"); reader.beginArray(); reader.setLenient(true); @@ -896,7 +956,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void intMismatchWithStringDoesNotAdvance() throws Exception { + @Test + public void intMismatchWithStringDoesNotAdvance() throws Exception { JsonReader reader = newReader("[\"a\"]"); reader.beginArray(); try { @@ -908,7 +969,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void longMismatchWithStringDoesNotAdvance() throws Exception { + @Test + public void longMismatchWithStringDoesNotAdvance() throws Exception { JsonReader reader = newReader("[\"a\"]"); reader.beginArray(); try { @@ -920,7 +982,8 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void doubleMismatchWithStringDoesNotAdvance() throws Exception { + @Test + public void doubleMismatchWithStringDoesNotAdvance() throws Exception { JsonReader reader = newReader("[\"a\"]"); reader.beginArray(); try { @@ -932,38 +995,44 @@ JsonReader newReader(String json) throws IOException { reader.endArray(); } - @Test public void readJsonValueInt() throws IOException { + @Test + public void readJsonValueInt() throws IOException { JsonReader reader = newReader("1"); Object value = reader.readJsonValue(); assertThat(value).isEqualTo(1.0); } - @Test public void readJsonValueMap() throws IOException { + @Test + public void readJsonValueMap() throws IOException { JsonReader reader = newReader("{\"hello\": \"world\"}"); Object value = reader.readJsonValue(); assertThat(value).isEqualTo(Collections.singletonMap("hello", "world")); } - @Test public void readJsonValueList() throws IOException { + @Test + public void readJsonValueList() throws IOException { JsonReader reader = newReader("[\"a\", \"b\"]"); Object value = reader.readJsonValue(); assertThat(value).isEqualTo(Arrays.asList("a", "b")); } - @Test public void readJsonValueListMultipleTypes() throws IOException { + @Test + public void readJsonValueListMultipleTypes() throws IOException { JsonReader reader = newReader("[\"a\", 5, false]"); Object value = reader.readJsonValue(); assertThat(value).isEqualTo(Arrays.asList("a", 5.0, false)); } - @Test public void readJsonValueNestedListInMap() throws IOException { + @Test + public void readJsonValueNestedListInMap() throws IOException { JsonReader reader = newReader("{\"pizzas\": [\"cheese\", \"pepperoni\"]}"); Object value = reader.readJsonValue(); - assertThat(value).isEqualTo( - Collections.singletonMap("pizzas", Arrays.asList("cheese", "pepperoni"))); + assertThat(value) + .isEqualTo(Collections.singletonMap("pizzas", Arrays.asList("cheese", "pepperoni"))); } - @Test public void skipName() throws IOException { + @Test + public void skipName() throws IOException { JsonReader reader = newReader("{\"a\":1}"); reader.beginObject(); reader.skipName(); @@ -972,7 +1041,8 @@ JsonReader newReader(String json) throws IOException { reader.endObject(); } - @Test public void skipNameFailUnknown() throws IOException { + @Test + public void skipNameFailUnknown() throws IOException { JsonReader reader = newReader("{\"a\":1,\"b\":2}"); reader.setFailOnUnknown(true); reader.beginObject(); @@ -986,7 +1056,8 @@ JsonReader newReader(String json) throws IOException { } } - @Test public void skipNameOnValueFails() throws IOException { + @Test + public void skipNameOnValueFails() throws IOException { JsonReader reader = newReader("1"); try { reader.skipName(); @@ -996,13 +1067,15 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.nextInt()).isEqualTo(1); } - @Test public void emptyDocumentHasNextReturnsFalse() throws IOException { + @Test + public void emptyDocumentHasNextReturnsFalse() throws IOException { JsonReader reader = newReader("1"); reader.readJsonValue(); assertThat(reader.hasNext()).isFalse(); } - @Test public void skipValueAtEndOfObjectFails() throws IOException { + @Test + public void skipValueAtEndOfObjectFails() throws IOException { JsonReader reader = newReader("{}"); reader.beginObject(); try { @@ -1015,7 +1088,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipValueAtEndOfArrayFails() throws IOException { + @Test + public void skipValueAtEndOfArrayFails() throws IOException { JsonReader reader = newReader("[]"); reader.beginArray(); try { @@ -1028,7 +1102,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipValueAtEndOfDocumentFails() throws IOException { + @Test + public void skipValueAtEndOfDocumentFails() throws IOException { JsonReader reader = newReader("1"); reader.nextInt(); try { @@ -1040,7 +1115,8 @@ JsonReader newReader(String json) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void basicPeekJson() throws IOException { + @Test + public void basicPeekJson() throws IOException { JsonReader reader = newReader("{\"a\":12,\"b\":[34,56],\"c\":78}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -1072,7 +1148,8 @@ JsonReader newReader(String json) throws IOException { * reader. Before each of the real reader’s operations we create a peeking reader and let it read * the rest of the document. */ - @Test public void peekJsonReader() throws IOException { + @Test + public void peekJsonReader() throws IOException { JsonReader reader = newReader("[12,34,{\"a\":56,\"b\":78},90]"); for (int i = 0; i < 12; i++) { readPeek12Steps(reader.peekJson(), i, 12); @@ -1138,15 +1215,17 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx } /** Confirm that we can peek in every state of the UTF-8 reader. */ - @Test public void peekAfterPeek() throws IOException { - JsonReader reader = newReader( - "[{\"a\":\"aaa\",'b':'bbb',c:c,\"d\":\"d\"},true,false,null,1,2.0]"); + @Test + public void peekAfterPeek() throws IOException { + JsonReader reader = + newReader("[{\"a\":\"aaa\",'b':'bbb',c:c,\"d\":\"d\"},true,false,null,1,2.0]"); reader.setLenient(true); readValue(reader, true); reader.peekJson(); } - @Test public void peekAfterPromoteNameToValue() throws IOException { + @Test + public void peekAfterPromoteNameToValue() throws IOException { JsonReader reader = newReader("{\"a\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1157,7 +1236,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx reader.endObject(); } - @Test public void promoteStringNameToValue() throws IOException { + @Test + public void promoteStringNameToValue() throws IOException { JsonReader reader = newReader("{\"a\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1166,7 +1246,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx reader.endObject(); } - @Test public void promoteDoubleNameToValue() throws IOException { + @Test + public void promoteDoubleNameToValue() throws IOException { JsonReader reader = newReader("{\"5\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1175,7 +1256,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx reader.endObject(); } - @Test public void promoteLongNameToValue() throws IOException { + @Test + public void promoteLongNameToValue() throws IOException { JsonReader reader = newReader("{\"5\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1184,7 +1266,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx reader.endObject(); } - @Test public void promoteNullNameToValue() throws IOException { + @Test + public void promoteNullNameToValue() throws IOException { JsonReader reader = newReader("{\"null\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1196,7 +1279,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx assertEquals("null", reader.nextString()); } - @Test public void promoteBooleanNameToValue() throws IOException { + @Test + public void promoteBooleanNameToValue() throws IOException { JsonReader reader = newReader("{\"true\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1208,7 +1292,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx assertEquals("true", reader.nextString()); } - @Test public void promoteBooleanNameToValueCannotBeReadAsName() throws IOException { + @Test + public void promoteBooleanNameToValueCannotBeReadAsName() throws IOException { JsonReader reader = newReader("{\"true\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1220,7 +1305,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx assertEquals("true", reader.nextString()); } - @Test public void promoteSkippedNameToValue() throws IOException { + @Test + public void promoteSkippedNameToValue() throws IOException { JsonReader reader = newReader("{\"true\":\"b\"}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1228,7 +1314,8 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx assertEquals("b", reader.nextString()); } - @Test public void promoteNameToValueAtEndOfObject() throws IOException { + @Test + public void promoteNameToValueAtEndOfObject() throws IOException { JsonReader reader = newReader("{}"); reader.beginObject(); reader.promoteNameToValue(); @@ -1236,8 +1323,9 @@ private void readPeek12Steps(JsonReader reader, int from, int until) throws IOEx reader.endObject(); } - @Test public void optionsStrings() { - String[] options = new String[] { "a", "b", "c" }; + @Test + public void optionsStrings() { + String[] options = new String[] {"a", "b", "c"}; JsonReader.Options abc = JsonReader.Options.of("a", "b", "c"); List strings = abc.strings(); assertThat(options).containsExactlyElementsOf(strings); diff --git a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java index 7652b1c79..3f1c8d48a 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java @@ -15,15 +15,6 @@ */ package com.squareup.moshi; -import java.io.EOFException; -import java.io.IOException; -import java.util.Arrays; -import okio.Buffer; -import okio.ForwardingSource; -import okio.Okio; -import org.junit.Ignore; -import org.junit.Test; - import static com.squareup.moshi.JsonReader.Token.BEGIN_ARRAY; import static com.squareup.moshi.JsonReader.Token.BEGIN_OBJECT; import static com.squareup.moshi.JsonReader.Token.BOOLEAN; @@ -40,8 +31,18 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import java.io.EOFException; +import java.io.IOException; +import java.util.Arrays; +import okio.Buffer; +import okio.ForwardingSource; +import okio.Okio; +import org.junit.Ignore; +import org.junit.Test; + public final class JsonUtf8ReaderTest { - @Test public void readingDoesNotBuffer() throws IOException { + @Test + public void readingDoesNotBuffer() throws IOException { Buffer buffer = new Buffer().writeUtf8("{}{}"); JsonReader reader1 = JsonReader.of(buffer); @@ -55,7 +56,8 @@ public final class JsonUtf8ReaderTest { assertThat(buffer.size()).isEqualTo(0); } - @Test public void readObjectBuffer() throws IOException { + @Test + public void readObjectBuffer() throws IOException { Buffer buffer = new Buffer().writeUtf8("{\"a\": \"android\", \"b\": \"banana\"}"); JsonReader reader = JsonReader.of(buffer); reader.beginObject(); @@ -67,7 +69,8 @@ public final class JsonUtf8ReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void readObjectSource() throws IOException { + @Test + public void readObjectSource() throws IOException { Buffer buffer = new Buffer().writeUtf8("{\"a\": \"android\", \"b\": \"banana\"}"); JsonReader reader = JsonReader.of(Okio.buffer(new ForwardingSource(buffer) {})); reader.beginObject(); @@ -79,7 +82,8 @@ public final class JsonUtf8ReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void nullSource() { + @Test + public void nullSource() { try { JsonReader.of(null); fail(); @@ -87,7 +91,8 @@ public final class JsonUtf8ReaderTest { } } - @Test public void unescapingInvalidCharacters() throws IOException { + @Test + public void unescapingInvalidCharacters() throws IOException { String json = "[\"\\u000g\"]"; JsonReader reader = newReader(json); reader.beginArray(); @@ -98,7 +103,8 @@ public final class JsonUtf8ReaderTest { } } - @Test public void unescapingTruncatedCharacters() throws IOException { + @Test + public void unescapingTruncatedCharacters() throws IOException { String json = "[\"\\u000"; JsonReader reader = newReader(json); reader.beginArray(); @@ -109,7 +115,8 @@ public final class JsonUtf8ReaderTest { } } - @Test public void unescapingTruncatedSequence() throws IOException { + @Test + public void unescapingTruncatedSequence() throws IOException { String json = "[\"\\"; JsonReader reader = newReader(json); reader.beginArray(); @@ -120,7 +127,8 @@ public final class JsonUtf8ReaderTest { } } - @Test public void strictNonFiniteDoublesWithSkipValue() throws IOException { + @Test + public void strictNonFiniteDoublesWithSkipValue() throws IOException { String json = "[NaN]"; JsonReader reader = newReader(json); reader.beginArray(); @@ -131,7 +139,9 @@ public final class JsonUtf8ReaderTest { } } - @Test @Ignore public void numberWithOctalPrefix() throws IOException { + @Test + @Ignore + public void numberWithOctalPrefix() throws IOException { String json = "[01]"; JsonReader reader = newReader(json); reader.beginArray(); @@ -160,7 +170,8 @@ public final class JsonUtf8ReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void peekingUnquotedStringsPrefixedWithBooleans() throws IOException { + @Test + public void peekingUnquotedStringsPrefixedWithBooleans() throws IOException { JsonReader reader = newReader("[truey]"); reader.setLenient(true); reader.beginArray(); @@ -174,7 +185,8 @@ public final class JsonUtf8ReaderTest { reader.endArray(); } - @Test public void malformedNumbers() throws IOException { + @Test + public void malformedNumbers() throws IOException { assertNotANumber("-"); assertNotANumber("."); @@ -220,7 +232,8 @@ private void assertNotANumber(String s) throws IOException { reader.endArray(); } - @Test public void peekingUnquotedStringsPrefixedWithIntegers() throws IOException { + @Test + public void peekingUnquotedStringsPrefixedWithIntegers() throws IOException { JsonReader reader = newReader("[12.34e5x]"); reader.setLenient(true); reader.beginArray(); @@ -233,7 +246,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextString()).isEqualTo("12.34e5x"); } - @Test public void peekLongMinValue() throws IOException { + @Test + public void peekLongMinValue() throws IOException { JsonReader reader = newReader("[-9223372036854775808]"); reader.setLenient(true); reader.beginArray(); @@ -241,7 +255,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextLong()).isEqualTo(-9223372036854775808L); } - @Test public void peekLongMaxValue() throws IOException { + @Test + public void peekLongMaxValue() throws IOException { JsonReader reader = newReader("[9223372036854775807]"); reader.setLenient(true); reader.beginArray(); @@ -249,7 +264,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextLong()).isEqualTo(9223372036854775807L); } - @Test public void longLargerThanMaxLongThatWrapsAround() throws IOException { + @Test + public void longLargerThanMaxLongThatWrapsAround() throws IOException { JsonReader reader = newReader("[22233720368547758070]"); reader.setLenient(true); reader.beginArray(); @@ -261,7 +277,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void longLargerThanMinLongThatWrapsAround() throws IOException { + @Test + public void longLargerThanMinLongThatWrapsAround() throws IOException { JsonReader reader = newReader("[-22233720368547758070]"); reader.setLenient(true); reader.beginArray(); @@ -273,7 +290,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void peekLargerThanLongMaxValue() throws IOException { + @Test + public void peekLargerThanLongMaxValue() throws IOException { JsonReader reader = newReader("[9223372036854775808]"); reader.setLenient(true); reader.beginArray(); @@ -285,7 +303,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void precisionNotDiscarded() throws IOException { + @Test + public void precisionNotDiscarded() throws IOException { JsonReader reader = newReader("[9223372036854775806.5]"); reader.setLenient(true); reader.beginArray(); @@ -297,7 +316,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void peekLargerThanLongMinValue() throws IOException { + @Test + public void peekLargerThanLongMinValue() throws IOException { JsonReader reader = newReader("[-9223372036854775809]"); reader.setLenient(true); reader.beginArray(); @@ -310,7 +330,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextDouble()).isEqualTo(-9223372036854775809d); } - @Test public void highPrecisionLong() throws IOException { + @Test + public void highPrecisionLong() throws IOException { String json = "[9223372036854775806.000]"; JsonReader reader = newReader(json); reader.beginArray(); @@ -318,7 +339,8 @@ private void assertNotANumber(String s) throws IOException { reader.endArray(); } - @Test public void peekMuchLargerThanLongMinValue() throws IOException { + @Test + public void peekMuchLargerThanLongMinValue() throws IOException { JsonReader reader = newReader("[-92233720368547758080]"); reader.setLenient(true); reader.beginArray(); @@ -331,13 +353,15 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextDouble()).isEqualTo(-92233720368547758080d); } - @Test public void negativeZeroIsANumber() throws Exception { + @Test + public void negativeZeroIsANumber() throws Exception { JsonReader reader = newReader("-0"); assertEquals(NUMBER, reader.peek()); assertEquals("-0", reader.nextString()); } - @Test public void numberToStringCoersion() throws Exception { + @Test + public void numberToStringCoersion() throws Exception { JsonReader reader = newReader("[0, 9223372036854775807, 2.5, 3.010, \"a\", \"5\"]"); reader.beginArray(); assertThat(reader.nextString()).isEqualTo("0"); @@ -349,7 +373,8 @@ private void assertNotANumber(String s) throws IOException { reader.endArray(); } - @Test public void quotedNumberWithEscape() throws IOException { + @Test + public void quotedNumberWithEscape() throws IOException { JsonReader reader = newReader("[\"12\u00334\"]"); reader.setLenient(true); reader.beginArray(); @@ -357,7 +382,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextInt()).isEqualTo(1234); } - @Test public void mixedCaseLiterals() throws IOException { + @Test + public void mixedCaseLiterals() throws IOException { JsonReader reader = newReader("[True,TruE,False,FALSE,NULL,nulL]"); reader.beginArray(); assertThat(reader.nextBoolean()).isTrue(); @@ -370,7 +396,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void missingValue() throws IOException { + @Test + public void missingValue() throws IOException { JsonReader reader = newReader("{\"a\":}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -381,7 +408,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void prematureEndOfInput() throws IOException { + @Test + public void prematureEndOfInput() throws IOException { JsonReader reader = newReader("{\"a\":true,"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -394,7 +422,8 @@ private void assertNotANumber(String s) throws IOException { } @SuppressWarnings("CheckReturnValue") - @Test public void prematurelyClosed() throws IOException { + @Test + public void prematurelyClosed() throws IOException { try { JsonReader reader = newReader("{\"a\":[]}"); reader.beginObject(); @@ -424,7 +453,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictNameValueSeparator() throws IOException { + @Test + public void strictNameValueSeparator() throws IOException { JsonReader reader = newReader("{\"a\"=true}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -444,7 +474,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientNameValueSeparator() throws IOException { + @Test + public void lenientNameValueSeparator() throws IOException { JsonReader reader = newReader("{\"a\"=true}"); reader.setLenient(true); reader.beginObject(); @@ -458,7 +489,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextBoolean()).isTrue(); } - @Test public void strictNameValueSeparatorWithSkipValue() throws IOException { + @Test + public void strictNameValueSeparatorWithSkipValue() throws IOException { JsonReader reader = newReader("{\"a\"=true}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -478,7 +510,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void commentsInStringValue() throws Exception { + @Test + public void commentsInStringValue() throws Exception { JsonReader reader = newReader("[\"// comment\"]"); reader.beginArray(); assertThat(reader.nextString()).isEqualTo("// comment"); @@ -497,7 +530,8 @@ private void assertNotANumber(String s) throws IOException { reader.endObject(); } - @Test public void strictComments() throws IOException { + @Test + public void strictComments() throws IOException { JsonReader reader = newReader("[// comment \n true]"); reader.beginArray(); try { @@ -523,7 +557,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientComments() throws IOException { + @Test + public void lenientComments() throws IOException { JsonReader reader = newReader("[// comment \n true]"); reader.setLenient(true); reader.beginArray(); @@ -545,7 +580,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void strictCommentsWithSkipValue() throws IOException { + @Test + public void strictCommentsWithSkipValue() throws IOException { JsonReader reader = newReader("[// comment \n true]"); reader.beginArray(); try { @@ -571,7 +607,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictUnquotedNames() throws IOException { + @Test + public void strictUnquotedNames() throws IOException { JsonReader reader = newReader("{a:true}"); reader.beginObject(); try { @@ -581,21 +618,24 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientUnquotedNames() throws IOException { + @Test + public void lenientUnquotedNames() throws IOException { JsonReader reader = newReader("{a:true}"); reader.setLenient(true); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); } - @Test public void jsonIsSingleUnquotedString() throws IOException { + @Test + public void jsonIsSingleUnquotedString() throws IOException { JsonReader reader = newReader("abc"); reader.setLenient(true); assertThat(reader.nextString()).isEqualTo("abc"); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void strictUnquotedNamesWithSkipValue() throws IOException { + @Test + public void strictUnquotedNamesWithSkipValue() throws IOException { JsonReader reader = newReader("{a:true}"); reader.beginObject(); try { @@ -605,7 +645,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictSingleQuotedNames() throws IOException { + @Test + public void strictSingleQuotedNames() throws IOException { JsonReader reader = newReader("{'a':true}"); reader.beginObject(); try { @@ -615,14 +656,16 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientSingleQuotedNames() throws IOException { + @Test + public void lenientSingleQuotedNames() throws IOException { JsonReader reader = newReader("{'a':true}"); reader.setLenient(true); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); } - @Test public void strictSingleQuotedNamesWithSkipValue() throws IOException { + @Test + public void strictSingleQuotedNamesWithSkipValue() throws IOException { JsonReader reader = newReader("{'a':true}"); reader.beginObject(); try { @@ -632,7 +675,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictUnquotedStrings() throws IOException { + @Test + public void strictUnquotedStrings() throws IOException { JsonReader reader = newReader("[a]"); reader.beginArray(); try { @@ -642,7 +686,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictUnquotedStringsWithSkipValue() throws IOException { + @Test + public void strictUnquotedStringsWithSkipValue() throws IOException { JsonReader reader = newReader("[a]"); reader.beginArray(); try { @@ -652,14 +697,16 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientUnquotedStrings() throws IOException { + @Test + public void lenientUnquotedStrings() throws IOException { JsonReader reader = newReader("[a]"); reader.setLenient(true); reader.beginArray(); assertThat(reader.nextString()).isEqualTo("a"); } - @Test public void lenientUnquotedStringsDelimitedByComment() throws IOException { + @Test + public void lenientUnquotedStringsDelimitedByComment() throws IOException { JsonReader reader = newReader("[a#comment\n]"); reader.setLenient(true); reader.beginArray(); @@ -667,7 +714,8 @@ private void assertNotANumber(String s) throws IOException { reader.endArray(); } - @Test public void strictSingleQuotedStrings() throws IOException { + @Test + public void strictSingleQuotedStrings() throws IOException { JsonReader reader = newReader("['a']"); reader.beginArray(); try { @@ -677,14 +725,16 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientSingleQuotedStrings() throws IOException { + @Test + public void lenientSingleQuotedStrings() throws IOException { JsonReader reader = newReader("['a']"); reader.setLenient(true); reader.beginArray(); assertThat(reader.nextString()).isEqualTo("a"); } - @Test public void strictSingleQuotedStringsWithSkipValue() throws IOException { + @Test + public void strictSingleQuotedStringsWithSkipValue() throws IOException { JsonReader reader = newReader("['a']"); reader.beginArray(); try { @@ -694,7 +744,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictSemicolonDelimitedArray() throws IOException { + @Test + public void strictSemicolonDelimitedArray() throws IOException { JsonReader reader = newReader("[true;true]"); reader.beginArray(); try { @@ -705,7 +756,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientSemicolonDelimitedArray() throws IOException { + @Test + public void lenientSemicolonDelimitedArray() throws IOException { JsonReader reader = newReader("[true;true]"); reader.setLenient(true); reader.beginArray(); @@ -713,7 +765,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextBoolean()).isTrue(); } - @Test public void strictSemicolonDelimitedArrayWithSkipValue() throws IOException { + @Test + public void strictSemicolonDelimitedArrayWithSkipValue() throws IOException { JsonReader reader = newReader("[true;true]"); reader.beginArray(); try { @@ -724,7 +777,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictSemicolonDelimitedNameValuePair() throws IOException { + @Test + public void strictSemicolonDelimitedNameValuePair() throws IOException { JsonReader reader = newReader("{\"a\":true;\"b\":true}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -736,7 +790,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientSemicolonDelimitedNameValuePair() throws IOException { + @Test + public void lenientSemicolonDelimitedNameValuePair() throws IOException { JsonReader reader = newReader("{\"a\":true;\"b\":true}"); reader.setLenient(true); reader.beginObject(); @@ -745,7 +800,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.nextName()).isEqualTo("b"); } - @Test public void strictSemicolonDelimitedNameValuePairWithSkipValue() throws IOException { + @Test + public void strictSemicolonDelimitedNameValuePairWithSkipValue() throws IOException { JsonReader reader = newReader("{\"a\":true;\"b\":true}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -757,7 +813,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictUnnecessaryArraySeparators() throws IOException { + @Test + public void strictUnnecessaryArraySeparators() throws IOException { JsonReader reader = newReader("[true,,true]"); reader.beginArray(); assertThat(reader.nextBoolean()).isTrue(); @@ -793,7 +850,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientUnnecessaryArraySeparators() throws IOException { + @Test + public void lenientUnnecessaryArraySeparators() throws IOException { JsonReader reader = newReader("[true,,true]"); reader.setLenient(true); reader.beginArray(); @@ -824,7 +882,8 @@ private void assertNotANumber(String s) throws IOException { reader.endArray(); } - @Test public void strictUnnecessaryArraySeparatorsWithSkipValue() throws IOException { + @Test + public void strictUnnecessaryArraySeparatorsWithSkipValue() throws IOException { JsonReader reader = newReader("[true,,true]"); reader.beginArray(); assertThat(reader.nextBoolean()).isTrue(); @@ -860,7 +919,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void strictMultipleTopLevelValues() throws IOException { + @Test + public void strictMultipleTopLevelValues() throws IOException { JsonReader reader = newReader("[] []"); reader.beginArray(); reader.endArray(); @@ -871,7 +931,8 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void lenientMultipleTopLevelValues() throws IOException { + @Test + public void lenientMultipleTopLevelValues() throws IOException { JsonReader reader = newReader("[] true {}"); reader.setLenient(true); reader.beginArray(); @@ -882,7 +943,8 @@ private void assertNotANumber(String s) throws IOException { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void strictMultipleTopLevelValuesWithSkipValue() throws IOException { + @Test + public void strictMultipleTopLevelValuesWithSkipValue() throws IOException { JsonReader reader = newReader("[] []"); reader.beginArray(); reader.endArray(); @@ -893,13 +955,16 @@ private void assertNotANumber(String s) throws IOException { } } - @Test @Ignore public void bomIgnoredAsFirstCharacterOfDocument() throws IOException { + @Test + @Ignore + public void bomIgnoredAsFirstCharacterOfDocument() throws IOException { JsonReader reader = newReader("\ufeff[]"); reader.beginArray(); reader.endArray(); } - @Test public void bomForbiddenAsOtherCharacterInDocument() throws IOException { + @Test + public void bomForbiddenAsOtherCharacterInDocument() throws IOException { JsonReader reader = newReader("[\ufeff]"); reader.beginArray(); try { @@ -909,46 +974,50 @@ private void assertNotANumber(String s) throws IOException { } } - @Test public void failWithPosition() throws IOException { - testFailWithPosition("Expected value at path $[1]", - "[\n\n\n\n\n\"a\",}]"); + @Test + public void failWithPosition() throws IOException { + testFailWithPosition("Expected value at path $[1]", "[\n\n\n\n\n\"a\",}]"); } - @Test public void failWithPositionGreaterThanBufferSize() throws IOException { + @Test + public void failWithPositionGreaterThanBufferSize() throws IOException { String spaces = repeat(' ', 8192); - testFailWithPosition("Expected value at path $[1]", - "[\n\n" + spaces + "\n\n\n\"a\",}]"); + testFailWithPosition("Expected value at path $[1]", "[\n\n" + spaces + "\n\n\n\"a\",}]"); } - @Test public void failWithPositionOverSlashSlashEndOfLineComment() throws IOException { - testFailWithPosition("Expected value at path $[1]", - "\n// foo\n\n//bar\r\n[\"a\",}"); + @Test + public void failWithPositionOverSlashSlashEndOfLineComment() throws IOException { + testFailWithPosition("Expected value at path $[1]", "\n// foo\n\n//bar\r\n[\"a\",}"); } - @Test public void failWithPositionOverHashEndOfLineComment() throws IOException { - testFailWithPosition("Expected value at path $[1]", - "\n# foo\n\n#bar\r\n[\"a\",}"); + @Test + public void failWithPositionOverHashEndOfLineComment() throws IOException { + testFailWithPosition("Expected value at path $[1]", "\n# foo\n\n#bar\r\n[\"a\",}"); } - @Test public void failWithPositionOverCStyleComment() throws IOException { - testFailWithPosition("Expected value at path $[1]", - "\n\n/* foo\n*\n*\r\nbar */[\"a\",}"); + @Test + public void failWithPositionOverCStyleComment() throws IOException { + testFailWithPosition("Expected value at path $[1]", "\n\n/* foo\n*\n*\r\nbar */[\"a\",}"); } - @Test public void failWithPositionOverQuotedString() throws IOException { - testFailWithPosition("Expected value at path $[1]", - "[\"foo\nbar\r\nbaz\n\",\n }"); + @Test + public void failWithPositionOverQuotedString() throws IOException { + testFailWithPosition("Expected value at path $[1]", "[\"foo\nbar\r\nbaz\n\",\n }"); } - @Test public void failWithPositionOverUnquotedString() throws IOException { + @Test + public void failWithPositionOverUnquotedString() throws IOException { testFailWithPosition("Expected value at path $[1]", "[\n\nabcd\n\n,}"); } - @Test public void failWithEscapedNewlineCharacter() throws IOException { + @Test + public void failWithEscapedNewlineCharacter() throws IOException { testFailWithPosition("Expected value at path $[1]", "[\n\n\"\\\n\n\",}"); } - @Test @Ignore public void failWithPositionIsOffsetByBom() throws IOException { + @Test + @Ignore + public void failWithPositionIsOffsetByBom() throws IOException { testFailWithPosition("Expected value at path $[1]", "\ufeff[\"a\",}]"); } @@ -979,7 +1048,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } @SuppressWarnings("CheckReturnValue") - @Test public void failWithPositionDeepPath() throws IOException { + @Test + public void failWithPositionDeepPath() throws IOException { JsonReader reader = newReader("[1,{\"a\":[2,3,}"); reader.beginArray(); reader.nextInt(); @@ -996,7 +1066,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void failureMessagePathFromSkipName() throws IOException { + @Test + public void failureMessagePathFromSkipName() throws IOException { JsonReader reader = newReader("{\"a\":[42,}"); reader.beginObject(); reader.skipName(); @@ -1010,7 +1081,9 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test @Ignore public void strictVeryLongNumber() throws IOException { + @Test + @Ignore + public void strictVeryLongNumber() throws IOException { JsonReader reader = newReader("[0." + repeat('9', 8192) + "]"); reader.beginArray(); try { @@ -1020,7 +1093,9 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test @Ignore public void lenientVeryLongNumber() throws IOException { + @Test + @Ignore + public void lenientVeryLongNumber() throws IOException { JsonReader reader = newReader("[0." + repeat('9', 8192) + "]"); reader.setLenient(true); reader.beginArray(); @@ -1030,7 +1105,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void veryLongUnquotedLiteral() throws IOException { + @Test + public void veryLongUnquotedLiteral() throws IOException { String literal = "a" + repeat('b', 8192) + "c"; JsonReader reader = newReader("[" + literal + "]"); reader.setLenient(true); @@ -1039,7 +1115,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio reader.endArray(); } - @Test public void tooDeeplyNestedArrays() throws IOException { + @Test + public void tooDeeplyNestedArrays() throws IOException { JsonReader reader = newReader(repeat("[", MAX_DEPTH + 1) + repeat("]", MAX_DEPTH + 1)); for (int i = 0; i < MAX_DEPTH; i++) { reader.beginArray(); @@ -1052,7 +1129,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void tooDeeplyNestedObjects() throws IOException { + @Test + public void tooDeeplyNestedObjects() throws IOException { // Build a JSON document structured like {"a":{"a":{"a":{"a":true}}}}, but 255 levels deep. String array = "{\"a\":%s}"; String json = "true"; @@ -1074,7 +1152,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } // http://code.google.com/p/google-gson/issues/detail?id=409 - @Test public void stringEndingInSlash() throws IOException { + @Test + public void stringEndingInSlash() throws IOException { JsonReader reader = newReader("/"); reader.setLenient(true); try { @@ -1084,7 +1163,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void documentWithCommentEndingInSlash() throws IOException { + @Test + public void documentWithCommentEndingInSlash() throws IOException { JsonReader reader = newReader("/* foo *//"); reader.setLenient(true); try { @@ -1094,7 +1174,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void stringWithLeadingSlash() throws IOException { + @Test + public void stringWithLeadingSlash() throws IOException { JsonReader reader = newReader("/x"); reader.setLenient(true); try { @@ -1104,7 +1185,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void unterminatedObject() throws IOException { + @Test + public void unterminatedObject() throws IOException { JsonReader reader = newReader("{\"a\":\"android\"x"); reader.setLenient(true); reader.beginObject(); @@ -1117,7 +1199,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void veryLongQuotedString() throws IOException { + @Test + public void veryLongQuotedString() throws IOException { char[] stringChars = new char[1024 * 16]; Arrays.fill(stringChars, 'x'); String string = new String(stringChars); @@ -1128,7 +1211,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio reader.endArray(); } - @Test public void veryLongUnquotedString() throws IOException { + @Test + public void veryLongUnquotedString() throws IOException { char[] stringChars = new char[1024 * 16]; Arrays.fill(stringChars, 'x'); String string = new String(stringChars); @@ -1140,7 +1224,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio reader.endArray(); } - @Test public void veryLongUnterminatedString() throws IOException { + @Test + public void veryLongUnterminatedString() throws IOException { char[] stringChars = new char[1024 * 16]; Arrays.fill(stringChars, 'x'); String string = new String(stringChars); @@ -1156,7 +1241,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void strictExtraCommasInMaps() throws IOException { + @Test + public void strictExtraCommasInMaps() throws IOException { JsonReader reader = newReader("{\"a\":\"b\",}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -1168,7 +1254,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void lenientExtraCommasInMaps() throws IOException { + @Test + public void lenientExtraCommasInMaps() throws IOException { JsonReader reader = newReader("{\"a\":\"b\",}"); reader.setLenient(true); reader.beginObject(); @@ -1181,7 +1268,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void malformedDocuments() throws IOException { + @Test + public void malformedDocuments() throws IOException { assertDocument("{]", BEGIN_OBJECT, JsonEncodingException.class); assertDocument("{,", BEGIN_OBJECT, JsonEncodingException.class); assertDocument("{{", BEGIN_OBJECT, JsonEncodingException.class); @@ -1193,12 +1281,12 @@ private void testFailWithPosition(String message, String json) throws IOExceptio assertDocument("{\"name\":,", BEGIN_OBJECT, NAME, JsonEncodingException.class); assertDocument("{\"name\"=}", BEGIN_OBJECT, NAME, JsonEncodingException.class); assertDocument("{\"name\"=>}", BEGIN_OBJECT, NAME, JsonEncodingException.class); - assertDocument("{\"name\"=>\"string\":", BEGIN_OBJECT, NAME, STRING, - JsonEncodingException.class); - assertDocument("{\"name\"=>\"string\"=", BEGIN_OBJECT, NAME, STRING, - JsonEncodingException.class); - assertDocument("{\"name\"=>\"string\"=>", BEGIN_OBJECT, NAME, STRING, - JsonEncodingException.class); + assertDocument( + "{\"name\"=>\"string\":", BEGIN_OBJECT, NAME, STRING, JsonEncodingException.class); + assertDocument( + "{\"name\"=>\"string\"=", BEGIN_OBJECT, NAME, STRING, JsonEncodingException.class); + assertDocument( + "{\"name\"=>\"string\"=>", BEGIN_OBJECT, NAME, STRING, JsonEncodingException.class); assertDocument("{\"name\"=>\"string\",", BEGIN_OBJECT, NAME, STRING, EOFException.class); assertDocument("{\"name\"=>\"string\",\"name\"", BEGIN_OBJECT, NAME, STRING, NAME); assertDocument("[}", BEGIN_ARRAY, JsonEncodingException.class); @@ -1226,10 +1314,11 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } /** - * This test behave slightly differently in Gson 2.2 and earlier. It fails - * during peek rather than during nextString(). + * This test behave slightly differently in Gson 2.2 and earlier. It fails during peek rather than + * during nextString(). */ - @Test public void unterminatedStringFailure() throws IOException { + @Test + public void unterminatedStringFailure() throws IOException { JsonReader reader = newReader("[\"string"); reader.setLenient(true); reader.beginArray(); @@ -1241,7 +1330,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void invalidEscape() throws IOException { + @Test + public void invalidEscape() throws IOException { JsonReader reader = newReader("[\"str\\ing\"]"); reader.beginArray(); try { @@ -1252,7 +1342,8 @@ private void testFailWithPosition(String message, String json) throws IOExceptio } } - @Test public void lenientInvalidEscape() throws IOException { + @Test + public void lenientInvalidEscape() throws IOException { JsonReader reader = newReader("[\"str\\ing\"]"); reader.setLenient(true); reader.beginArray(); diff --git a/moshi/src/test/java/com/squareup/moshi/JsonUtf8WriterTest.java b/moshi/src/test/java/com/squareup/moshi/JsonUtf8WriterTest.java index 086792130..eec1bd274 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonUtf8WriterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonUtf8WriterTest.java @@ -15,14 +15,15 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; + import java.io.IOException; import okio.Buffer; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; - public final class JsonUtf8WriterTest { - @Test public void prettyPrintObject() throws IOException { + @Test + public void prettyPrintObject() throws IOException { Buffer buffer = new Buffer(); JsonWriter writer = JsonWriter.of(buffer); writer.setSerializeNulls(true); @@ -43,24 +44,26 @@ public final class JsonUtf8WriterTest { writer.endObject(); writer.endObject(); - String expected = "{\n" - + " \"a\": true,\n" - + " \"b\": false,\n" - + " \"c\": 5.0,\n" - + " \"e\": null,\n" - + " \"f\": [\n" - + " 6.0,\n" - + " 7.0\n" - + " ],\n" - + " \"g\": {\n" - + " \"h\": 8.0,\n" - + " \"i\": 9.0\n" - + " }\n" - + "}"; + String expected = + "{\n" + + " \"a\": true,\n" + + " \"b\": false,\n" + + " \"c\": 5.0,\n" + + " \"e\": null,\n" + + " \"f\": [\n" + + " 6.0,\n" + + " 7.0\n" + + " ],\n" + + " \"g\": {\n" + + " \"h\": 8.0,\n" + + " \"i\": 9.0\n" + + " }\n" + + "}"; assertThat(buffer.readUtf8()).isEqualTo(expected); } - @Test public void prettyPrintArray() throws IOException { + @Test + public void prettyPrintArray() throws IOException { Buffer buffer = new Buffer(); JsonWriter writer = JsonWriter.of(buffer); writer.setIndent(" "); @@ -80,24 +83,26 @@ public final class JsonUtf8WriterTest { writer.endArray(); writer.endArray(); - String expected = "[\n" - + " true,\n" - + " false,\n" - + " 5.0,\n" - + " null,\n" - + " {\n" - + " \"a\": 6.0,\n" - + " \"b\": 7.0\n" - + " },\n" - + " [\n" - + " 8.0,\n" - + " 9.0\n" - + " ]\n" - + "]"; + String expected = + "[\n" + + " true,\n" + + " false,\n" + + " 5.0,\n" + + " null,\n" + + " {\n" + + " \"a\": 6.0,\n" + + " \"b\": 7.0\n" + + " },\n" + + " [\n" + + " 8.0,\n" + + " 9.0\n" + + " ]\n" + + "]"; assertThat(buffer.readUtf8()).isEqualTo(expected); } - @Test public void repeatedNameIgnored() throws IOException { + @Test + public void repeatedNameIgnored() throws IOException { Buffer buffer = new Buffer(); JsonWriter writer = JsonWriter.of(buffer); writer.beginObject(); @@ -108,7 +113,8 @@ public final class JsonUtf8WriterTest { assertThat(buffer.readUtf8()).isEqualTo("{\"a\":1,\"a\":2}"); } - @Test public void valueFromSource() throws IOException { + @Test + public void valueFromSource() throws IOException { Buffer buffer = new Buffer(); JsonWriter writer = JsonUtf8Writer.of(buffer); writer.beginObject(); diff --git a/moshi/src/test/java/com/squareup/moshi/JsonValueReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonValueReaderTest.java index 3be3edccc..6c9abdeae 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonValueReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonValueReaderTest.java @@ -15,6 +15,13 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.TestUtil.MAX_DEPTH; +import static com.squareup.moshi.TestUtil.repeat; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -24,15 +31,9 @@ import java.util.Map; import org.junit.Test; -import static com.squareup.moshi.TestUtil.MAX_DEPTH; -import static com.squareup.moshi.TestUtil.repeat; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class JsonValueReaderTest { - @Test public void array() throws Exception { + @Test + public void array() throws Exception { List root = new ArrayList<>(); root.add("s"); root.add(1.5d); @@ -67,7 +68,8 @@ public final class JsonValueReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void object() throws Exception { + @Test + public void object() throws Exception { Map root = new LinkedHashMap<>(); root.put("a", "s"); root.put("b", 1.5d); @@ -110,9 +112,10 @@ public final class JsonValueReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void nesting() throws Exception { - List>>> root - = singletonList(singletonMap("a", singletonList(singletonMap("b", 1.5d)))); + @Test + public void nesting() throws Exception { + List>>> root = + singletonList(singletonMap("a", singletonList(singletonMap("b", 1.5d)))); JsonReader reader = new JsonValueReader(root); assertThat(reader.hasNext()).isTrue(); @@ -162,7 +165,8 @@ public final class JsonValueReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void promoteNameToValue() throws Exception { + @Test + public void promoteNameToValue() throws Exception { Map root = singletonMap("a", "b"); JsonReader reader = new JsonValueReader(root); @@ -178,7 +182,8 @@ public final class JsonValueReaderTest { assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void endArrayTooEarly() throws Exception { + @Test + public void endArrayTooEarly() throws Exception { JsonReader reader = new JsonValueReader(singletonList("s")); reader.beginArray(); @@ -186,12 +191,13 @@ public final class JsonValueReaderTest { reader.endArray(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected END_ARRAY but was s, a java.lang.String, at path $[0]"); + assertThat(expected) + .hasMessage("Expected END_ARRAY but was s, a java.lang.String, at path $[0]"); } } - @Test public void endObjectTooEarly() throws Exception { + @Test + public void endObjectTooEarly() throws Exception { JsonReader reader = new JsonValueReader(singletonMap("a", "b")); reader.beginObject(); @@ -203,7 +209,8 @@ public final class JsonValueReaderTest { } } - @Test public void unsupportedType() throws Exception { + @Test + public void unsupportedType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("x"))); reader.beginArray(); @@ -211,12 +218,13 @@ public final class JsonValueReaderTest { reader.peek(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected a JSON value but was x, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected a JSON value but was x, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void unsupportedKeyType() throws Exception { + @Test + public void unsupportedKeyType() throws Exception { JsonReader reader = new JsonValueReader(singletonMap(new StringBuilder("x"), "y")); reader.beginObject(); @@ -224,12 +232,13 @@ public final class JsonValueReaderTest { reader.nextName(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected NAME but was x, a java.lang.StringBuilder, at path $."); + assertThat(expected) + .hasMessage("Expected NAME but was x, a java.lang.StringBuilder, at path $."); } } - @Test public void nullKey() throws Exception { + @Test + public void nullKey() throws Exception { JsonReader reader = new JsonValueReader(singletonMap(null, "y")); reader.beginObject(); @@ -241,85 +250,93 @@ public final class JsonValueReaderTest { } } - @Test public void unexpectedIntType() throws Exception { + @Test + public void unexpectedIntType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("1"))); reader.beginArray(); try { reader.nextInt(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected NUMBER but was 1, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected NUMBER but was 1, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void unexpectedLongType() throws Exception { + @Test + public void unexpectedLongType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("1"))); reader.beginArray(); try { reader.nextLong(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected NUMBER but was 1, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected NUMBER but was 1, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void unexpectedDoubleType() throws Exception { + @Test + public void unexpectedDoubleType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("1"))); reader.beginArray(); try { reader.nextDouble(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected NUMBER but was 1, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected NUMBER but was 1, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void unexpectedStringType() throws Exception { + @Test + public void unexpectedStringType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("s"))); reader.beginArray(); try { reader.nextString(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected STRING but was s, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected STRING but was s, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void unexpectedBooleanType() throws Exception { + @Test + public void unexpectedBooleanType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("true"))); reader.beginArray(); try { reader.nextBoolean(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected BOOLEAN but was true, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected BOOLEAN but was true, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void unexpectedNullType() throws Exception { + @Test + public void unexpectedNullType() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("null"))); reader.beginArray(); try { reader.nextNull(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected NULL but was null, a java.lang.StringBuilder, at path $[0]"); + assertThat(expected) + .hasMessage("Expected NULL but was null, a java.lang.StringBuilder, at path $[0]"); } } - @Test public void skipRoot() throws Exception { + @Test + public void skipRoot() throws Exception { JsonReader reader = new JsonValueReader(singletonList(new StringBuilder("x"))); reader.skipValue(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void skipListValue() throws Exception { + @Test + public void skipListValue() throws Exception { List root = new ArrayList<>(); root.add("a"); root.add("b"); @@ -340,7 +357,8 @@ public final class JsonValueReaderTest { reader.endArray(); } - @Test public void skipObjectName() throws Exception { + @Test + public void skipObjectName() throws Exception { Map root = new LinkedHashMap<>(); root.put("a", "s"); root.put("b", 1.5d); @@ -367,7 +385,8 @@ public final class JsonValueReaderTest { reader.endObject(); } - @Test public void skipObjectValue() throws Exception { + @Test + public void skipObjectValue() throws Exception { Map root = new LinkedHashMap<>(); root.put("a", "s"); root.put("b", 1.5d); @@ -394,7 +413,8 @@ public final class JsonValueReaderTest { reader.endObject(); } - @Test public void failOnUnknown() throws Exception { + @Test + public void failOnUnknown() throws Exception { JsonReader reader = new JsonValueReader(singletonList("a")); reader.setFailOnUnknown(true); @@ -407,7 +427,8 @@ public final class JsonValueReaderTest { } } - @Test public void close() throws Exception { + @Test + public void close() throws Exception { try { JsonReader reader = new JsonValueReader(singletonList("a")); reader.beginArray(); @@ -426,7 +447,8 @@ public final class JsonValueReaderTest { } } - @Test public void numberToStringCoersion() throws Exception { + @Test + public void numberToStringCoersion() throws Exception { JsonReader reader = new JsonValueReader(Arrays.asList(0, 9223372036854775807L, 2.5d, 3.01f, "a", "5")); reader.beginArray(); @@ -439,7 +461,8 @@ public final class JsonValueReaderTest { reader.endArray(); } - @Test public void tooDeeplyNestedArrays() throws IOException { + @Test + public void tooDeeplyNestedArrays() throws IOException { Object root = Collections.emptyList(); for (int i = 0; i < MAX_DEPTH + 1; i++) { root = singletonList(root); @@ -456,7 +479,8 @@ public final class JsonValueReaderTest { } } - @Test public void tooDeeplyNestedObjects() throws IOException { + @Test + public void tooDeeplyNestedObjects() throws IOException { Object root = Boolean.TRUE; for (int i = 0; i < MAX_DEPTH + 1; i++) { root = singletonMap("a", root); diff --git a/moshi/src/test/java/com/squareup/moshi/JsonValueWriterTest.java b/moshi/src/test/java/com/squareup/moshi/JsonValueWriterTest.java index 7faae6ff3..39167ef28 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonValueWriterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonValueWriterTest.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; @@ -27,13 +31,10 @@ import okio.Buffer; import org.junit.Test; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class JsonValueWriterTest { @SuppressWarnings("unchecked") - @Test public void array() throws Exception { + @Test + public void array() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.beginArray(); @@ -46,7 +47,8 @@ public final class JsonValueWriterTest { assertThat((List) writer.root()).containsExactly("s", 1.5d, true, null); } - @Test public void object() throws Exception { + @Test + public void object() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.setSerializeNulls(true); @@ -57,14 +59,16 @@ public final class JsonValueWriterTest { writer.name("d").nullValue(); writer.endObject(); - assertThat((Map) writer.root()).containsExactly( - new SimpleEntry("a", "s"), - new SimpleEntry("b", 1.5d), - new SimpleEntry("c", true), - new SimpleEntry("d", null)); + assertThat((Map) writer.root()) + .containsExactly( + new SimpleEntry("a", "s"), + new SimpleEntry("b", 1.5d), + new SimpleEntry("c", true), + new SimpleEntry("d", null)); } - @Test public void repeatedNameThrows() throws IOException { + @Test + public void repeatedNameThrows() throws IOException { JsonValueWriter writer = new JsonValueWriter(); writer.beginObject(); writer.name("a").value(1L); @@ -72,12 +76,12 @@ public final class JsonValueWriterTest { writer.name("a").value(2L); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage( - "Map key 'a' has multiple values at path $.a: 1 and 2"); + assertThat(expected).hasMessage("Map key 'a' has multiple values at path $.a: 1 and 2"); } } - @Test public void valueLongEmitsLong() throws Exception { + @Test + public void valueLongEmitsLong() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.beginArray(); writer.value(Long.MIN_VALUE); @@ -87,16 +91,12 @@ public final class JsonValueWriterTest { writer.value(Long.MAX_VALUE); writer.endArray(); - List numbers = Arrays.asList( - Long.MIN_VALUE, - -1L, - 0L, - 1L, - Long.MAX_VALUE); + List numbers = Arrays.asList(Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE); assertThat((List) writer.root()).isEqualTo(numbers); } - @Test public void valueDoubleEmitsDouble() throws Exception { + @Test + public void valueDoubleEmitsDouble() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.setLenient(true); writer.beginArray(); @@ -124,33 +124,35 @@ public final class JsonValueWriterTest { writer.value(Double.NaN); writer.endArray(); - List numbers = Arrays.asList( - -2147483649.0d, - -2147483648.0d, - -1.0d, - 0.0d, - 1.0d, - 2147483647.0d, - 2147483648.0d, - 9007199254740991.0d, - 9007199254740992.0d, - 9007199254740994.0d, - 9223372036854775807.0d, - -0.5d, - -0.0d, - 0.5d, - 9.22337203685478e18, - Double.NEGATIVE_INFINITY, - Double.MIN_VALUE, - Double.MIN_NORMAL, - -Double.MIN_NORMAL, - Double.MAX_VALUE, - Double.POSITIVE_INFINITY, - Double.NaN); + List numbers = + Arrays.asList( + -2147483649.0d, + -2147483648.0d, + -1.0d, + 0.0d, + 1.0d, + 2147483647.0d, + 2147483648.0d, + 9007199254740991.0d, + 9007199254740992.0d, + 9007199254740994.0d, + 9223372036854775807.0d, + -0.5d, + -0.0d, + 0.5d, + 9.22337203685478e18, + Double.NEGATIVE_INFINITY, + Double.MIN_VALUE, + Double.MIN_NORMAL, + -Double.MIN_NORMAL, + Double.MAX_VALUE, + Double.POSITIVE_INFINITY, + Double.NaN); assertThat((List) writer.root()).isEqualTo(numbers); } - @Test public void primitiveIntegerTypesEmitLong() throws Exception { + @Test + public void primitiveIntegerTypesEmitLong() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.beginArray(); writer.value(new Byte(Byte.MIN_VALUE)); @@ -159,28 +161,25 @@ public final class JsonValueWriterTest { writer.value(new Long(Long.MIN_VALUE)); writer.endArray(); - List numbers = Arrays.asList( - -128L, - -32768L, - -2147483648L, - -9223372036854775808L); + List numbers = + Arrays.asList(-128L, -32768L, -2147483648L, -9223372036854775808L); assertThat((List) writer.root()).isEqualTo(numbers); } - @Test public void primitiveFloatingPointTypesEmitDouble() throws Exception { + @Test + public void primitiveFloatingPointTypesEmitDouble() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.beginArray(); writer.value(new Float(0.5f)); writer.value(new Double(0.5d)); writer.endArray(); - List numbers = Arrays.asList( - 0.5d, - 0.5d); + List numbers = Arrays.asList(0.5d, 0.5d); assertThat((List) writer.root()).isEqualTo(numbers); } - @Test public void otherNumberTypesEmitBigDecimal() throws Exception { + @Test + public void otherNumberTypesEmitBigDecimal() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.beginArray(); writer.value(new AtomicInteger(-2147483648)); @@ -204,30 +203,32 @@ public final class JsonValueWriterTest { writer.value(new BigDecimal("0.0000100e-10")); writer.endArray(); - List numbers = Arrays.asList( - new BigDecimal("-2147483648"), - new BigDecimal("-9223372036854775808"), - new BigDecimal("-9223372036854775808"), - new BigDecimal("-1"), - new BigDecimal("0"), - new BigDecimal("1"), - new BigDecimal("9223372036854775807"), - new BigDecimal("-9223372036854775808"), - new BigDecimal("-1"), - new BigDecimal("0"), - new BigDecimal("1"), - new BigDecimal("9223372036854775807"), - new BigDecimal("-9223372036854775809"), - new BigDecimal("9223372036854775808"), - new BigDecimal("-9223372036854775809"), - new BigDecimal("9223372036854775808"), - new BigDecimal("0.5"), - new BigDecimal("100000e15"), - new BigDecimal("0.0000100e-10")); + List numbers = + Arrays.asList( + new BigDecimal("-2147483648"), + new BigDecimal("-9223372036854775808"), + new BigDecimal("-9223372036854775808"), + new BigDecimal("-1"), + new BigDecimal("0"), + new BigDecimal("1"), + new BigDecimal("9223372036854775807"), + new BigDecimal("-9223372036854775808"), + new BigDecimal("-1"), + new BigDecimal("0"), + new BigDecimal("1"), + new BigDecimal("9223372036854775807"), + new BigDecimal("-9223372036854775809"), + new BigDecimal("9223372036854775808"), + new BigDecimal("-9223372036854775809"), + new BigDecimal("9223372036854775808"), + new BigDecimal("0.5"), + new BigDecimal("100000e15"), + new BigDecimal("0.0000100e-10")); assertThat((List) writer.root()).isEqualTo(numbers); } - @Test public void valueCustomNumberTypeEmitsLongOrBigDecimal() throws Exception { + @Test + public void valueCustomNumberTypeEmitsLongOrBigDecimal() throws Exception { JsonValueWriter writer = new JsonValueWriter(); writer.beginArray(); writer.value(stringNumber("-9223372036854775809")); @@ -236,15 +237,17 @@ public final class JsonValueWriterTest { writer.value(stringNumber("1.0")); writer.endArray(); - List numbers = Arrays.asList( - new BigDecimal("-9223372036854775809"), - new BigDecimal("-9223372036854775808"), - new BigDecimal("0.5"), - new BigDecimal("1.0")); + List numbers = + Arrays.asList( + new BigDecimal("-9223372036854775809"), + new BigDecimal("-9223372036854775808"), + new BigDecimal("0.5"), + new BigDecimal("1.0")); assertThat((List) writer.root()).isEqualTo(numbers); } - @Test public void valueFromSource() throws IOException { + @Test + public void valueFromSource() throws IOException { JsonValueWriter writer = new JsonValueWriter(); writer.beginObject(); writer.name("a"); @@ -256,11 +259,12 @@ public final class JsonValueWriterTest { writer.name("d"); writer.value(new Buffer().writeUtf8("null")); writer.endObject(); - assertThat((Map) writer.root()).containsExactly( - new SimpleEntry("a", singletonList("value")), - new SimpleEntry("b", 2.0d), - new SimpleEntry("c", 3L), - new SimpleEntry("d", null)); + assertThat((Map) writer.root()) + .containsExactly( + new SimpleEntry("a", singletonList("value")), + new SimpleEntry("b", 2.0d), + new SimpleEntry("c", 3L), + new SimpleEntry("d", null)); } /** @@ -270,23 +274,28 @@ public final class JsonValueWriterTest { */ private Number stringNumber(final String s) { return new Number() { - @Override public int intValue() { + @Override + public int intValue() { throw new AssertionError(); } - @Override public long longValue() { + @Override + public long longValue() { throw new AssertionError(); } - @Override public float floatValue() { + @Override + public float floatValue() { throw new AssertionError(); } - @Override public double doubleValue() { + @Override + public double doubleValue() { throw new AssertionError(); } - @Override public String toString() { + @Override + public String toString() { return s; } }; diff --git a/moshi/src/test/java/com/squareup/moshi/JsonWriterPathTest.java b/moshi/src/test/java/com/squareup/moshi/JsonWriterPathTest.java index ad9ca0cdf..347e270f2 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonWriterPathTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonWriterPathTest.java @@ -15,6 +15,9 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; + import java.io.IOException; import java.math.BigInteger; import java.util.List; @@ -24,9 +27,6 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assume.assumeTrue; - @RunWith(Parameterized.class) public final class JsonWriterPathTest { @Parameter public JsonCodecFactory factory; @@ -36,7 +36,8 @@ public static List parameters() { return JsonCodecFactory.factories(); } - @Test public void path() throws IOException { + @Test + public void path() throws IOException { JsonWriter writer = factory.newWriter(); assertThat(writer.getPath()).isEqualTo("$"); writer.beginObject(); @@ -75,7 +76,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void arrayOfObjects() throws IOException { + @Test + public void arrayOfObjects() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); assertThat(writer.getPath()).isEqualTo("$[0]"); @@ -95,7 +97,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void arrayOfArrays() throws IOException { + @Test + public void arrayOfArrays() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); assertThat(writer.getPath()).isEqualTo("$[0]"); @@ -115,7 +118,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void objectPath() throws IOException { + @Test + public void objectPath() throws IOException { JsonWriter writer = factory.newWriter(); assertThat(writer.getPath()).isEqualTo("$"); writer.beginObject(); @@ -134,7 +138,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void nestedObjects() throws IOException { + @Test + public void nestedObjects() throws IOException { JsonWriter writer = factory.newWriter(); assertThat(writer.getPath()).isEqualTo("$"); writer.beginObject(); @@ -159,7 +164,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void arrayPath() throws IOException { + @Test + public void arrayPath() throws IOException { JsonWriter writer = factory.newWriter(); assertThat(writer.getPath()).isEqualTo("$"); writer.beginArray(); @@ -180,7 +186,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void nestedArrays() throws IOException { + @Test + public void nestedArrays() throws IOException { JsonWriter writer = factory.newWriter(); assertThat(writer.getPath()).isEqualTo("$"); writer.beginArray(); @@ -201,7 +208,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void multipleTopLevelValuesInOneDocument() throws IOException { + @Test + public void multipleTopLevelValuesInOneDocument() throws IOException { assumeTrue(factory.encodesToBytes()); JsonWriter writer = factory.newWriter(); @@ -214,7 +222,8 @@ public static List parameters() { assertThat(writer.getPath()).isEqualTo("$"); } - @Test public void skipNulls() throws IOException { + @Test + public void skipNulls() throws IOException { JsonWriter writer = factory.newWriter(); writer.setSerializeNulls(false); assertThat(writer.getPath()).isEqualTo("$"); diff --git a/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java b/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java index d2e441bc8..76b1c5978 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java @@ -15,6 +15,12 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.TestUtil.MAX_DEPTH; +import static com.squareup.moshi.TestUtil.repeat; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; + import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; @@ -30,12 +36,6 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static com.squareup.moshi.TestUtil.MAX_DEPTH; -import static com.squareup.moshi.TestUtil.repeat; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeTrue; - @RunWith(Parameterized.class) public final class JsonWriterTest { @Parameter public JsonCodecFactory factory; @@ -45,7 +45,8 @@ public static List parameters() { return JsonCodecFactory.factories(); } - @Test public void nullsValuesNotSerializedByDefault() throws IOException { + @Test + public void nullsValuesNotSerializedByDefault() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -55,7 +56,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{}"); } - @Test public void nullsValuesSerializedWhenConfigured() throws IOException { + @Test + public void nullsValuesSerializedWhenConfigured() throws IOException { JsonWriter writer = factory.newWriter(); writer.setSerializeNulls(true); writer.beginObject(); @@ -66,42 +68,48 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":null}"); } - @Test public void topLevelBoolean() throws IOException { + @Test + public void topLevelBoolean() throws IOException { JsonWriter writer = factory.newWriter(); writer.value(true); writer.close(); assertThat(factory.json()).isEqualTo("true"); } - @Test public void topLevelNull() throws IOException { + @Test + public void topLevelNull() throws IOException { JsonWriter writer = factory.newWriter(); writer.nullValue(); writer.close(); assertThat(factory.json()).isEqualTo("null"); } - @Test public void topLevelInt() throws IOException { + @Test + public void topLevelInt() throws IOException { JsonWriter writer = factory.newWriter(); writer.value(123); writer.close(); assertThat(factory.json()).isEqualTo("123"); } - @Test public void topLevelDouble() throws IOException { + @Test + public void topLevelDouble() throws IOException { JsonWriter writer = factory.newWriter(); writer.value(123.4); writer.close(); assertThat(factory.json()).isEqualTo("123.4"); } - @Test public void topLevelString() throws IOException { + @Test + public void topLevelString() throws IOException { JsonWriter writer = factory.newWriter(); writer.value("a"); writer.close(); assertThat(factory.json()).isEqualTo("\"a\""); } - @Test public void invalidTopLevelTypes() throws IOException { + @Test + public void invalidTopLevelTypes() throws IOException { JsonWriter writer = factory.newWriter(); try { writer.name("hello").value("world"); @@ -110,7 +118,8 @@ public static List parameters() { } } - @Test public void twoNames() throws IOException { + @Test + public void twoNames() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -121,7 +130,8 @@ public static List parameters() { } } - @Test public void nameWithoutValue() throws IOException { + @Test + public void nameWithoutValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -132,7 +142,8 @@ public static List parameters() { } } - @Test public void valueWithoutName() throws IOException { + @Test + public void valueWithoutName() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); try { @@ -142,7 +153,8 @@ public static List parameters() { } } - @Test public void multipleTopLevelValues() throws IOException { + @Test + public void multipleTopLevelValues() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray().endArray(); try { @@ -152,7 +164,8 @@ public static List parameters() { } } - @Test public void badNestingObject() throws IOException { + @Test + public void badNestingObject() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.beginObject(); @@ -163,7 +176,8 @@ public static List parameters() { } } - @Test public void badNestingArray() throws IOException { + @Test + public void badNestingArray() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.beginArray(); @@ -174,7 +188,8 @@ public static List parameters() { } } - @Test public void nullName() throws IOException { + @Test + public void nullName() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); try { @@ -184,7 +199,8 @@ public static List parameters() { } } - @Test public void nullStringValue() throws IOException { + @Test + public void nullStringValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.setSerializeNulls(true); writer.beginObject(); @@ -194,7 +210,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":null}"); } - @Test public void nonFiniteDoubles() throws IOException { + @Test + public void nonFiniteDoubles() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); try { @@ -214,7 +231,8 @@ public static List parameters() { } } - @Test public void nonFiniteBoxedDoubles() throws IOException { + @Test + public void nonFiniteBoxedDoubles() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); try { @@ -234,7 +252,8 @@ public static List parameters() { } } - @Test public void doubles() throws IOException { + @Test + public void doubles() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value(-0.0); @@ -248,18 +267,21 @@ public static List parameters() { writer.value(Math.E); writer.endArray(); writer.close(); - assertThat(factory.json()).isEqualTo("[-0.0," - + "1.0," - + "1.7976931348623157E308," - + "4.9E-324," - + "0.0," - + "-0.5," - + "2.2250738585072014E-308," - + "3.141592653589793," - + "2.718281828459045]"); + assertThat(factory.json()) + .isEqualTo( + "[-0.0," + + "1.0," + + "1.7976931348623157E308," + + "4.9E-324," + + "0.0," + + "-0.5," + + "2.2250738585072014E-308," + + "3.141592653589793," + + "2.718281828459045]"); } - @Test public void longs() throws IOException { + @Test + public void longs() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value(0); @@ -269,14 +291,12 @@ public static List parameters() { writer.value(Long.MAX_VALUE); writer.endArray(); writer.close(); - assertThat(factory.json()).isEqualTo("[0," - + "1," - + "-1," - + "-9223372036854775808," - + "9223372036854775807]"); + assertThat(factory.json()) + .isEqualTo("[0," + "1," + "-1," + "-9223372036854775808," + "9223372036854775807]"); } - @Test public void numbers() throws IOException { + @Test + public void numbers() throws IOException { assumeTrue(factory.supportsBigNumbers()); JsonWriter writer = factory.newWriter(); @@ -287,13 +307,16 @@ public static List parameters() { writer.value(new BigDecimal("3.141592653589793238462643383")); writer.endArray(); writer.close(); - assertThat(factory.json()).isEqualTo("[0," - + "9223372036854775808," - + "-9223372036854775809," - + "3.141592653589793238462643383]"); + assertThat(factory.json()) + .isEqualTo( + "[0," + + "9223372036854775808," + + "-9223372036854775809," + + "3.141592653589793238462643383]"); } - @Test public void nullNumbers() throws IOException { + @Test + public void nullNumbers() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value((Number) null); @@ -302,7 +325,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[null]"); } - @Test public void booleans() throws IOException { + @Test + public void booleans() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value(true); @@ -311,7 +335,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[true,false]"); } - @Test public void boxedBooleans() throws IOException { + @Test + public void boxedBooleans() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value((Boolean) true); @@ -321,7 +346,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[true,false,null]"); } - @Test public void nulls() throws IOException { + @Test + public void nulls() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.nullValue(); @@ -329,7 +355,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[null]"); } - @Test public void strings() throws IOException { + @Test + public void strings() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value("a"); @@ -351,27 +378,30 @@ public static List parameters() { writer.value("\0"); writer.value("\u0019"); writer.endArray(); - assertThat(factory.json()).isEqualTo("[\"a\"," - + "\"a\\\"\"," - + "\"\\\"\"," - + "\":\"," - + "\",\"," - + "\"\\b\"," - + "\"\\f\"," - + "\"\\n\"," - + "\"\\r\"," - + "\"\\t\"," - + "\" \"," - + "\"\\\\\"," - + "\"{\"," - + "\"}\"," - + "\"[\"," - + "\"]\"," - + "\"\\u0000\"," - + "\"\\u0019\"]"); - } - - @Test public void unicodeLineBreaksEscaped() throws IOException { + assertThat(factory.json()) + .isEqualTo( + "[\"a\"," + + "\"a\\\"\"," + + "\"\\\"\"," + + "\":\"," + + "\",\"," + + "\"\\b\"," + + "\"\\f\"," + + "\"\\n\"," + + "\"\\r\"," + + "\"\\t\"," + + "\" \"," + + "\"\\\\\"," + + "\"{\"," + + "\"}\"," + + "\"[\"," + + "\"]\"," + + "\"\\u0000\"," + + "\"\\u0019\"]"); + } + + @Test + public void unicodeLineBreaksEscaped() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.value("\u2028 \u2029"); @@ -379,21 +409,24 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[\"\\u2028 \\u2029\"]"); } - @Test public void emptyArray() throws IOException { + @Test + public void emptyArray() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); assertThat(factory.json()).isEqualTo("[]"); } - @Test public void emptyObject() throws IOException { + @Test + public void emptyObject() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.endObject(); assertThat(factory.json()).isEqualTo("{}"); } - @Test public void objectsInArrays() throws IOException { + @Test + public void objectsInArrays() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.beginObject(); @@ -405,11 +438,11 @@ public static List parameters() { writer.name("d").value(true); writer.endObject(); writer.endArray(); - assertThat(factory.json()).isEqualTo("[{\"a\":5,\"b\":false}," - + "{\"c\":6,\"d\":true}]"); + assertThat(factory.json()).isEqualTo("[{\"a\":5,\"b\":false}," + "{\"c\":6,\"d\":true}]"); } - @Test public void arraysInObjects() throws IOException { + @Test + public void arraysInObjects() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -423,11 +456,11 @@ public static List parameters() { writer.value(true); writer.endArray(); writer.endObject(); - assertThat(factory.json()).isEqualTo("{\"a\":[5,false]," - + "\"b\":[6,true]}"); + assertThat(factory.json()).isEqualTo("{\"a\":[5,false]," + "\"b\":[6,true]}"); } - @Test public void deepNestingArrays() throws IOException { + @Test + public void deepNestingArrays() throws IOException { JsonWriter writer = factory.newWriter(); for (int i = 0; i < MAX_DEPTH; i++) { writer.beginArray(); @@ -435,11 +468,11 @@ public static List parameters() { for (int i = 0; i < MAX_DEPTH; i++) { writer.endArray(); } - assertThat(factory.json()) - .isEqualTo(repeat("[", MAX_DEPTH) + repeat("]", MAX_DEPTH)); + assertThat(factory.json()).isEqualTo(repeat("[", MAX_DEPTH) + repeat("]", MAX_DEPTH)); } - @Test public void tooDeeplyNestingArrays() throws IOException { + @Test + public void tooDeeplyNestingArrays() throws IOException { JsonWriter writer = factory.newWriter(); for (int i = 0; i < MAX_DEPTH; i++) { writer.beginArray(); @@ -448,12 +481,13 @@ public static List parameters() { writer.beginArray(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage("Nesting too deep at $" - + repeat("[0]", MAX_DEPTH) + ": circular reference?"); + assertThat(expected) + .hasMessage("Nesting too deep at $" + repeat("[0]", MAX_DEPTH) + ": circular reference?"); } } - @Test public void deepNestingObjects() throws IOException { + @Test + public void deepNestingObjects() throws IOException { JsonWriter writer = factory.newWriter(); for (int i = 0; i < MAX_DEPTH; i++) { writer.beginObject(); @@ -463,11 +497,12 @@ public static List parameters() { for (int i = 0; i < MAX_DEPTH; i++) { writer.endObject(); } - assertThat(factory.json()).isEqualTo( - repeat("{\"a\":", MAX_DEPTH) + "true" + repeat("}", MAX_DEPTH)); + assertThat(factory.json()) + .isEqualTo(repeat("{\"a\":", MAX_DEPTH) + "true" + repeat("}", MAX_DEPTH)); } - @Test public void tooDeeplyNestingObjects() throws IOException { + @Test + public void tooDeeplyNestingObjects() throws IOException { JsonWriter writer = factory.newWriter(); for (int i = 0; i < MAX_DEPTH; i++) { writer.beginObject(); @@ -477,12 +512,13 @@ public static List parameters() { writer.beginObject(); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage("Nesting too deep at $" - + repeat(".a", MAX_DEPTH) + ": circular reference?"); + assertThat(expected) + .hasMessage("Nesting too deep at $" + repeat(".a", MAX_DEPTH) + ": circular reference?"); } } - @Test public void lenientWriterPermitsMultipleTopLevelValues() throws IOException { + @Test + public void lenientWriterPermitsMultipleTopLevelValues() throws IOException { assumeTrue(factory.encodesToBytes()); JsonWriter writer = factory.newWriter(); @@ -495,7 +531,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("[][]"); } - @Test public void strictWriterDoesNotPermitMultipleTopLevelValues() throws IOException { + @Test + public void strictWriterDoesNotPermitMultipleTopLevelValues() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); @@ -506,7 +543,8 @@ public static List parameters() { } } - @Test public void closedWriterThrowsOnStructure() throws IOException { + @Test + public void closedWriterThrowsOnStructure() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); @@ -533,7 +571,8 @@ public static List parameters() { } } - @Test public void closedWriterThrowsOnName() throws IOException { + @Test + public void closedWriterThrowsOnName() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); @@ -545,7 +584,8 @@ public static List parameters() { } } - @Test public void closedWriterThrowsOnValue() throws IOException { + @Test + public void closedWriterThrowsOnValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); @@ -557,7 +597,8 @@ public static List parameters() { } } - @Test public void closedWriterThrowsOnFlush() throws IOException { + @Test + public void closedWriterThrowsOnFlush() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); @@ -569,7 +610,8 @@ public static List parameters() { } } - @Test public void writerCloseIsIdempotent() throws IOException { + @Test + public void writerCloseIsIdempotent() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.endArray(); @@ -577,7 +619,8 @@ public static List parameters() { writer.close(); } - @Test public void nameNotInObjectFails() throws IOException { + @Test + public void nameNotInObjectFails() throws IOException { JsonWriter writer = factory.newWriter(); try { writer.name("a"); @@ -587,7 +630,8 @@ public static List parameters() { } } - @Test public void missingValueInObjectIsANestingProblem() throws IOException { + @Test + public void missingValueInObjectIsANestingProblem() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -599,7 +643,8 @@ public static List parameters() { } } - @Test public void nameInArrayIsANestingProblem() throws IOException { + @Test + public void nameInArrayIsANestingProblem() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); try { @@ -610,7 +655,8 @@ public static List parameters() { } } - @Test public void danglingNameFails() throws IOException { + @Test + public void danglingNameFails() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -622,7 +668,8 @@ public static List parameters() { } } - @Test public void streamingValueInObject() throws IOException { + @Test + public void streamingValueInObject() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -637,35 +684,26 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":\"ffffffffffffffffsup-1\"}"); } - @Test public void streamingValueInArray() throws IOException { + @Test + public void streamingValueInArray() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginArray(); - writer.valueSink() - .writeByte('"') - .writeHexadecimalUnsignedLong(-1L) - .writeByte('"') - .close(); - writer.valueSink() - .writeByte('"') - .writeUtf8("sup") - .writeByte('"') - .close(); - writer.valueSink() - .writeUtf8("-1.0") - .close(); + writer.valueSink().writeByte('"').writeHexadecimalUnsignedLong(-1L).writeByte('"').close(); + writer.valueSink().writeByte('"').writeUtf8("sup").writeByte('"').close(); + writer.valueSink().writeUtf8("-1.0").close(); writer.endArray(); assertThat(factory.json()).isEqualTo("[\"ffffffffffffffff\",\"sup\",-1.0]"); } - @Test public void streamingValueTopLevel() throws IOException { + @Test + public void streamingValueTopLevel() throws IOException { JsonWriter writer = factory.newWriter(); - writer.valueSink() - .writeUtf8("-1.0") - .close(); + writer.valueSink().writeUtf8("-1.0").close(); assertThat(factory.json()).isEqualTo("-1.0"); } - @Test public void streamingValueTwiceBeforeCloseFails() throws IOException { + @Test + public void streamingValueTwiceBeforeCloseFails() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -678,7 +716,8 @@ public static List parameters() { } } - @Test public void streamingValueTwiceAfterCloseFails() throws IOException { + @Test + public void streamingValueTwiceAfterCloseFails() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -692,7 +731,8 @@ public static List parameters() { } } - @Test public void streamingValueAndScalarValueFails() throws IOException { + @Test + public void streamingValueAndScalarValueFails() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -705,7 +745,8 @@ public static List parameters() { } } - @Test public void streamingValueAndNameFails() throws IOException { + @Test + public void streamingValueAndNameFails() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -718,7 +759,8 @@ public static List parameters() { } } - @Test public void streamingValueInteractionAfterCloseFails() throws IOException { + @Test + public void streamingValueInteractionAfterCloseFails() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -733,7 +775,8 @@ public static List parameters() { } } - @Test public void streamingValueCloseIsIdempotent() throws IOException { + @Test + public void streamingValueCloseIsIdempotent() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -747,7 +790,8 @@ public static List parameters() { sink.close(); } - @Test public void jsonValueTypes() throws IOException { + @Test + public void jsonValueTypes() throws IOException { JsonWriter writer = factory.newWriter(); writer.setSerializeNulls(true); @@ -767,21 +811,24 @@ public static List parameters() { 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 { + 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(); @@ -815,7 +862,8 @@ public static List parameters() { } } - @Test public void promoteStringNameToValue() throws IOException { + @Test + public void promoteStringNameToValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -825,7 +873,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":\"b\"}"); } - @Test public void promoteDoubleNameToValue() throws IOException { + @Test + public void promoteDoubleNameToValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -835,7 +884,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"5.0\":\"b\"}"); } - @Test public void promoteLongNameToValue() throws IOException { + @Test + public void promoteLongNameToValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -845,7 +895,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"5\":\"b\"}"); } - @Test public void promoteNumberNameToValue() throws IOException { + @Test + public void promoteNumberNameToValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -855,7 +906,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"1\":\"b\"}"); } - @Test public void promoteNullNameToValue() throws IOException { + @Test + public void promoteNullNameToValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -867,7 +919,8 @@ public static List parameters() { } } - @Test public void promoteBooleanNameToValue() throws IOException { + @Test + public void promoteBooleanNameToValue() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -879,7 +932,8 @@ public static List parameters() { } } - @Test public void promoteNameToValueCannotBeWrittenAsName() throws IOException { + @Test + public void promoteNameToValueCannotBeWrittenAsName() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -891,7 +945,8 @@ public static List parameters() { } } - @Test public void promoteNameToValueAtEndOfObject() throws IOException { + @Test + public void promoteNameToValueAtEndOfObject() throws IOException { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); diff --git a/moshi/src/test/java/com/squareup/moshi/LinkedHashTreeMapTest.java b/moshi/src/test/java/com/squareup/moshi/LinkedHashTreeMapTest.java index f8c605cdc..4b8dff66d 100644 --- a/moshi/src/test/java/com/squareup/moshi/LinkedHashTreeMapTest.java +++ b/moshi/src/test/java/com/squareup/moshi/LinkedHashTreeMapTest.java @@ -15,6 +15,9 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import com.squareup.moshi.LinkedHashTreeMap.AvlBuilder; import com.squareup.moshi.LinkedHashTreeMap.AvlIterator; import com.squareup.moshi.LinkedHashTreeMap.Node; @@ -23,11 +26,9 @@ import java.util.Random; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class LinkedHashTreeMapTest { - @Test public void iterationOrder() { + @Test + public void iterationOrder() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); map.put("a", "android"); map.put("c", "cola"); @@ -36,12 +37,13 @@ public final class LinkedHashTreeMapTest { assertThat(map.values()).containsExactly("android", "cola", "bbq"); } - @Test public void removeRootDoesNotDoubleUnlink() { + @Test + public void removeRootDoesNotDoubleUnlink() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); map.put("a", "android"); map.put("c", "cola"); map.put("b", "bbq"); - Iterator> it = map.entrySet().iterator(); + Iterator> it = map.entrySet().iterator(); it.next(); it.next(); it.next(); @@ -49,7 +51,8 @@ public final class LinkedHashTreeMapTest { assertThat(map.keySet()).containsExactly("a", "c"); } - @Test public void putNullKeyFails() { + @Test + public void putNullKeyFails() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); try { map.put(null, "android"); @@ -58,27 +61,32 @@ public final class LinkedHashTreeMapTest { } } - @Test public void putNonComparableKeyFails() { + @Test + public void putNonComparableKeyFails() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); try { map.put(new Object(), "android"); fail(); - } catch (ClassCastException expected) {} + } catch (ClassCastException expected) { + } } - @Test public void ContainsNonComparableKeyReturnsFalse() { + @Test + public void ContainsNonComparableKeyReturnsFalse() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); map.put("a", "android"); assertThat(map).doesNotContainKey(new Object()); } - @Test public void containsNullKeyIsAlwaysFalse() { + @Test + public void containsNullKeyIsAlwaysFalse() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); map.put("a", "android"); assertThat(map).doesNotContainKey(null); } - @Test public void putOverrides() throws Exception { + @Test + public void putOverrides() throws Exception { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); assertThat(map.put("d", "donut")).isNull(); assertThat(map.put("e", "eclair")).isNull(); @@ -90,7 +98,8 @@ public final class LinkedHashTreeMapTest { assertThat(map).hasSize(3); } - @Test public void emptyStringValues() { + @Test + public void emptyStringValues() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); map.put("a", ""); assertThat(map.containsKey("a")).isTrue(); @@ -100,7 +109,8 @@ public final class LinkedHashTreeMapTest { // NOTE that this does not happen every time, but given the below predictable random, // this test will consistently fail (assuming the initial size is 16 and rehashing // size remains at 3/4) - @Test public void forceDoublingAndRehash() throws Exception { + @Test + public void forceDoublingAndRehash() throws Exception { Random random = new Random(1367593214724L); LinkedHashTreeMap map = new LinkedHashTreeMap<>(); String[] keys = new String[1000]; @@ -116,7 +126,8 @@ public final class LinkedHashTreeMapTest { } } - @Test public void clear() { + @Test + public void clear() { LinkedHashTreeMap map = new LinkedHashTreeMap<>(); map.put("a", "android"); map.put("c", "cola"); @@ -126,7 +137,8 @@ public final class LinkedHashTreeMapTest { assertThat(map).isEmpty(); } - @Test public void equalsAndHashCode() throws Exception { + @Test + public void equalsAndHashCode() throws Exception { LinkedHashTreeMap map1 = new LinkedHashTreeMap<>(); map1.put("A", 1); map1.put("B", 2); @@ -143,17 +155,24 @@ public final class LinkedHashTreeMapTest { assertThat(map2.hashCode()).isEqualTo(map1.hashCode()); } - @Test public void avlWalker() { - assertAvlWalker(node(node("a"), "b", node("c")), - "a", "b", "c"); - assertAvlWalker(node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g"))), - "a", "b", "c", "d", "e", "f", "g"); - assertAvlWalker(node(node(null, "a", node("b")), "c", node(node("d"), "e", null)), - "a", "b", "c", "d", "e"); - assertAvlWalker(node(null, "a", node(null, "b", node(null, "c", node("d")))), - "a", "b", "c", "d"); - assertAvlWalker(node(node(node(node("a"), "b", null), "c", null), "d", null), - "a", "b", "c", "d"); + @Test + public void avlWalker() { + assertAvlWalker(node(node("a"), "b", node("c")), "a", "b", "c"); + assertAvlWalker( + node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g"))), + "a", + "b", + "c", + "d", + "e", + "f", + "g"); + assertAvlWalker( + node(node(null, "a", node("b")), "c", node(node("d"), "e", null)), "a", "b", "c", "d", "e"); + assertAvlWalker( + node(null, "a", node(null, "b", node(null, "c", node("d")))), "a", "b", "c", "d"); + assertAvlWalker( + node(node(node(node("a"), "b", null), "c", null), "d", null), "a", "b", "c", "d"); } private void assertAvlWalker(Node root, String... values) { @@ -165,7 +184,8 @@ private void assertAvlWalker(Node root, String... values) { assertThat(iterator.next()).isNull(); } - @Test public void avlBuilder() { + @Test + public void avlBuilder() { assertAvlBuilder(1, "a"); assertAvlBuilder(2, "(. a b)"); assertAvlBuilder(3, "(a b c)"); @@ -182,10 +202,14 @@ private void assertAvlWalker(Node root, String... values) { assertAvlBuilder(14, "(((. a b) c (d e f)) g ((h i j) k (l m n)))"); assertAvlBuilder(15, "(((a b c) d (e f g)) h ((i j k) l (m n o)))"); assertAvlBuilder(16, "(((a b c) d (e f g)) h ((i j k) l (m n (. o p))))"); - assertAvlBuilder(30, "((((. a b) c (d e f)) g ((h i j) k (l m n))) o " - + "(((p q r) s (t u v)) w ((x y z) A (B C D))))"); - assertAvlBuilder(31, "((((a b c) d (e f g)) h ((i j k) l (m n o))) p " - + "(((q r s) t (u v w)) x ((y z A) B (C D E))))"); + assertAvlBuilder( + 30, + "((((. a b) c (d e f)) g ((h i j) k (l m n))) o " + + "(((p q r) s (t u v)) w ((x y z) A (B C D))))"); + assertAvlBuilder( + 31, + "((((a b c) d (e f g)) h ((i j k) l (m n o))) p " + + "(((q r s) t (u v w)) x ((y z A) B (C D E))))"); } private void assertAvlBuilder(int size, String expected) { @@ -198,7 +222,8 @@ private void assertAvlBuilder(int size, String expected) { assertTree(expected, avlBuilder.root()); } - @Test public void doubleCapacity() { + @Test + public void doubleCapacity() { @SuppressWarnings("unchecked") // Arrays and generics don't get along. Node[] oldTable = new Node[1]; oldTable[0] = node(node(node("a"), "b", node("c")), "d", node(node("e"), "f", node("g"))); @@ -208,9 +233,10 @@ private void assertAvlBuilder(int size, String expected) { assertTree("(a c (. e g))", newTable[1]); // Odd hash codes! } - @Test public void doubleCapacityAllNodesOnLeft() { + @Test + public void doubleCapacityAllNodesOnLeft() { @SuppressWarnings("unchecked") // Arrays and generics don't get along. - Node[] oldTable = new Node[1]; + Node[] oldTable = new Node[1]; oldTable[0] = node(node("b"), "d", node("f")); Node[] newTable = LinkedHashTreeMap.doubleCapacity(oldTable); @@ -230,8 +256,8 @@ private Node node(String value) { return new Node<>(null, value, value.hashCode(), head, head); } - private Node node(Node left, String value, - Node right) { + private Node node( + Node left, String value, Node right) { Node result = node(value); if (left != null) { result.left = left; diff --git a/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java index c2aaed542..5562e854c 100644 --- a/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/MapJsonAdapterTest.java @@ -15,6 +15,11 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.TestUtil.newReader; +import static com.squareup.moshi.internal.Util.NO_ANNOTATIONS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.io.IOException; import java.lang.reflect.Type; import java.util.AbstractMap.SimpleEntry; @@ -25,15 +30,11 @@ import okio.Buffer; import org.junit.Test; -import static com.squareup.moshi.TestUtil.newReader; -import static com.squareup.moshi.internal.Util.NO_ANNOTATIONS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class MapJsonAdapterTest { private final Moshi moshi = new Moshi.Builder().build(); - @Test public void map() throws Exception { + @Test + public void map() throws Exception { Map map = new LinkedHashMap<>(); map.put("a", true); map.put("b", false); @@ -42,15 +43,17 @@ public final class MapJsonAdapterTest { String toJson = toJson(String.class, Boolean.class, map); assertThat(toJson).isEqualTo("{\"a\":true,\"b\":false,\"c\":null}"); - Map fromJson = fromJson( - String.class, Boolean.class, "{\"a\":true,\"b\":false,\"c\":null}"); - assertThat(fromJson).containsExactly( - new SimpleEntry("a", true), - new SimpleEntry("b", false), - new SimpleEntry("c", null)); + Map fromJson = + fromJson(String.class, Boolean.class, "{\"a\":true,\"b\":false,\"c\":null}"); + assertThat(fromJson) + .containsExactly( + new SimpleEntry("a", true), + new SimpleEntry("b", false), + new SimpleEntry("c", null)); } - @Test public void mapWithNullKeyFailsToEmit() throws Exception { + @Test + public void mapWithNullKeyFailsToEmit() throws Exception { Map map = new LinkedHashMap<>(); map.put(null, true); @@ -62,7 +65,8 @@ public final class MapJsonAdapterTest { } } - @Test public void emptyMap() throws Exception { + @Test + public void emptyMap() throws Exception { Map map = new LinkedHashMap<>(); String toJson = toJson(String.class, Boolean.class, map); @@ -72,7 +76,8 @@ public final class MapJsonAdapterTest { assertThat(fromJson).isEmpty(); } - @Test public void nullMap() throws Exception { + @Test + public void nullMap() throws Exception { JsonAdapter jsonAdapter = mapAdapter(String.class, Boolean.class); Buffer buffer = new Buffer(); @@ -86,7 +91,8 @@ public final class MapJsonAdapterTest { assertThat(jsonAdapter.fromJson(jsonReader)).isEqualTo(null); } - @Test public void covariantValue() throws Exception { + @Test + public void covariantValue() throws Exception { // Important for Kotlin maps, which are all Map. JsonAdapter> jsonAdapter = mapAdapter(String.class, Types.subtypeOf(Object.class)); @@ -107,7 +113,8 @@ public final class MapJsonAdapterTest { assertThat(jsonAdapter.fromJson(jsonReader)).isEqualTo(map); } - @Test public void orderIsRetained() throws Exception { + @Test + public void orderIsRetained() throws Exception { Map map = new LinkedHashMap<>(); map.put("c", 1); map.put("a", 2); @@ -117,13 +124,14 @@ public final class MapJsonAdapterTest { String toJson = toJson(String.class, Integer.class, map); assertThat(toJson).isEqualTo("{\"c\":1,\"a\":2,\"d\":3,\"b\":4}"); - Map fromJson = fromJson( - String.class, Integer.class, "{\"c\":1,\"a\":2,\"d\":3,\"b\":4}"); + Map fromJson = + fromJson(String.class, Integer.class, "{\"c\":1,\"a\":2,\"d\":3,\"b\":4}"); assertThat(new ArrayList(fromJson.keySet())) .isEqualTo(Arrays.asList("c", "a", "d", "b")); } - @Test public void duplicatesAreForbidden() throws Exception { + @Test + public void duplicatesAreForbidden() throws Exception { try { fromJson(String.class, Integer.class, "{\"c\":1,\"c\":2}"); fail(); @@ -133,7 +141,8 @@ public final class MapJsonAdapterTest { } /** This leans on {@code promoteNameToValue} to do the heavy lifting. */ - @Test public void mapWithNonStringKeys() throws Exception { + @Test + public void mapWithNonStringKeys() throws Exception { Map map = new LinkedHashMap<>(); map.put(5, true); map.put(6, false); @@ -142,15 +151,17 @@ public final class MapJsonAdapterTest { String toJson = toJson(Integer.class, Boolean.class, map); assertThat(toJson).isEqualTo("{\"5\":true,\"6\":false,\"7\":null}"); - Map fromJson = fromJson( - Integer.class, Boolean.class, "{\"5\":true,\"6\":false,\"7\":null}"); - assertThat(fromJson).containsExactly( - new SimpleEntry(5, true), - new SimpleEntry(6, false), - new SimpleEntry(7, null)); + Map fromJson = + fromJson(Integer.class, Boolean.class, "{\"5\":true,\"6\":false,\"7\":null}"); + assertThat(fromJson) + .containsExactly( + new SimpleEntry(5, true), + new SimpleEntry(6, false), + new SimpleEntry(7, null)); } - @Test public void mapWithNonStringKeysToJsonObject() { + @Test + public void mapWithNonStringKeysToJsonObject() { Map map = new LinkedHashMap<>(); map.put(5, true); map.put(6, false); @@ -166,7 +177,8 @@ public final class MapJsonAdapterTest { assertThat(jsonAdapter.fromJsonValue(jsonObject)).isEqualTo(map); } - @Test public void booleanKeyTypeHasCoherentErrorMessage() { + @Test + public void booleanKeyTypeHasCoherentErrorMessage() { Map map = new LinkedHashMap<>(); map.put(true, ""); JsonAdapter> adapter = mapAdapter(Boolean.class, String.class); @@ -184,10 +196,10 @@ public final class MapJsonAdapterTest { } } - static final class Key { - } + static final class Key {} - @Test public void objectKeyTypeHasCoherentErrorMessage() { + @Test + public void objectKeyTypeHasCoherentErrorMessage() { Map map = new LinkedHashMap<>(); map.put(new Key(), ""); JsonAdapter> adapter = mapAdapter(Key.class, String.class); @@ -201,12 +213,12 @@ static final class Key { adapter.toJsonValue(map); fail(); } catch (IllegalStateException expected) { - assertThat(expected).hasMessage("Object cannot be " - + "used as a map key in JSON at path $."); + assertThat(expected).hasMessage("Object cannot be " + "used as a map key in JSON at path $."); } } - @Test public void arrayKeyTypeHasCoherentErrorMessage() { + @Test + public void arrayKeyTypeHasCoherentErrorMessage() { Map map = new LinkedHashMap<>(); map.put(new String[0], ""); JsonAdapter> adapter = @@ -236,8 +248,9 @@ private String toJson(Type keyType, Type valueType, Map value) thro @SuppressWarnings("unchecked") // It's the caller's responsibility to make sure K and V match. private JsonAdapter> mapAdapter(Type keyType, Type valueType) { - return (JsonAdapter>) MapJsonAdapter.FACTORY.create( - Types.newParameterizedType(Map.class, keyType, valueType), NO_ANNOTATIONS, moshi); + return (JsonAdapter>) + MapJsonAdapter.FACTORY.create( + Types.newParameterizedType(Map.class, keyType, valueType), NO_ANNOTATIONS, moshi); } private Map fromJson(Type keyType, Type valueType, String json) throws IOException { diff --git a/moshi/src/test/java/com/squareup/moshi/MoshiTest.java b/moshi/src/test/java/com/squareup/moshi/MoshiTest.java index e6f20131b..4e9107aad 100644 --- a/moshi/src/test/java/com/squareup/moshi/MoshiTest.java +++ b/moshi/src/test/java/com/squareup/moshi/MoshiTest.java @@ -15,6 +15,12 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.TestUtil.newReader; +import static com.squareup.moshi.TestUtil.repeat; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import android.util.Pair; import com.squareup.moshi.internal.Util; import java.io.File; @@ -41,15 +47,10 @@ import okio.Buffer; import org.junit.Test; -import static com.squareup.moshi.TestUtil.newReader; -import static com.squareup.moshi.TestUtil.repeat; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - @SuppressWarnings({"CheckReturnValue", "ResultOfMethodCallIgnored"}) public final class MoshiTest { - @Test public void booleanAdapter() throws Exception { + @Test + public void booleanAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(boolean.class).lenient(); assertThat(adapter.fromJson("true")).isTrue(); @@ -74,7 +75,8 @@ public final class MoshiTest { } } - @Test public void BooleanAdapter() throws Exception { + @Test + public void BooleanAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Boolean.class).lenient(); assertThat(adapter.fromJson("true")).isTrue(); @@ -86,7 +88,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void byteAdapter() throws Exception { + @Test + public void byteAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(byte.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo((byte) 1); @@ -132,7 +135,8 @@ public final class MoshiTest { } } - @Test public void ByteAdapter() throws Exception { + @Test + public void ByteAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Byte.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo((byte) 1); @@ -142,7 +146,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void charAdapter() throws Exception { + @Test + public void charAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(char.class).lenient(); assertThat(adapter.fromJson("\"a\"")).isEqualTo('a'); @@ -154,7 +159,7 @@ public final class MoshiTest { final char c = (char) i; String s; switch (c) { - // TODO: make JsonWriter.REPLACEMENT_CHARS visible for testing? + // TODO: make JsonWriter.REPLACEMENT_CHARS visible for testing? case '\"': s = "\\\""; break; @@ -221,7 +226,8 @@ public final class MoshiTest { } } - @Test public void CharacterAdapter() throws Exception { + @Test + public void CharacterAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Character.class).lenient(); assertThat(adapter.fromJson("\"a\"")).isEqualTo('a'); @@ -241,7 +247,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void doubleAdapter() throws Exception { + @Test + public void doubleAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(double.class).lenient(); assertThat(adapter.fromJson("1.0")).isEqualTo(1.0); @@ -297,7 +304,8 @@ public final class MoshiTest { } } - @Test public void DoubleAdapter() throws Exception { + @Test + public void DoubleAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Double.class).lenient(); assertThat(adapter.fromJson("1.0")).isEqualTo(1.0); @@ -309,7 +317,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void floatAdapter() throws Exception { + @Test + public void floatAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(float.class).lenient(); assertThat(adapter.fromJson("1.0")).isEqualTo(1.0f); @@ -365,7 +374,8 @@ public final class MoshiTest { } } - @Test public void FloatAdapter() throws Exception { + @Test + public void FloatAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Float.class).lenient(); assertThat(adapter.fromJson("1.0")).isEqualTo(1.0f); @@ -377,7 +387,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void intAdapter() throws Exception { + @Test + public void intAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(int.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo(1); @@ -418,7 +429,8 @@ public final class MoshiTest { } } - @Test public void IntegerAdapter() throws Exception { + @Test + public void IntegerAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Integer.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo(1); @@ -428,7 +440,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void longAdapter() throws Exception { + @Test + public void longAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(long.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo(1L); @@ -469,7 +482,8 @@ public final class MoshiTest { } } - @Test public void LongAdapter() throws Exception { + @Test + public void LongAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Long.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo(1L); @@ -479,7 +493,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void shortAdapter() throws Exception { + @Test + public void shortAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(short.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo((short) 1); @@ -520,7 +535,8 @@ public final class MoshiTest { } } - @Test public void ShortAdapter() throws Exception { + @Test + public void ShortAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Short.class).lenient(); assertThat(adapter.fromJson("1")).isEqualTo((short) 1); @@ -530,7 +546,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void stringAdapter() throws Exception { + @Test + public void stringAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(String.class).lenient(); assertThat(adapter.fromJson("\"a\"")).isEqualTo("a"); @@ -539,7 +556,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void upperBoundedWildcardsAreHandled() throws Exception { + @Test + public void upperBoundedWildcardsAreHandled() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Types.subtypeOf(String.class)); assertThat(adapter.fromJson("\"a\"")).isEqualTo("a"); @@ -548,7 +566,8 @@ public final class MoshiTest { assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void lowerBoundedWildcardsAreNotHandled() { + @Test + public void lowerBoundedWildcardsAreNotHandled() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(Types.supertypeOf(String.class)); @@ -558,7 +577,8 @@ public final class MoshiTest { } } - @Test public void addNullFails() throws Exception { + @Test + public void addNullFails() throws Exception { Type type = Object.class; Class annotation = Annotation.class; Moshi.Builder builder = new Moshi.Builder(); @@ -606,10 +626,9 @@ public final class MoshiTest { } } - @Test public void customJsonAdapter() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(Pizza.class, new PizzaAdapter()) - .build(); + @Test + public void customJsonAdapter() throws Exception { + Moshi moshi = new Moshi.Builder().add(Pizza.class, new PizzaAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(Pizza.class); assertThat(jsonAdapter.toJson(new Pizza(15, true))) @@ -618,7 +637,8 @@ public final class MoshiTest { .isEqualTo(new Pizza(18, true)); } - @Test public void classAdapterToObjectAndFromObject() throws Exception { + @Test + public void classAdapterToObjectAndFromObject() throws Exception { Moshi moshi = new Moshi.Builder().build(); Pizza pizza = new Pizza(15, true); @@ -632,10 +652,9 @@ public final class MoshiTest { assertThat(jsonAdapter.fromJsonValue(pizzaObject)).isEqualTo(pizza); } - @Test public void customJsonAdapterToObjectAndFromObject() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(Pizza.class, new PizzaAdapter()) - .build(); + @Test + public void customJsonAdapterToObjectAndFromObject() throws Exception { + Moshi moshi = new Moshi.Builder().add(Pizza.class, new PizzaAdapter()).build(); Pizza pizza = new Pizza(15, true); @@ -648,19 +667,18 @@ public final class MoshiTest { assertThat(jsonAdapter.fromJsonValue(pizzaObject)).isEqualTo(pizza); } - @Test public void indent() throws Exception { + @Test + public void indent() throws Exception { Moshi moshi = new Moshi.Builder().add(Pizza.class, new PizzaAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(Pizza.class); Pizza pizza = new Pizza(15, true); - assertThat(jsonAdapter.indent(" ").toJson(pizza)).isEqualTo("" - + "{\n" - + " \"size\": 15,\n" - + " \"extra cheese\": true\n" - + "}"); + assertThat(jsonAdapter.indent(" ").toJson(pizza)) + .isEqualTo("" + "{\n" + " \"size\": 15,\n" + " \"extra cheese\": true\n" + "}"); } - @Test public void unindent() throws Exception { + @Test + public void unindent() throws Exception { Moshi moshi = new Moshi.Builder().add(Pizza.class, new PizzaAdapter()).build(); JsonAdapter jsonAdapter = moshi.adapter(Pizza.class); @@ -677,18 +695,17 @@ public final class MoshiTest { // Indentation changes only apply to their use. jsonAdapter.toJson(writer, pizza); - assertThat(buffer.readUtf8()).isEqualTo("" - + "{\n" - + " \"size\": 15,\n" - + " \"extra cheese\": true\n" - + "}"); + assertThat(buffer.readUtf8()) + .isEqualTo("" + "{\n" + " \"size\": 15,\n" + " \"extra cheese\": true\n" + "}"); } - @Test public void composingJsonAdapterFactory() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new MealDealAdapterFactory()) - .add(Pizza.class, new PizzaAdapter()) - .build(); + @Test + public void composingJsonAdapterFactory() throws Exception { + Moshi moshi = + new Moshi.Builder() + .add(new MealDealAdapterFactory()) + .add(Pizza.class, new PizzaAdapter()) + .build(); JsonAdapter jsonAdapter = moshi.adapter(MealDeal.class); assertThat(jsonAdapter.toJson(new MealDeal(new Pizza(15, true), "Pepsi"))) @@ -702,20 +719,22 @@ static class Message { @Uppercase String shout; } - @Test public void registerJsonAdapterForAnnotatedType() throws Exception { - JsonAdapter uppercaseAdapter = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - throw new AssertionError(); - } + @Test + public void registerJsonAdapterForAnnotatedType() throws Exception { + JsonAdapter uppercaseAdapter = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + throw new AssertionError(); + } - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value(value.toUpperCase(Locale.US)); - } - }; + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value(value.toUpperCase(Locale.US)); + } + }; - Moshi moshi = new Moshi.Builder() - .add(String.class, Uppercase.class, uppercaseAdapter) - .build(); + Moshi moshi = new Moshi.Builder().add(String.class, Uppercase.class, uppercaseAdapter).build(); JsonAdapter messageAdapter = moshi.adapter(Message.class); @@ -727,7 +746,8 @@ static class Message { .isEqualTo("{\"shout\":\"WHAT'S UP\",\"speak\":\"Yo dog\"}"); } - @Test public void adapterLookupDisallowsNullType() { + @Test + public void adapterLookupDisallowsNullType() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(null, Collections.emptySet()); @@ -737,7 +757,8 @@ static class Message { } } - @Test public void adapterLookupDisallowsNullAnnotations() { + @Test + public void adapterLookupDisallowsNullAnnotations() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(String.class, (Class) null); @@ -753,14 +774,17 @@ static class Message { } } - @Test public void nextJsonAdapterDisallowsNullAnnotations() throws Exception { - JsonAdapter.Factory badFactory = new JsonAdapter.Factory() { - @Nullable @Override - public JsonAdapter create(Type type, Set annotations, - Moshi moshi) { - return moshi.nextAdapter(this, type, null); - } - }; + @Test + public void nextJsonAdapterDisallowsNullAnnotations() throws Exception { + JsonAdapter.Factory badFactory = + new JsonAdapter.Factory() { + @Nullable + @Override + public JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + return moshi.nextAdapter(this, type, null); + } + }; Moshi moshi = new Moshi.Builder().add(badFactory).build(); try { moshi.adapter(Object.class); @@ -770,13 +794,11 @@ public JsonAdapter create(Type type, Set annotations, } } - @Uppercase - static String uppercaseString; + @Uppercase static String uppercaseString; - @Test public void delegatingJsonAdapterFactory() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new UppercaseAdapterFactory()) - .build(); + @Test + public void delegatingJsonAdapterFactory() throws Exception { + Moshi moshi = new Moshi.Builder().add(new UppercaseAdapterFactory()).build(); Field uppercaseString = MoshiTest.class.getDeclaredField("uppercaseString"); Set annotations = Util.jsonAnnotations(uppercaseString); @@ -785,7 +807,8 @@ public JsonAdapter create(Type type, Set annotations, assertThat(adapter.fromJson("\"b\"")).isEqualTo("B"); } - @Test public void listJsonAdapter() throws Exception { + @Test + public void listJsonAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter> adapter = moshi.adapter(Types.newParameterizedType(List.class, String.class)); @@ -793,7 +816,8 @@ public JsonAdapter create(Type type, Set annotations, assertThat(adapter.fromJson("[\"a\",\"b\"]")).isEqualTo(Arrays.asList("a", "b")); } - @Test public void setJsonAdapter() throws Exception { + @Test + public void setJsonAdapter() throws Exception { Set set = new LinkedHashSet<>(); set.add("a"); set.add("b"); @@ -805,7 +829,8 @@ public JsonAdapter create(Type type, Set annotations, assertThat(adapter.fromJson("[\"a\",\"b\"]")).isEqualTo(set); } - @Test public void collectionJsonAdapter() throws Exception { + @Test + public void collectionJsonAdapter() throws Exception { Collection collection = new ArrayDeque<>(); collection.add("a"); collection.add("b"); @@ -817,79 +842,87 @@ public JsonAdapter create(Type type, Set annotations, assertThat(adapter.fromJson("[\"a\",\"b\"]")).containsExactly("a", "b"); } - @Uppercase - static List uppercaseStrings; + @Uppercase static List uppercaseStrings; - @Test public void collectionsDoNotKeepAnnotations() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(new UppercaseAdapterFactory()) - .build(); + @Test + public void collectionsDoNotKeepAnnotations() throws Exception { + Moshi moshi = new Moshi.Builder().add(new UppercaseAdapterFactory()).build(); Field uppercaseStringsField = MoshiTest.class.getDeclaredField("uppercaseStrings"); try { - moshi.adapter(uppercaseStringsField.getGenericType(), - Util.jsonAnnotations(uppercaseStringsField)); + moshi.adapter( + uppercaseStringsField.getGenericType(), Util.jsonAnnotations(uppercaseStringsField)); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("No JsonAdapter for java.util.List " - + "annotated [@com.squareup.moshi.MoshiTest$Uppercase()]"); + assertThat(expected) + .hasMessage( + "No JsonAdapter for java.util.List " + + "annotated [@com.squareup.moshi.MoshiTest$Uppercase()]"); } } - @Test public void noTypeAdapterForQualifiedPlatformType() throws Exception { + @Test + public void noTypeAdapterForQualifiedPlatformType() throws Exception { Moshi moshi = new Moshi.Builder().build(); Field uppercaseStringField = MoshiTest.class.getDeclaredField("uppercaseString"); try { - moshi.adapter(uppercaseStringField.getGenericType(), - Util.jsonAnnotations(uppercaseStringField)); + moshi.adapter( + uppercaseStringField.getGenericType(), Util.jsonAnnotations(uppercaseStringField)); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage("No JsonAdapter for class java.lang.String " - + "annotated [@com.squareup.moshi.MoshiTest$Uppercase()]"); + assertThat(expected) + .hasMessage( + "No JsonAdapter for class java.lang.String " + + "annotated [@com.squareup.moshi.MoshiTest$Uppercase()]"); } } - @Test public void objectArray() throws Exception { + @Test + public void objectArray() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(String[].class); assertThat(adapter.toJson(new String[] {"a", "b"})).isEqualTo("[\"a\",\"b\"]"); assertThat(adapter.fromJson("[\"a\",\"b\"]")).containsExactly("a", "b"); } - @Test public void primitiveArray() throws Exception { + @Test + public void primitiveArray() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(int[].class); - assertThat(adapter.toJson(new int[] { 1, 2 })).isEqualTo("[1,2]"); + assertThat(adapter.toJson(new int[] {1, 2})).isEqualTo("[1,2]"); assertThat(adapter.fromJson("[2,3]")).containsExactly(2, 3); } - @Test public void enumAdapter() throws Exception { + @Test + public void enumAdapter() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Roshambo.class).lenient(); assertThat(adapter.fromJson("\"ROCK\"")).isEqualTo(Roshambo.ROCK); assertThat(adapter.toJson(Roshambo.PAPER)).isEqualTo("\"PAPER\""); } - @Test public void annotatedEnum() throws Exception { + @Test + public void annotatedEnum() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Roshambo.class).lenient(); assertThat(adapter.fromJson("\"scr\"")).isEqualTo(Roshambo.SCISSORS); assertThat(adapter.toJson(Roshambo.SCISSORS)).isEqualTo("\"scr\""); } - @Test public void invalidEnum() throws Exception { + @Test + public void invalidEnum() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Roshambo.class); try { adapter.fromJson("\"SPOCK\""); 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 $"); } } - @Test public void invalidEnumHasCorrectPathInExceptionMessage() throws Exception { + @Test + public void invalidEnumHasCorrectPathInExceptionMessage() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Roshambo.class); JsonReader reader = JsonReader.of(new Buffer().writeUtf8("[\"SPOCK\"]")); @@ -898,21 +931,23 @@ public JsonAdapter create(Type type, Set annotations, adapter.fromJson(reader); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Expected one of [ROCK, PAPER, scr] but was SPOCK at path $[0]"); + assertThat(expected) + .hasMessage("Expected one of [ROCK, PAPER, scr] but was SPOCK at path $[0]"); } reader.endArray(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); } - @Test public void nullEnum() throws Exception { + @Test + public void nullEnum() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Roshambo.class).lenient(); assertThat(adapter.fromJson("null")).isNull(); assertThat(adapter.toJson(null)).isEqualTo("null"); } - @Test public void byDefaultUnknownFieldsAreIgnored() throws Exception { + @Test + public void byDefaultUnknownFieldsAreIgnored() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Pizza.class); Pizza pizza = adapter.fromJson("{\"diameter\":5,\"crust\":\"thick\",\"extraCheese\":true}"); @@ -920,7 +955,8 @@ public JsonAdapter create(Type type, Set annotations, assertThat(pizza.extraCheese).isEqualTo(true); } - @Test public void failOnUnknownThrowsOnUnknownFields() throws Exception { + @Test + public void failOnUnknownThrowsOnUnknownFields() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Pizza.class).failOnUnknown(); try { @@ -931,68 +967,81 @@ public JsonAdapter create(Type type, Set annotations, } } - @Test public void platformTypeThrows() throws IOException { + @Test + public void platformTypeThrows() throws IOException { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(File.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage( - "Platform class java.io.File requires explicit JsonAdapter to be registered"); + assertThat(e) + .hasMessage("Platform class java.io.File requires explicit JsonAdapter to be registered"); } try { moshi.adapter(KeyGenerator.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("Platform class javax.crypto.KeyGenerator requires explicit " - + "JsonAdapter to be registered"); + assertThat(e) + .hasMessage( + "Platform class javax.crypto.KeyGenerator requires explicit " + + "JsonAdapter to be registered"); } try { moshi.adapter(Pair.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage( - "Platform class android.util.Pair requires explicit JsonAdapter to be registered"); + assertThat(e) + .hasMessage( + "Platform class android.util.Pair requires explicit JsonAdapter to be registered"); } } - @Test public void collectionClassesHaveClearErrorMessage() { + @Test + public void collectionClassesHaveClearErrorMessage() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(Types.newParameterizedType(ArrayList.class, String.class)); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("No JsonAdapter for " - + "java.util.ArrayList, " - + "you should probably use List instead of ArrayList " - + "(Moshi only supports the collection interfaces by default) " - + "or else register a custom JsonAdapter."); + assertThat(e) + .hasMessage( + "No JsonAdapter for " + + "java.util.ArrayList, " + + "you should probably use List instead of ArrayList " + + "(Moshi only supports the collection interfaces by default) " + + "or else register a custom JsonAdapter."); } try { moshi.adapter(Types.newParameterizedType(HashMap.class, String.class, String.class)); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("No JsonAdapter for " - + "java.util.HashMap, " - + "you should probably use Map instead of HashMap " - + "(Moshi only supports the collection interfaces by default) " - + "or else register a custom JsonAdapter."); - } - } - - @Test public void noCollectionErrorIfAdapterExplicitlyProvided() { - Moshi moshi = new Moshi.Builder() - .add(new JsonAdapter.Factory() { - @Override public JsonAdapter create(Type type, Set annotations, - Moshi moshi) { - return new MapJsonAdapter(moshi, String.class, String.class); - } - }) - .build(); - - JsonAdapter> adapter = moshi.adapter( - Types.newParameterizedType(HashMap.class, String.class, String.class)); + assertThat(e) + .hasMessage( + "No JsonAdapter for " + + "java.util.HashMap, " + + "you should probably use Map instead of HashMap " + + "(Moshi only supports the collection interfaces by default) " + + "or else register a custom JsonAdapter."); + } + } + + @Test + public void noCollectionErrorIfAdapterExplicitlyProvided() { + Moshi moshi = + new Moshi.Builder() + .add( + new JsonAdapter.Factory() { + @Override + public JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + return new MapJsonAdapter(moshi, String.class, String.class); + } + }) + .build(); + + JsonAdapter> adapter = + moshi.adapter(Types.newParameterizedType(HashMap.class, String.class, String.class)); assertThat(adapter).isInstanceOf(MapJsonAdapter.class); } @@ -1008,63 +1057,73 @@ static final class ListWrapper { } } - @Test public void reentrantFieldErrorMessagesTopLevelMap() { + @Test + public void reentrantFieldErrorMessagesTopLevelMap() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(Types.newParameterizedType(Map.class, String.class, HasPlatformType.class)); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage( - "Platform class java.util.UUID requires explicit " - + "JsonAdapter to be registered" - + "\nfor class java.util.UUID uuid" - + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType" - + "\nfor java.util.Map"); + assertThat(e) + .hasMessage( + "Platform class java.util.UUID requires explicit " + + "JsonAdapter to be registered" + + "\nfor class java.util.UUID uuid" + + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType" + + "\nfor java.util.Map"); assertThat(e).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(e.getCause()).hasMessage("Platform class java.util.UUID " - + "requires explicit JsonAdapter to be registered"); + assertThat(e.getCause()) + .hasMessage( + "Platform class java.util.UUID " + "requires explicit JsonAdapter to be registered"); } } - @Test public void reentrantFieldErrorMessagesWrapper() { + @Test + public void reentrantFieldErrorMessagesWrapper() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(HasPlatformType.Wrapper.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage( - "Platform class java.util.UUID requires explicit " - + "JsonAdapter to be registered" - + "\nfor class java.util.UUID uuid" - + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType hasPlatformType" - + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType$Wrapper"); + assertThat(e) + .hasMessage( + "Platform class java.util.UUID requires explicit " + + "JsonAdapter to be registered" + + "\nfor class java.util.UUID uuid" + + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType hasPlatformType" + + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType$Wrapper"); assertThat(e).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(e.getCause()).hasMessage("Platform class java.util.UUID " - + "requires explicit JsonAdapter to be registered"); + assertThat(e.getCause()) + .hasMessage( + "Platform class java.util.UUID " + "requires explicit JsonAdapter to be registered"); } } - @Test public void reentrantFieldErrorMessagesListWrapper() { + @Test + public void reentrantFieldErrorMessagesListWrapper() { Moshi moshi = new Moshi.Builder().build(); try { moshi.adapter(HasPlatformType.ListWrapper.class); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage( - "Platform class java.util.UUID requires explicit " - + "JsonAdapter to be registered" - + "\nfor class java.util.UUID uuid" - + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType" - + "\nfor java.util.List platformTypes" - + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType$ListWrapper"); + assertThat(e) + .hasMessage( + "Platform class java.util.UUID requires explicit " + + "JsonAdapter to be registered" + + "\nfor class java.util.UUID uuid" + + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType" + + "\nfor java.util.List platformTypes" + + "\nfor class com.squareup.moshi.MoshiTest$HasPlatformType$ListWrapper"); assertThat(e).hasCauseExactlyInstanceOf(IllegalArgumentException.class); - assertThat(e.getCause()).hasMessage("Platform class java.util.UUID " - + "requires explicit JsonAdapter to be registered"); + assertThat(e.getCause()) + .hasMessage( + "Platform class java.util.UUID " + "requires explicit JsonAdapter to be registered"); } } - @Test public void qualifierWithElementsMayNotBeDirectlyRegistered() throws IOException { + @Test + public void qualifierWithElementsMayNotBeDirectlyRegistered() throws IOException { try { new Moshi.Builder() .add(Boolean.class, Localized.class, StandardJsonAdapters.BOOLEAN_JSON_ADAPTER); @@ -1074,10 +1133,9 @@ static final class ListWrapper { } } - @Test public void qualifierWithElements() throws IOException { - Moshi moshi = new Moshi.Builder() - .add(LocalizedBooleanAdapter.FACTORY) - .build(); + @Test + public void qualifierWithElements() throws IOException { + Moshi moshi = new Moshi.Builder().add(LocalizedBooleanAdapter.FACTORY).build(); Baguette baguette = new Baguette(); baguette.avecBeurre = true; @@ -1093,34 +1151,42 @@ static final class ListWrapper { } /** Note that this is the opposite of Gson's behavior, where later adapters are preferred. */ - @Test public void adaptersRegisteredInOrderOfPrecedence() throws Exception { - JsonAdapter adapter1 = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - throw new AssertionError(); - } - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value("one!"); - } - }; + @Test + public void adaptersRegisteredInOrderOfPrecedence() throws Exception { + JsonAdapter adapter1 = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + throw new AssertionError(); + } - JsonAdapter adapter2 = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - throw new AssertionError(); - } - @Override public void toJson(JsonWriter writer, String value) throws IOException { - writer.value("two!"); - } - }; + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value("one!"); + } + }; + + JsonAdapter adapter2 = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + throw new AssertionError(); + } + + @Override + public void toJson(JsonWriter writer, String value) throws IOException { + writer.value("two!"); + } + }; - Moshi moshi = new Moshi.Builder() - .add(String.class, adapter1) - .add(String.class, adapter2) - .build(); + Moshi moshi = + new Moshi.Builder().add(String.class, adapter1).add(String.class, adapter2).build(); JsonAdapter adapter = moshi.adapter(String.class).lenient(); assertThat(adapter.toJson("a")).isEqualTo("\"one!\""); } - @Test public void cachingJsonAdapters() throws Exception { + @Test + public void cachingJsonAdapters() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter1 = moshi.adapter(MealDeal.class); @@ -1128,17 +1194,17 @@ static final class ListWrapper { assertThat(adapter1).isSameAs(adapter2); } - @Test public void newBuilder() throws Exception { - Moshi moshi = new Moshi.Builder() - .add(Pizza.class, new PizzaAdapter()) - .build(); + @Test + public void newBuilder() throws Exception { + Moshi moshi = new Moshi.Builder().add(Pizza.class, new PizzaAdapter()).build(); Moshi.Builder newBuilder = moshi.newBuilder(); for (JsonAdapter.Factory factory : Moshi.BUILT_IN_FACTORIES) { assertThat(factory).isNotIn(newBuilder.factories); } } - @Test public void referenceCyclesOnArrays() throws Exception { + @Test + public void referenceCyclesOnArrays() throws Exception { Moshi moshi = new Moshi.Builder().build(); Map map = new LinkedHashMap<>(); map.put("a", map); @@ -1146,12 +1212,13 @@ static final class ListWrapper { moshi.adapter(Object.class).toJson(map); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage("Nesting too deep at $" - + repeat(".a", 255) + ": circular reference?"); + assertThat(expected) + .hasMessage("Nesting too deep at $" + repeat(".a", 255) + ": circular reference?"); } } - @Test public void referenceCyclesOnObjects() throws Exception { + @Test + public void referenceCyclesOnObjects() throws Exception { Moshi moshi = new Moshi.Builder().build(); List list = new ArrayList<>(); list.add(list); @@ -1159,12 +1226,13 @@ static final class ListWrapper { moshi.adapter(Object.class).toJson(list); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage("Nesting too deep at $" - + repeat("[0]", 255) + ": circular reference?"); + assertThat(expected) + .hasMessage("Nesting too deep at $" + repeat("[0]", 255) + ": circular reference?"); } } - @Test public void referenceCyclesOnMixedTypes() throws Exception { + @Test + public void referenceCyclesOnMixedTypes() throws Exception { Moshi moshi = new Moshi.Builder().build(); List list = new ArrayList<>(); Map map = new LinkedHashMap<>(); @@ -1174,12 +1242,13 @@ static final class ListWrapper { moshi.adapter(Object.class).toJson(list); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage("Nesting too deep at $[0]" - + repeat(".a[0]", 127) + ": circular reference?"); + assertThat(expected) + .hasMessage("Nesting too deep at $[0]" + repeat(".a[0]", 127) + ": circular reference?"); } } - @Test public void duplicateKeyDisallowedInObjectType() throws Exception { + @Test + public void duplicateKeyDisallowedInObjectType() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); String json = "{\"diameter\":5,\"diameter\":5,\"extraCheese\":true}"; @@ -1187,12 +1256,13 @@ static final class ListWrapper { adapter.fromJson(json); fail(); } catch (JsonDataException expected) { - assertThat(expected).hasMessage( - "Map key 'diameter' has multiple values at path $.diameter: 5.0 and 5.0"); + assertThat(expected) + .hasMessage("Map key 'diameter' has multiple values at path $.diameter: 5.0 and 5.0"); } } - @Test public void duplicateKeysAllowedInCustomType() throws Exception { + @Test + public void duplicateKeysAllowedInCustomType() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Pizza.class); String json = "{\"diameter\":5,\"diameter\":5,\"extraCheese\":true}"; @@ -1208,13 +1278,15 @@ static class Pizza { this.extraCheese = extraCheese; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof Pizza && ((Pizza) o).diameter == diameter && ((Pizza) o).extraCheese == extraCheese; } - @Override public int hashCode() { + @Override + public int hashCode() { return diameter * (extraCheese ? 31 : 1); } } @@ -1228,19 +1300,22 @@ static class MealDeal { this.drink = drink; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof MealDeal && ((MealDeal) o).pizza.equals(pizza) && ((MealDeal) o).drink.equals(drink); } - @Override public int hashCode() { + @Override + public int hashCode() { return pizza.hashCode() + (31 * drink.hashCode()); } } static class PizzaAdapter extends JsonAdapter { - @Override public Pizza fromJson(JsonReader reader) throws IOException { + @Override + public Pizza fromJson(JsonReader reader) throws IOException { int diameter = 13; boolean extraCheese = false; reader.beginObject(); @@ -1258,7 +1333,8 @@ static class PizzaAdapter extends JsonAdapter { return new Pizza(diameter, extraCheese); } - @Override public void toJson(JsonWriter writer, Pizza value) throws IOException { + @Override + public void toJson(JsonWriter writer, Pizza value) throws IOException { writer.beginObject(); writer.name("size").value(value.diameter); writer.name("extra cheese").value(value.extraCheese); @@ -1267,13 +1343,14 @@ static class PizzaAdapter extends JsonAdapter { } static class MealDealAdapterFactory implements JsonAdapter.Factory { - @Override public JsonAdapter create( - Type type, Set annotations, Moshi moshi) { + @Override + public JsonAdapter create(Type type, Set annotations, Moshi moshi) { if (!type.equals(MealDeal.class)) return null; final JsonAdapter pizzaAdapter = moshi.adapter(Pizza.class); final JsonAdapter drinkAdapter = moshi.adapter(String.class); return new JsonAdapter() { - @Override public MealDeal fromJson(JsonReader reader) throws IOException { + @Override + public MealDeal fromJson(JsonReader reader) throws IOException { reader.beginArray(); Pizza pizza = pizzaAdapter.fromJson(reader); String drink = drinkAdapter.fromJson(reader); @@ -1281,7 +1358,8 @@ static class MealDealAdapterFactory implements JsonAdapter.Factory { return new MealDeal(pizza, drink); } - @Override public void toJson(JsonWriter writer, MealDeal value) throws IOException { + @Override + public void toJson(JsonWriter writer, MealDeal value) throws IOException { writer.beginArray(); pizzaAdapter.toJson(writer, value.pizza); drinkAdapter.toJson(writer, value.drink); @@ -1293,24 +1371,25 @@ static class MealDealAdapterFactory implements JsonAdapter.Factory { @Retention(RUNTIME) @JsonQualifier - public @interface Uppercase { - } + public @interface Uppercase {} static class UppercaseAdapterFactory implements JsonAdapter.Factory { - @Override public JsonAdapter create( - Type type, Set annotations, Moshi moshi) { + @Override + public JsonAdapter create(Type type, Set annotations, Moshi moshi) { if (!type.equals(String.class)) return null; if (!Util.isAnnotationPresent(annotations, Uppercase.class)) return null; - final JsonAdapter stringAdapter - = moshi.nextAdapter(this, String.class, Util.NO_ANNOTATIONS); + final JsonAdapter stringAdapter = + moshi.nextAdapter(this, String.class, Util.NO_ANNOTATIONS); return new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { + @Override + public String fromJson(JsonReader reader) throws IOException { String s = stringAdapter.fromJson(reader); return s.toUpperCase(Locale.US); } - @Override public void toJson(JsonWriter writer, String value) throws IOException { + @Override + public void toJson(JsonWriter writer, String value) throws IOException { stringAdapter.toJson(writer, value.toUpperCase()); } }; @@ -1320,7 +1399,8 @@ static class UppercaseAdapterFactory implements JsonAdapter.Factory { enum Roshambo { ROCK, PAPER, - @Json(name = "scr") SCISSORS + @Json(name = "scr") + SCISSORS } @Retention(RUNTIME) @@ -1330,24 +1410,29 @@ enum Roshambo { } static class Baguette { - @Localized("en") boolean withButter; - @Localized("fr") boolean avecBeurre; + @Localized("en") + boolean withButter; + + @Localized("fr") + boolean avecBeurre; } static class LocalizedBooleanAdapter extends JsonAdapter { - private static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() { - @Override public JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - if (type == boolean.class) { - for (Annotation annotation : annotations) { - if (annotation instanceof Localized) { - return new LocalizedBooleanAdapter(((Localized) annotation).value()); + private static final JsonAdapter.Factory FACTORY = + new JsonAdapter.Factory() { + @Override + public JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + if (type == boolean.class) { + for (Annotation annotation : annotations) { + if (annotation instanceof Localized) { + return new LocalizedBooleanAdapter(((Localized) annotation).value()); + } + } } + return null; } - } - return null; - } - }; + }; private final String trueString; private final String falseString; @@ -1362,11 +1447,13 @@ public LocalizedBooleanAdapter(String language) { } } - @Override public Boolean fromJson(JsonReader reader) throws IOException { + @Override + public Boolean fromJson(JsonReader reader) throws IOException { return reader.nextString().equals(trueString); } - @Override public void toJson(JsonWriter writer, Boolean value) throws IOException { + @Override + public void toJson(JsonWriter writer, Boolean value) throws IOException { writer.value(value ? trueString : falseString); } } diff --git a/moshi/src/test/java/com/squareup/moshi/ObjectAdapterTest.java b/moshi/src/test/java/com/squareup/moshi/ObjectAdapterTest.java index 993539f40..d1cd6e204 100644 --- a/moshi/src/test/java/com/squareup/moshi/ObjectAdapterTest.java +++ b/moshi/src/test/java/com/squareup/moshi/ObjectAdapterTest.java @@ -15,6 +15,10 @@ */ package com.squareup.moshi; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; + import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -35,15 +39,11 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nullable; -import org.junit.Ignore; import org.junit.Test; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static org.assertj.core.api.Assertions.assertThat; - public final class ObjectAdapterTest { - @Test public void toJsonUsesRuntimeType() { + @Test + public void toJsonUsesRuntimeType() { Delivery delivery = new Delivery(); delivery.address = "1455 Market St."; Pizza pizza = new Pizza(); @@ -53,22 +53,26 @@ public final class ObjectAdapterTest { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); - assertThat(adapter.toJson(delivery)).isEqualTo("{" - + "\"address\":\"1455 Market St.\"," - + "\"items\":[" - + "{\"diameter\":12,\"extraCheese\":true}," - + "\"Pepsi\"" - + "]" - + "}"); + assertThat(adapter.toJson(delivery)) + .isEqualTo( + "{" + + "\"address\":\"1455 Market St.\"," + + "\"items\":[" + + "{\"diameter\":12,\"extraCheese\":true}," + + "\"Pepsi\"" + + "]" + + "}"); } - @Test public void toJsonJavaLangObject() { + @Test + public void toJsonJavaLangObject() { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.toJson(new Object())).isEqualTo("{}"); } - @Test public void fromJsonReturnsMapsAndLists() throws Exception { + @Test + public void fromJsonReturnsMapsAndLists() throws Exception { Map delivery = new LinkedHashMap<>(); delivery.put("address", "1455 Market St."); Map pizza = new LinkedHashMap<>(); @@ -78,102 +82,126 @@ public final class ObjectAdapterTest { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); - assertThat(adapter.fromJson("{" - + "\"address\":\"1455 Market St.\"," - + "\"items\":[" - + "{\"diameter\":12,\"extraCheese\":true}," - + "\"Pepsi\"" - + "]" - + "}")).isEqualTo(delivery); + assertThat( + adapter.fromJson( + "{" + + "\"address\":\"1455 Market St.\"," + + "\"items\":[" + + "{\"diameter\":12,\"extraCheese\":true}," + + "\"Pepsi\"" + + "]" + + "}")) + .isEqualTo(delivery); } - @Test public void fromJsonUsesDoublesForNumbers() throws Exception { + @Test + public void fromJsonUsesDoublesForNumbers() throws Exception { Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.fromJson("[0, 1]")).isEqualTo(Arrays.asList(0d, 1d)); } - @Test public void fromJsonDoesNotFailOnNullValues() throws Exception { + @Test + public void fromJsonDoesNotFailOnNullValues() throws Exception { Map emptyDelivery = new LinkedHashMap<>(); emptyDelivery.put("address", null); emptyDelivery.put("items", null); Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); - assertThat(adapter.fromJson("{\"address\":null, \"items\":null}")) - .isEqualTo(emptyDelivery); + assertThat(adapter.fromJson("{\"address\":null, \"items\":null}")).isEqualTo(emptyDelivery); } - @Test public void toJsonCoercesRuntimeTypeForCollections() { - Collection collection = new AbstractCollection() { - @Override public Iterator iterator() { - return Collections.singleton("A").iterator(); - } - @Override public int size() { - return 1; - } - }; + @Test + public void toJsonCoercesRuntimeTypeForCollections() { + Collection collection = + new AbstractCollection() { + @Override + public Iterator iterator() { + return Collections.singleton("A").iterator(); + } + + @Override + public int size() { + return 1; + } + }; Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.toJson(collection)).isEqualTo("[\"A\"]"); } - @Test public void toJsonCoercesRuntimeTypeForLists() { - List list = new AbstractList() { - @Override public String get(int i) { - return "A"; - } + @Test + public void toJsonCoercesRuntimeTypeForLists() { + List list = + new AbstractList() { + @Override + public String get(int i) { + return "A"; + } - @Override public int size() { - return 1; - } - }; + @Override + public int size() { + return 1; + } + }; Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.toJson(list)).isEqualTo("[\"A\"]"); } - @Test public void toJsonCoercesRuntimeTypeForSets() { - Set set = new AbstractSet() { - @Override public Iterator iterator() { - return Collections.singleton("A").iterator(); - } - @Override public int size() { - return 1; - } - }; + @Test + public void toJsonCoercesRuntimeTypeForSets() { + Set set = + new AbstractSet() { + @Override + public Iterator iterator() { + return Collections.singleton("A").iterator(); + } + + @Override + public int size() { + return 1; + } + }; Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.toJson(set)).isEqualTo("[\"A\"]"); } - @Test public void toJsonCoercesRuntimeTypeForMaps() { - Map map = new AbstractMap() { - @Override public Set> entrySet() { - return Collections.singletonMap("A", true).entrySet(); - } - }; + @Test + public void toJsonCoercesRuntimeTypeForMaps() { + Map map = + new AbstractMap() { + @Override + public Set> entrySet() { + return Collections.singletonMap("A", true).entrySet(); + } + }; Moshi moshi = new Moshi.Builder().build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.toJson(map)).isEqualTo("{\"A\":true}"); } - @Test public void toJsonUsesTypeAdapters() { - Object dateAdapter = new Object() { - @ToJson Long dateToJson(Date d) { - return d.getTime(); - } - @FromJson Date dateFromJson(Long millis) { - return new Date(millis); - } - }; - Moshi moshi = new Moshi.Builder() - .add(dateAdapter) - .build(); + @Test + public void toJsonUsesTypeAdapters() { + Object dateAdapter = + new Object() { + @ToJson + Long dateToJson(Date d) { + return d.getTime(); + } + + @FromJson + Date dateFromJson(Long millis) { + return new Date(millis); + } + }; + Moshi moshi = new Moshi.Builder().add(dateAdapter).build(); JsonAdapter adapter = moshi.adapter(Object.class); assertThat(adapter.toJson(Arrays.asList(new Date(1), new Date(2)))).isEqualTo("[1,2]"); } @@ -182,23 +210,25 @@ public final class ObjectAdapterTest { * Confirm that the built-in adapter for Object delegates to user-supplied adapters for JSON value * types like strings. */ - @Test public void objectAdapterDelegatesStringNamesAndValues() throws Exception { - JsonAdapter stringAdapter = new JsonAdapter() { - @Override public String fromJson(JsonReader reader) throws IOException { - return reader.nextString().toUpperCase(Locale.US); - } - - @Override public void toJson(JsonWriter writer, @Nullable String value) { - throw new UnsupportedOperationException(); - } - }; - - Moshi moshi = new Moshi.Builder() - .add(String.class, stringAdapter) - .build(); + @Test + public void objectAdapterDelegatesStringNamesAndValues() throws Exception { + JsonAdapter stringAdapter = + new JsonAdapter() { + @Override + public String fromJson(JsonReader reader) throws IOException { + return reader.nextString().toUpperCase(Locale.US); + } + + @Override + public void toJson(JsonWriter writer, @Nullable String value) { + throw new UnsupportedOperationException(); + } + }; + + Moshi moshi = new Moshi.Builder().add(String.class, stringAdapter).build(); JsonAdapter objectAdapter = moshi.adapter(Object.class); - Map value - = (Map) objectAdapter.fromJson("{\"a\":\"b\", \"c\":\"d\"}"); + Map value = + (Map) objectAdapter.fromJson("{\"a\":\"b\", \"c\":\"d\"}"); assertThat(value).containsExactly(new SimpleEntry<>("A", "B"), new SimpleEntry<>("C", "D")); } @@ -206,75 +236,87 @@ public final class ObjectAdapterTest { * Confirm that the built-in adapter for Object delegates to any user-supplied adapters for * Object. This is necessary to customize adapters for primitives like numbers. */ - @Test public void objectAdapterDelegatesObjects() throws Exception { - JsonAdapter.Factory objectFactory = new JsonAdapter.Factory() { - @Override public @Nullable JsonAdapter create( - Type type, Set annotations, Moshi moshi) { - if (type != Object.class) return null; - - final JsonAdapter delegate = moshi.nextAdapter(this, Object.class, annotations); - return new JsonAdapter() { - @Override public @Nullable Object fromJson(JsonReader reader) throws IOException { - if (reader.peek() != JsonReader.Token.NUMBER) { - return delegate.fromJson(reader); - } else { - return new BigDecimal(reader.nextString()); - } - } - - @Override public void toJson(JsonWriter writer, @Nullable Object value) { - throw new UnsupportedOperationException(); + @Test + public void objectAdapterDelegatesObjects() throws Exception { + JsonAdapter.Factory objectFactory = + new JsonAdapter.Factory() { + @Override + public @Nullable JsonAdapter create( + Type type, Set annotations, Moshi moshi) { + if (type != Object.class) return null; + + final JsonAdapter delegate = moshi.nextAdapter(this, Object.class, annotations); + return new JsonAdapter() { + @Override + public @Nullable Object fromJson(JsonReader reader) throws IOException { + if (reader.peek() != JsonReader.Token.NUMBER) { + return delegate.fromJson(reader); + } else { + return new BigDecimal(reader.nextString()); + } + } + + @Override + public void toJson(JsonWriter writer, @Nullable Object value) { + throw new UnsupportedOperationException(); + } + }; } }; - } - }; - Moshi moshi = new Moshi.Builder() - .add(objectFactory) - .build(); + Moshi moshi = new Moshi.Builder().add(objectFactory).build(); JsonAdapter objectAdapter = moshi.adapter(Object.class); List value = (List) objectAdapter.fromJson("[0, 1, 2.0, 3.14]"); - assertThat(value).isEqualTo(Arrays.asList(new BigDecimal("0"), new BigDecimal("1"), - new BigDecimal("2.0"), new BigDecimal("3.14"))); + assertThat(value) + .isEqualTo( + Arrays.asList( + new BigDecimal("0"), + new BigDecimal("1"), + new BigDecimal("2.0"), + new BigDecimal("3.14"))); } /** Confirm that the built-in adapter for Object delegates to user-supplied adapters for lists. */ - @Test public void objectAdapterDelegatesLists() throws Exception { - JsonAdapter> listAdapter = new JsonAdapter>() { - @Override public List fromJson(JsonReader reader) throws IOException { - reader.skipValue(); - return singletonList("z"); - } - - @Override public void toJson(JsonWriter writer, @Nullable List value) { - throw new UnsupportedOperationException(); - } - }; - - Moshi moshi = new Moshi.Builder() - .add(List.class, listAdapter) - .build(); + @Test + public void objectAdapterDelegatesLists() throws Exception { + JsonAdapter> listAdapter = + new JsonAdapter>() { + @Override + public List fromJson(JsonReader reader) throws IOException { + reader.skipValue(); + return singletonList("z"); + } + + @Override + public void toJson(JsonWriter writer, @Nullable List value) { + throw new UnsupportedOperationException(); + } + }; + + Moshi moshi = new Moshi.Builder().add(List.class, listAdapter).build(); JsonAdapter objectAdapter = moshi.adapter(Object.class); Map mapOfList = (Map) objectAdapter.fromJson("{\"a\":[\"b\"]}"); assertThat(mapOfList).isEqualTo(singletonMap("a", singletonList("z"))); } /** Confirm that the built-in adapter for Object delegates to user-supplied adapters for maps. */ - @Test public void objectAdapterDelegatesMaps() throws Exception { - JsonAdapter> mapAdapter = new JsonAdapter>() { - @Override public Map fromJson(JsonReader reader) throws IOException { - reader.skipValue(); - return singletonMap("x", "y"); - } - - @Override public void toJson(JsonWriter writer, @Nullable Map value) { - throw new UnsupportedOperationException(); - } - }; - - Moshi moshi = new Moshi.Builder() - .add(Map.class, mapAdapter) - .build(); + @Test + public void objectAdapterDelegatesMaps() throws Exception { + JsonAdapter> mapAdapter = + new JsonAdapter>() { + @Override + public Map fromJson(JsonReader reader) throws IOException { + reader.skipValue(); + return singletonMap("x", "y"); + } + + @Override + public void toJson(JsonWriter writer, @Nullable Map value) { + throw new UnsupportedOperationException(); + } + }; + + Moshi moshi = new Moshi.Builder().add(Map.class, mapAdapter).build(); JsonAdapter objectAdapter = moshi.adapter(Object.class); List listOfMap = (List) objectAdapter.fromJson("[{\"b\":\"c\"}]"); assertThat(listOfMap).isEqualTo(singletonList(singletonMap("x", "y"))); diff --git a/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java b/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java index 33a177003..3f7d191a5 100644 --- a/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java +++ b/moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java @@ -15,6 +15,9 @@ */ package com.squareup.moshi; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.util.List; import okio.Buffer; import org.junit.Test; @@ -23,9 +26,6 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - @RunWith(Parameterized.class) public final class PromoteNameToValueTest { @Parameter public JsonCodecFactory factory; @@ -35,7 +35,8 @@ public static List parameters() { return JsonCodecFactory.factories(); } - @Test public void readerStringValue() throws Exception { + @Test + public void readerStringValue() throws Exception { JsonReader reader = factory.newReader("{\"a\":1}"); reader.beginObject(); reader.promoteNameToValue(); @@ -49,7 +50,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerIntegerValue() throws Exception { + @Test + public void readerIntegerValue() throws Exception { JsonReader reader = factory.newReader("{\"5\":1}"); reader.beginObject(); reader.promoteNameToValue(); @@ -63,7 +65,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerDoubleValue() throws Exception { + @Test + public void readerDoubleValue() throws Exception { JsonReader reader = factory.newReader("{\"5.5\":1}"); reader.beginObject(); reader.promoteNameToValue(); @@ -77,7 +80,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerBooleanValue() throws Exception { + @Test + public void readerBooleanValue() throws Exception { JsonReader reader = factory.newReader("{\"true\":1}"); reader.beginObject(); reader.promoteNameToValue(); @@ -87,9 +91,10 @@ public static List parameters() { reader.nextBoolean(); fail(); } catch (JsonDataException e) { - assertThat(e.getMessage()).isIn( - "Expected BOOLEAN but was true, a java.lang.String, at path $.true", - "Expected a boolean but was STRING at path $.true"); + assertThat(e.getMessage()) + .isIn( + "Expected BOOLEAN but was true, a java.lang.String, at path $.true", + "Expected a boolean but was STRING at path $.true"); } assertThat(reader.getPath()).isEqualTo("$.true"); assertThat(reader.nextString()).isEqualTo("true"); @@ -99,7 +104,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerLongValue() throws Exception { + @Test + public void readerLongValue() throws Exception { JsonReader reader = factory.newReader("{\"5\":1}"); reader.beginObject(); reader.promoteNameToValue(); @@ -113,7 +119,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerNullValue() throws Exception { + @Test + public void readerNullValue() throws Exception { JsonReader reader = factory.newReader("{\"null\":1}"); reader.beginObject(); reader.promoteNameToValue(); @@ -123,9 +130,10 @@ public static List parameters() { reader.nextNull(); fail(); } catch (JsonDataException e) { - assertThat(e.getMessage()).isIn( - "Expected NULL but was null, a java.lang.String, at path $.null", - "Expected null but was STRING at path $.null"); + assertThat(e.getMessage()) + .isIn( + "Expected NULL but was null, a java.lang.String, at path $.null", + "Expected null but was STRING at path $.null"); } assertThat(reader.nextString()).isEqualTo("null"); assertThat(reader.getPath()).isEqualTo("$.null"); @@ -135,7 +143,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerMultipleValueObject() throws Exception { + @Test + public void readerMultipleValueObject() throws Exception { JsonReader reader = factory.newReader("{\"a\":1,\"b\":2}"); reader.beginObject(); assertThat(reader.nextName()).isEqualTo("a"); @@ -151,7 +160,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerEmptyValueObject() throws Exception { + @Test + public void readerEmptyValueObject() throws Exception { JsonReader reader = factory.newReader("{}"); reader.beginObject(); assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_OBJECT); @@ -161,7 +171,8 @@ public static List parameters() { assertThat(reader.getPath()).isEqualTo("$"); } - @Test public void readerUnusedPromotionDoesntPersist() throws Exception { + @Test + public void readerUnusedPromotionDoesntPersist() throws Exception { JsonReader reader = factory.newReader("[{},{\"a\":5}]"); reader.beginArray(); reader.beginObject(); @@ -176,7 +187,8 @@ public static List parameters() { assertThat(reader.nextName()).isEqualTo("a"); } - @Test public void readerUnquotedIntegerValue() throws Exception { + @Test + public void readerUnquotedIntegerValue() throws Exception { JsonReader reader = factory.newReader("{5:1}"); reader.setLenient(true); reader.beginObject(); @@ -186,7 +198,8 @@ public static List parameters() { reader.endObject(); } - @Test public void readerUnquotedLongValue() throws Exception { + @Test + public void readerUnquotedLongValue() throws Exception { JsonReader reader = factory.newReader("{5:1}"); reader.setLenient(true); reader.beginObject(); @@ -196,7 +209,8 @@ public static List parameters() { reader.endObject(); } - @Test public void readerUnquotedDoubleValue() throws Exception { + @Test + public void readerUnquotedDoubleValue() throws Exception { JsonReader reader = factory.newReader("{5:1}"); reader.setLenient(true); reader.beginObject(); @@ -206,7 +220,8 @@ public static List parameters() { reader.endObject(); } - @Test public void writerStringValue() throws Exception { + @Test + public void writerStringValue() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -219,7 +234,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":1}"); } - @Test public void writerIntegerValue() throws Exception { + @Test + public void writerIntegerValue() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -232,7 +248,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"5\":1}"); } - @Test public void writerDoubleValue() throws Exception { + @Test + public void writerDoubleValue() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -245,7 +262,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"5.5\":1}"); } - @Test public void writerBooleanValue() throws Exception { + @Test + public void writerBooleanValue() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -263,7 +281,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"true\":1}"); } - @Test public void writerLongValue() throws Exception { + @Test + public void writerLongValue() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -276,7 +295,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"5\":1}"); } - @Test public void writerNullValue() throws Exception { + @Test + public void writerNullValue() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -295,7 +315,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"null\":1}"); } - @Test public void writerMultipleValueObject() throws Exception { + @Test + public void writerMultipleValueObject() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.name("a"); @@ -310,7 +331,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":1,\"b\":2}"); } - @Test public void writerEmptyValueObject() throws Exception { + @Test + public void writerEmptyValueObject() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -320,7 +342,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{}"); } - @Test public void writerUnusedPromotionDoesntPersist() throws Exception { + @Test + public void writerUnusedPromotionDoesntPersist() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginArray(); writer.beginObject(); @@ -335,7 +358,8 @@ public static List parameters() { writer.name("a"); } - @Test public void writerSourceValueFails() throws Exception { + @Test + public void writerSourceValueFails() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -343,8 +367,8 @@ public static List parameters() { writer.value(new Buffer().writeUtf8("\"a\"")); fail(); } catch (IllegalStateException expected) { - assertThat(expected).hasMessage( - "BufferedSource cannot be used as a map key in JSON at path $."); + assertThat(expected) + .hasMessage("BufferedSource cannot be used as a map key in JSON at path $."); } writer.value("a"); writer.value("a value"); @@ -352,7 +376,8 @@ public static List parameters() { assertThat(factory.json()).isEqualTo("{\"a\":\"a value\"}"); } - @Test public void writerValueSinkFails() throws Exception { + @Test + public void writerValueSinkFails() throws Exception { JsonWriter writer = factory.newWriter(); writer.beginObject(); writer.promoteValueToName(); @@ -360,8 +385,8 @@ public static List parameters() { writer.valueSink(); fail(); } catch (IllegalStateException expected) { - assertThat(expected).hasMessage( - "BufferedSink cannot be used as a map key in JSON at path $."); + assertThat(expected) + .hasMessage("BufferedSink cannot be used as a map key in JSON at path $."); } writer.value("a"); writer.value("a value"); diff --git a/moshi/src/test/java/com/squareup/moshi/RecursiveTypesResolveTest.java b/moshi/src/test/java/com/squareup/moshi/RecursiveTypesResolveTest.java index 21f7d091b..a390606f5 100644 --- a/moshi/src/test/java/com/squareup/moshi/RecursiveTypesResolveTest.java +++ b/moshi/src/test/java/com/squareup/moshi/RecursiveTypesResolveTest.java @@ -16,21 +16,22 @@ package com.squareup.moshi; -import com.squareup.moshi.internal.Util; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import com.squareup.moshi.internal.Util; +import org.junit.Test; + /** * Test fixes for infinite recursion on {@link Util#resolve(java.lang.reflect.Type, Class, - * java.lang.reflect.Type)}, described at Issue #440 - * and similar issues. - *

    - * These tests originally caused {@link StackOverflowError} because of infinite recursion on attempts to - * resolve generics on types, with an intermediate types like 'Foo2<? extends ? super ? extends ... ? extends A>' - *

    - * Adapted from https://github.com/google/gson/commit/a300148003e3a067875b1444e8268b6e0f0e0e02 in + * java.lang.reflect.Type)}, described at Issue + * #440 and similar issues. + * + *

    These tests originally caused {@link StackOverflowError} because of infinite recursion on + * attempts to resolve generics on types, with an intermediate types like 'Foo2<? extends ? super + * ? extends ... ? extends A>' + * + *

    Adapted from https://github.com/google/gson/commit/a300148003e3a067875b1444e8268b6e0f0e0e02 in * service of https://github.com/square/moshi/issues/338. */ public final class RecursiveTypesResolveTest { @@ -43,10 +44,9 @@ private static class Foo2 { public Foo1 foo1; } - /** - * Test simplest case of recursion. - */ - @Test public void recursiveResolveSimple() { + /** Test simplest case of recursion. */ + @Test + public void recursiveResolveSimple() { JsonAdapter adapter = new Moshi.Builder().build().adapter(Foo1.class); assertNotNull(adapter); } @@ -55,23 +55,24 @@ private static class Foo2 { // Tests belows check the behaviour of the methods changed for the fix // - @Test public void doubleSupertype() { - assertEquals(Types.supertypeOf(Number.class), - Types.supertypeOf(Types.supertypeOf(Number.class))); + @Test + public void doubleSupertype() { + assertEquals( + Types.supertypeOf(Number.class), Types.supertypeOf(Types.supertypeOf(Number.class))); } - @Test public void doubleSubtype() { - assertEquals(Types.subtypeOf(Number.class), - Types.subtypeOf(Types.subtypeOf(Number.class))); + @Test + public void doubleSubtype() { + assertEquals(Types.subtypeOf(Number.class), Types.subtypeOf(Types.subtypeOf(Number.class))); } - @Test public void superSubtype() { - assertEquals(Types.subtypeOf(Object.class), - Types.supertypeOf(Types.subtypeOf(Number.class))); + @Test + public void superSubtype() { + assertEquals(Types.subtypeOf(Object.class), Types.supertypeOf(Types.subtypeOf(Number.class))); } - @Test public void subSupertype() { - assertEquals(Types.subtypeOf(Object.class), - Types.subtypeOf(Types.supertypeOf(Number.class))); + @Test + public void subSupertype() { + assertEquals(Types.subtypeOf(Object.class), Types.subtypeOf(Types.supertypeOf(Number.class))); } } diff --git a/moshi/src/test/java/com/squareup/moshi/TypesTest.java b/moshi/src/test/java/com/squareup/moshi/TypesTest.java index e1419ba11..f7d9e8a25 100644 --- a/moshi/src/test/java/com/squareup/moshi/TypesTest.java +++ b/moshi/src/test/java/com/squareup/moshi/TypesTest.java @@ -15,6 +15,12 @@ */ package com.squareup.moshi; +import static com.squareup.moshi.internal.Util.canonicalize; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -29,43 +35,43 @@ import java.util.Set; import org.junit.Test; -import static com.squareup.moshi.internal.Util.canonicalize; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - public final class TypesTest { - @Retention(RUNTIME) @JsonQualifier @interface TestQualifier { - } + @Retention(RUNTIME) + @JsonQualifier + @interface TestQualifier {} - @Retention(RUNTIME) @JsonQualifier @interface AnotherTestQualifier { - } + @Retention(RUNTIME) + @JsonQualifier + @interface AnotherTestQualifier {} - @Retention(RUNTIME) @interface TestAnnotation { - } + @Retention(RUNTIME) + @interface TestAnnotation {} @TestQualifier private Object hasTestQualifier; - @Test public void nextAnnotationsRequiresJsonAnnotation() throws Exception { + @Test + public void nextAnnotationsRequiresJsonAnnotation() throws Exception { try { Types.nextAnnotations(Collections.emptySet(), TestAnnotation.class); fail(); } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessage( - "interface com.squareup.moshi.TypesTest$TestAnnotation is not a JsonQualifier."); + assertThat(expected) + .hasMessage( + "interface com.squareup.moshi.TypesTest$TestAnnotation is not a JsonQualifier."); } } - @Test public void nextAnnotationsDoesNotContainReturnsNull() throws Exception { + @Test + public void nextAnnotationsDoesNotContainReturnsNull() throws Exception { Set annotations = Collections.singleton(Types.createJsonQualifierImplementation(AnotherTestQualifier.class)); assertThat(Types.nextAnnotations(annotations, TestQualifier.class)).isNull(); - assertThat( - Types.nextAnnotations(Collections.emptySet(), TestQualifier.class)).isNull(); + assertThat(Types.nextAnnotations(Collections.emptySet(), TestQualifier.class)) + .isNull(); } - @Test public void nextAnnotationsReturnsDelegateAnnotations() throws Exception { + @Test + public void nextAnnotationsReturnsDelegateAnnotations() throws Exception { Set annotations = new LinkedHashSet<>(2); annotations.add(Types.createJsonQualifierImplementation(TestQualifier.class)); annotations.add(Types.createJsonQualifierImplementation(AnotherTestQualifier.class)); @@ -75,7 +81,8 @@ public final class TypesTest { .isEqualTo(expected); } - @Test public void newParameterizedType() throws Exception { + @Test + public void newParameterizedType() throws Exception { // List. List is a top-level class. Type type = Types.newParameterizedType(List.class, A.class); assertThat(getFirstTypeArgument(type)).isEqualTo(A.class); @@ -85,7 +92,8 @@ public final class TypesTest { assertThat(getFirstTypeArgument(type)).isEqualTo(B.class); } - @Test public void newParameterizedType_missingTypeVars() { + @Test + public void newParameterizedType_missingTypeVars() { try { Types.newParameterizedType(List.class); fail("Should have errored due to missing type variable"); @@ -101,7 +109,8 @@ public final class TypesTest { } } - @Test public void parameterizedTypeWithRequiredOwnerMissing() throws Exception { + @Test + public void parameterizedTypeWithRequiredOwnerMissing() throws Exception { try { Types.newParameterizedType(A.class, B.class); fail(); @@ -110,7 +119,8 @@ public final class TypesTest { } } - @Test public void parameterizedTypeWithUnnecessaryOwnerProvided() throws Exception { + @Test + public void parameterizedTypeWithUnnecessaryOwnerProvided() throws Exception { try { Types.newParameterizedTypeWithOwner(A.class, List.class, B.class); fail(); @@ -119,7 +129,8 @@ public final class TypesTest { } } - @Test public void parameterizedTypeWithIncorrectOwnerProvided() throws Exception { + @Test + public void parameterizedTypeWithIncorrectOwnerProvided() throws Exception { try { Types.newParameterizedTypeWithOwner(A.class, D.class, B.class); fail(); @@ -128,7 +139,8 @@ public final class TypesTest { } } - @Test public void arrayOf() { + @Test + public void arrayOf() { assertThat(Types.getRawType(Types.arrayOf(int.class))).isEqualTo(int[].class); assertThat(Types.getRawType(Types.arrayOf(List.class))).isEqualTo(List[].class); assertThat(Types.getRawType(Types.arrayOf(String[].class))).isEqualTo(String[][].class); @@ -137,52 +149,53 @@ public final class TypesTest { List listSubtype; List listSupertype; - @Test public void subtypeOf() throws Exception { + @Test + public void subtypeOf() throws Exception { Type listOfWildcardType = TypesTest.class.getDeclaredField("listSubtype").getGenericType(); Type expected = Types.collectionElementType(listOfWildcardType, List.class); assertThat(Types.subtypeOf(CharSequence.class)).isEqualTo(expected); } - @Test public void supertypeOf() throws Exception { + @Test + public void supertypeOf() throws Exception { Type listOfWildcardType = TypesTest.class.getDeclaredField("listSupertype").getGenericType(); Type expected = Types.collectionElementType(listOfWildcardType, List.class); assertThat(Types.supertypeOf(String.class)).isEqualTo(expected); } - @Test public void getFirstTypeArgument() throws Exception { + @Test + public void getFirstTypeArgument() throws Exception { assertThat(getFirstTypeArgument(A.class)).isNull(); Type type = Types.newParameterizedTypeWithOwner(TypesTest.class, A.class, B.class, C.class); assertThat(getFirstTypeArgument(type)).isEqualTo(B.class); } - @Test public void newParameterizedTypeObjectMethods() throws Exception { - Type mapOfStringIntegerType = TypesTest.class.getDeclaredField( - "mapOfStringInteger").getGenericType(); - ParameterizedType newMapType = Types.newParameterizedType(Map.class, String.class, Integer.class); + @Test + public void newParameterizedTypeObjectMethods() throws Exception { + Type mapOfStringIntegerType = + TypesTest.class.getDeclaredField("mapOfStringInteger").getGenericType(); + ParameterizedType newMapType = + Types.newParameterizedType(Map.class, String.class, Integer.class); assertThat(newMapType).isEqualTo(mapOfStringIntegerType); assertThat(newMapType.hashCode()).isEqualTo(mapOfStringIntegerType.hashCode()); assertThat(newMapType.toString()).isEqualTo(mapOfStringIntegerType.toString()); - Type arrayListOfMapOfStringIntegerType = TypesTest.class.getDeclaredField( - "arrayListOfMapOfStringInteger").getGenericType(); + Type arrayListOfMapOfStringIntegerType = + TypesTest.class.getDeclaredField("arrayListOfMapOfStringInteger").getGenericType(); ParameterizedType newListType = Types.newParameterizedType(ArrayList.class, newMapType); assertThat(newListType).isEqualTo(arrayListOfMapOfStringIntegerType); assertThat(newListType.hashCode()).isEqualTo(arrayListOfMapOfStringIntegerType.hashCode()); assertThat(newListType.toString()).isEqualTo(arrayListOfMapOfStringIntegerType.toString()); } - private static final class A { - } + private static final class A {} - private static final class B { - } + private static final class B {} - private static final class C { - } + private static final class C {} - private static final class D { - } + private static final class D {} /** * Given a parameterized type {@code A}, returns B. If the specified type is not a generic @@ -199,49 +212,55 @@ public static Type getFirstTypeArgument(Type type) throws Exception { Map mapOfStringInteger; Map[] arrayOfMapOfStringInteger; ArrayList> arrayListOfMapOfStringInteger; - interface StringIntegerMap extends Map { - } - @Test public void arrayComponentType() throws Exception { + interface StringIntegerMap extends Map {} + + @Test + public void arrayComponentType() throws Exception { assertThat(Types.arrayComponentType(String[][].class)).isEqualTo(String[].class); assertThat(Types.arrayComponentType(String[].class)).isEqualTo(String.class); - Type arrayOfMapOfStringIntegerType = TypesTest.class.getDeclaredField( - "arrayOfMapOfStringInteger").getGenericType(); - Type mapOfStringIntegerType = TypesTest.class.getDeclaredField( - "mapOfStringInteger").getGenericType(); + Type arrayOfMapOfStringIntegerType = + TypesTest.class.getDeclaredField("arrayOfMapOfStringInteger").getGenericType(); + Type mapOfStringIntegerType = + TypesTest.class.getDeclaredField("mapOfStringInteger").getGenericType(); assertThat(Types.arrayComponentType(arrayOfMapOfStringIntegerType)) .isEqualTo(mapOfStringIntegerType); } - @Test public void collectionElementType() throws Exception { - Type arrayListOfMapOfStringIntegerType = TypesTest.class.getDeclaredField( - "arrayListOfMapOfStringInteger").getGenericType(); - Type mapOfStringIntegerType = TypesTest.class.getDeclaredField( - "mapOfStringInteger").getGenericType(); + @Test + public void collectionElementType() throws Exception { + Type arrayListOfMapOfStringIntegerType = + TypesTest.class.getDeclaredField("arrayListOfMapOfStringInteger").getGenericType(); + Type mapOfStringIntegerType = + TypesTest.class.getDeclaredField("mapOfStringInteger").getGenericType(); assertThat(Types.collectionElementType(arrayListOfMapOfStringIntegerType, List.class)) .isEqualTo(mapOfStringIntegerType); } - @Test public void mapKeyAndValueTypes() throws Exception { - Type mapOfStringIntegerType = TypesTest.class.getDeclaredField( - "mapOfStringInteger").getGenericType(); + @Test + public void mapKeyAndValueTypes() throws Exception { + Type mapOfStringIntegerType = + TypesTest.class.getDeclaredField("mapOfStringInteger").getGenericType(); assertThat(Types.mapKeyAndValueTypes(mapOfStringIntegerType, Map.class)) .containsExactly(String.class, Integer.class); } - @Test public void propertiesTypes() throws Exception { + @Test + public void propertiesTypes() throws Exception { assertThat(Types.mapKeyAndValueTypes(Properties.class, Properties.class)) .containsExactly(String.class, String.class); } - @Test public void fixedVariablesTypes() throws Exception { + @Test + public void fixedVariablesTypes() throws Exception { assertThat(Types.mapKeyAndValueTypes(StringIntegerMap.class, StringIntegerMap.class)) .containsExactly(String.class, Integer.class); } @SuppressWarnings("GetClassOnAnnotation") // Explicitly checking for proxy implementation. - @Test public void createJsonQualifierImplementation() throws Exception { + @Test + public void createJsonQualifierImplementation() throws Exception { TestQualifier actual = Types.createJsonQualifierImplementation(TestQualifier.class); TestQualifier expected = (TestQualifier) TypesTest.class.getDeclaredField("hasTestQualifier").getAnnotations()[0]; @@ -252,14 +271,16 @@ interface StringIntegerMap extends Map { assertThat(actual.getClass()).isNotEqualTo(TestQualifier.class); } - @Test public void arrayEqualsGenericTypeArray() { + @Test + public void arrayEqualsGenericTypeArray() { assertThat(Types.equals(int[].class, Types.arrayOf(int.class))).isTrue(); assertThat(Types.equals(Types.arrayOf(int.class), int[].class)).isTrue(); assertThat(Types.equals(String[].class, Types.arrayOf(String.class))).isTrue(); assertThat(Types.equals(Types.arrayOf(String.class), String[].class)).isTrue(); } - @Test public void parameterizedAndWildcardTypesCannotHavePrimitiveArguments() throws Exception { + @Test + public void parameterizedAndWildcardTypesCannotHavePrimitiveArguments() throws Exception { try { Types.newParameterizedType(List.class, int.class); fail(); @@ -280,39 +301,47 @@ interface StringIntegerMap extends Map { } } - @Test public void getFieldJsonQualifierAnnotations_privateFieldTest() { - Set annotations = Types.getFieldJsonQualifierAnnotations(ClassWithAnnotatedFields.class, - "privateField"); + @Test + public void getFieldJsonQualifierAnnotations_privateFieldTest() { + Set annotations = + Types.getFieldJsonQualifierAnnotations(ClassWithAnnotatedFields.class, "privateField"); assertThat(annotations).hasSize(1); assertThat(annotations.iterator().next()).isInstanceOf(FieldAnnotation.class); } - @Test public void getFieldJsonQualifierAnnotations_publicFieldTest() { - Set annotations = Types.getFieldJsonQualifierAnnotations(ClassWithAnnotatedFields.class, - "publicField"); + @Test + public void getFieldJsonQualifierAnnotations_publicFieldTest() { + Set annotations = + Types.getFieldJsonQualifierAnnotations(ClassWithAnnotatedFields.class, "publicField"); assertThat(annotations).hasSize(1); assertThat(annotations.iterator().next()).isInstanceOf(FieldAnnotation.class); } - @Test public void getFieldJsonQualifierAnnotations_unannotatedTest() { - Set annotations = Types.getFieldJsonQualifierAnnotations(ClassWithAnnotatedFields.class, - "unannotatedField"); + @Test + public void getFieldJsonQualifierAnnotations_unannotatedTest() { + Set annotations = + Types.getFieldJsonQualifierAnnotations(ClassWithAnnotatedFields.class, "unannotatedField"); assertThat(annotations).hasSize(0); } - @Test public void generatedJsonAdapterName_strings() { + @Test + public void generatedJsonAdapterName_strings() { assertThat(Types.generatedJsonAdapterName("com.foo.Test")).isEqualTo("com.foo.TestJsonAdapter"); - assertThat(Types.generatedJsonAdapterName("com.foo.Test$Bar")).isEqualTo("com.foo.Test_BarJsonAdapter"); + assertThat(Types.generatedJsonAdapterName("com.foo.Test$Bar")) + .isEqualTo("com.foo.Test_BarJsonAdapter"); } - @Test public void generatedJsonAdapterName_class() { - assertThat(Types.generatedJsonAdapterName(TestJsonClass.class)).isEqualTo("com.squareup.moshi.TypesTest_TestJsonClassJsonAdapter"); + @Test + public void generatedJsonAdapterName_class() { + assertThat(Types.generatedJsonAdapterName(TestJsonClass.class)) + .isEqualTo("com.squareup.moshi.TypesTest_TestJsonClassJsonAdapter"); } - @Test public void generatedJsonAdapterName_class_missingJsonClass() { + @Test + public void generatedJsonAdapterName_class_missingJsonClass() { try { Types.generatedJsonAdapterName(TestNonJsonClass.class); fail(); @@ -331,18 +360,25 @@ private static final class RecursiveTypeVars { RecursiveTypeVars superType; } - @Test public void recursiveTypeVariablesResolve() { - JsonAdapter> adapter = new Moshi.Builder().build().adapter(Types - .newParameterizedTypeWithOwner(TypesTest.class, RecursiveTypeVars.class, String.class)); + @Test + public void recursiveTypeVariablesResolve() { + JsonAdapter> adapter = + new Moshi.Builder() + .build() + .adapter( + Types.newParameterizedTypeWithOwner( + TypesTest.class, RecursiveTypeVars.class, String.class)); assertThat(adapter).isNotNull(); } - @Test public void recursiveTypeVariablesResolve1() { + @Test + public void recursiveTypeVariablesResolve1() { JsonAdapter adapter = new Moshi.Builder().build().adapter(TestType.class); assertThat(adapter).isNotNull(); } - @Test public void recursiveTypeVariablesResolve2() { + @Test + public void recursiveTypeVariablesResolve2() { JsonAdapter adapter = new Moshi.Builder().build().adapter(TestType2.class); assertThat(adapter).isNotNull(); } @@ -356,35 +392,23 @@ private static class TestType2 { } @JsonClass(generateAdapter = false) - static class TestJsonClass { - - } + static class TestJsonClass {} - static class TestNonJsonClass { - - } + static class TestNonJsonClass {} @JsonQualifier @Target(FIELD) @Retention(RUNTIME) - @interface FieldAnnotation { - - } + @interface FieldAnnotation {} @Target(FIELD) @Retention(RUNTIME) - @interface NoQualifierAnnotation { - - } + @interface NoQualifierAnnotation {} static class ClassWithAnnotatedFields { - @FieldAnnotation - @NoQualifierAnnotation - private final int privateField = 0; + @FieldAnnotation @NoQualifierAnnotation private final int privateField = 0; - @FieldAnnotation - @NoQualifierAnnotation - public final int publicField = 0; + @FieldAnnotation @NoQualifierAnnotation public final int publicField = 0; private final int unannotatedField = 0; } diff --git a/settings.gradle.kts b/settings.gradle.kts index d595815a8..191ad18d4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,4 +39,4 @@ include(":adapters") include(":examples") include(":kotlin:reflect") include(":kotlin:codegen") -include(":kotlin:tests") \ No newline at end of file +include(":kotlin:tests") diff --git a/spotless/spotless.java b/spotless/spotless.java new file mode 100644 index 000000000..e6223bcc8 --- /dev/null +++ b/spotless/spotless.java @@ -0,0 +1,15 @@ +/* + * Copyright (C) $YEAR Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/spotless/spotless.kt b/spotless/spotless.kt new file mode 100644 index 000000000..e6223bcc8 --- /dev/null +++ b/spotless/spotless.kt @@ -0,0 +1,15 @@ +/* + * Copyright (C) $YEAR Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/spotless/spotless.kts b/spotless/spotless.kts new file mode 100644 index 000000000..387b9730d --- /dev/null +++ b/spotless/spotless.kts @@ -0,0 +1,16 @@ +/* + * Copyright (C) $YEAR Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +