8

I use Moshi for parse json from server. if server send null for item default value not set! but server not send that item default value set.

json:

{"percentChange": null,"change": "-2500.00","value": "130000","name": null}

data class:

@JsonClass(generateAdapter = true) data class Reference(val name:String? = "-",val value: Double,val change: Double,val percentChange: Double? = -10.0,)

but data for name and percentChange is null that should "-" for name and "-10.0" for percentChange. if server not send name and percentChange, default value work, but if send that null default value not work!

I use converter-moshi:2.4.0 and retrofit:2.4.0

h.kelidari
  • 800
  • 1
  • 11
  • 20
  • Did you use Kotlin version of moshi? – Joshua Nov 28 '18 at 09:33
  • @Joshua I use MoshiConverterFactory for retrofit – h.kelidari Nov 28 '18 at 09:46
  • I read you question again. I realize `name` is `String?`, so moshi works as intended. You should change it to `String` if `null` is not a valid value. – Joshua Nov 28 '18 at 10:03
  • @Joshua i want name set default value when server send null value for that. if change String? to String, error none-null Value 'name' was null – h.kelidari Nov 28 '18 at 10:18
  • 1
    This is an expected behavior. You see, the default value would be used if the field wasn't present. Null is different from absent. In other words: {"foo": "bar", "fizz": null} is different from {"foo": "bar"}. Fizz's default value would only be used on the second case, when absent. – Vitor Hugo Schwaab Dec 04 '18 at 00:37
  • Also, see if you are using the kotlin version of Moshi. There is Moshi and Moshi-Kotlin. If I remember correctly, default values only work on the latter. – Vitor Hugo Schwaab Dec 04 '18 at 00:38

1 Answers1

1

This is working as intended because the null literal as a value for a key in JSON is semantically different than the absence of the key and value.

You can make a custom JsonAdapter for your use case.

@JsonClass(generateAdapter = true)
data class Reference(
  @Name val name: String = "-",
  val value: Double,
  val change: Double,
  val percentChange: Double? = -10.0
) {
  @Retention(RUNTIME)
  @JsonQualifier
  annotation class Name

  companion object {
    @Name @FromJson fun fromJson(reader: JsonReader, delegate: JsonAdapter<String>): String {
      if (reader.peek() == JsonReader.Token.NULL) {
        reader.nextNull<Unit>()
        return "-"
      }
      return delegate.fromJson(reader)!!
    }

    @ToJson fun toJson(@Name name: String): String {
      return name
    }
  }
}

@Test fun reference() {
  val moshi = Moshi.Builder()
      .add(Reference)
      .build()
  val adapter = moshi.adapter(Reference::class.java)
  val decoded = Reference("-", 130_000.toDouble(), (-2_500).toDouble(), null)
  assertThat(adapter.fromJson(
      """{"percentChange": null,"change": "-2500.00","value": "130000"}"""))
      .isEqualTo(decoded)
  assertThat(adapter.fromJson(
      """{"percentChange": null,"change": "-2500.00","value": "130000","name": null}"""))
      .isEqualTo(decoded)
}
Eric Cochran
  • 8,414
  • 5
  • 50
  • 91