Невозможно округлить удвоение Gson до длинных с помощью Retrofit TypeAdapter в Kotlin - PullRequest
0 голосов
/ 25 июня 2019

Хорошо, мой API дает мне шальные 245.00000003 с давних времен, когда он должен был отправлять только целые числа.Я хочу убедиться, что я только анализирую это как Long со значением 245, и проверяю, если парни из бэкэнда делают это снова, я просто округляю его и затем кричу на них.

IЯ пробовал множество типов адаптеров, включая аннотацию @JsonAdapter и функцию registerHierarchyTypeAdapter, и ни один из них, похоже, не имел никакого эффекта.Что я делаю неправильно?

@Module
class CoreModule {

    @Provides
    internal fun provideGson(): Gson {
        return GsonBuilder().registerTypeAdapter(Long::class.java, LongTypeAdapter()).create()
    }
}

class LongTypeAdapter : TypeAdapter<Long>() {
    @Throws(IOException::class)
    override fun read(reader: JsonReader): Long? {
        if (reader.peek() === JsonToken.NULL) {
            reader.nextNull()
            return null
        }
        val stringValue = reader.nextString()

        return try {
            stringValue.toLong()
        } catch (e: NumberFormatException) {
            try { stringValue.toDouble().toLong() }
            catch (e: java.lang.NumberFormatException){ 0L }
        }
    }

    @Throws(IOException::class)
    override fun write(out: JsonWriter, value: Long?) {
        if (value == null) {
            out.nullValue()
            return
        }
        out.value(value)
    }
}

Я предполагаю, что код должен проверять любой Long в моем POJO, и когда придет время сопоставить его с содержимым JSON, он вернет null, если он нулевой,a Long, если оно может быть toLong()'d, Long, если оно может быть toDouble().toLong()'d, и 0 в противном случае.

POJO:

data class OrdersResponse(
    @SerializedName("error") val error: Boolean,
    @SerializedName("message") val message: String,
    @SerializedName("total") val total: Int,
    @SerializedName("orders") val orders: List<Orders>
) {

    data class Orders(
        @SerializedName("id") val id: Long,
        @SerializedName("status") val status: String,
        @SerializedName("completion_time") val completionTime: Long?,
        @SerializedName("total") val total: Long // This is the dodgy value
    ) {}
}

1 Ответ

0 голосов
/ 26 июня 2019

Хорошо, я понял это, это сбивает с толку, потому что есть несколько вариантов. Прежде всего, предоставляемая мной реализация Gson не использовалась на фабрике преобразователей для модернизации:

@Provides
@Singleton
fun provideRetrofit(@Named("baseUrlv1") baseUrl: String, okHttpClient: OkHttpClient, gson: Gson): Retrofit {
    return Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(LiveDataCallAdapterFactory<Any>())
            .build()
}

Во-вторых, меня интересует только Long в этом объекте Orders, поэтому вместо того, чтобы адаптер типа просматривал каждый Long, я использую JsonDeserializer ( дополнительную информацию здесь ):

@Module
class CoreModule {

    @Provides
    internal fun provideGson(): Gson {
        val gson = GsonBuilder()

        gson.registerTypeAdapter(OrdersResponse.Orders::class.java, OrdersDeserializer())

        return gson.create()
    }
}

class OrdersDeserializer : JsonDeserializer<OrdersResponse.Orders> {
    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): OrdersResponse.Orders {
        val jsonObject = json.asJsonObject

        val total = jsonObject.get("total").asNumber.toLong()
        jsonObject.add("total", JsonPrimitive(total))

        return Gson().fromJson(jsonObject, OrdersResponse.Orders::class.java)
    }
}
...