Reputation: 1574
I have a moshi PolymorphicJsonAdapterFactory and it works great.
.withSubtype(ColdWeather::class.java, "Cold")
.withSubtype(HotWeather::class.java, "Hot")
.withDefaultValue(//how to grab the label)
The method withDefaultValue is a great catch all, but my BE team wants me to log the actual label that comes down in order to help catch a bug that's going on on their end. As far as I can tell... in the withDefaultValue I can't grab a reference to the label which in this case the backend is sending back "Medium".
I feel like there must be a way to grab this label (but I'm missing something simple?) so I can log it and possibly propagate it in the withDefaultValue method.
Upvotes: 3
Views: 1864
Reputation: 1463
I stumbled on the issue a while ago. I found it impossible to achieve with just using .withDefaultValue
method. So far I did not find better solution other than .withFallbackJsonAdapter
(I am using moshi version 1.12), which lets you parse the json manually in case the label is unknown to your PolymorphicJsonAdapterFactory
adapter. The documentation says:
/**
* Returns a new factory that with default to {@code fallbackJsonAdapter.fromJson(reader)} upon
* decoding of unrecognized labels.
*
* <p>The {@link JsonReader} instance will not be automatically consumed, so make sure to consume
* it within your implementation of {@link JsonAdapter#fromJson(JsonReader)}
*/
public PolymorphicJsonAdapterFactory<T> withFallbackJsonAdapter(
@Nullable JsonAdapter<Object> fallbackJsonAdapter) {
return ...
}
I assume your code is somewhat like this (simplified):
interface Weather {
val type: String
}
@JsonClass(generateAdapter = true)
class ColdWeather( @Json(name = "type") override val type: String) : Weather
@JsonClass(generateAdapter = true)
class HotWeather( @Json(name = "type") override val type: String) : Weather
val weatherAdapter = PolymorphicJsonAdapterFactory.of(Weather::class.java, "type")
.withSubtype(ColdWeather::class.java, "Cold")
.withSubtype(HotWeather::class.java, "Hot")
and you receive a json similar to this:
{ "weather" : { "type" : "Cold" } }
To receive an unknown label, I would do something like this:
class UnknownWeather(override val type: String) : Weather
val weatherAdapter = PolymorphicJsonAdapterFactory.of(Weather::class.java, "type")
.withSubtype(ColdWeather::class.java, "Cold")
.withSubtype(HotWeather::class.java, "Hot")
.withFallbackJsonAdapter((object : JsonAdapter<Any>() {
override fun fromJson(reader: JsonReader): UnknownWeather {
var type = ... // parse it from the reader
return UnknownWeather(type)
}
override fun toJson(writer: JsonWriter, value: Any?) {
// nothing to do
}
}))
Of course that means that you will have to dig a bit into JsonReader
, but it has a fairly understandable interface, you basically iterate through the properties of the json object and extract what you need, in our case just the "type" property.
FYI, seems like more people had problem with this: https://github.com/square/moshi/issues/784
Upvotes: 2