square/retrofit

`@Tag` does not work with primitive types

Closed this issue · 2 comments

Not sure if there is anything that can be done about this, or if it just needs to be documented as a restriction:

Trying to use an @Tag annotation with a Kotlin primitive type (e.g., Long) fails.

E.g., with an interface entry like this:

@GET("some/path")
suspend fun foo(
    @Tag someParam: Long
    ...
)

calling it with foo(1L, ...) creates this runtime error:

java.lang.ClassCastException: Cannot cast java.lang.Long to long
    at java.lang.Class.cast(Class.java:2477)
    at okhttp3.Request$Builder.tag(Request.kt:283)
    at retrofit2.RequestBuilder.addTag(RequestBuilder.java:230)
    at retrofit2.ParameterHandler$Tag.apply(ParameterHandler.java:455)
    at retrofit2.RequestFactory.create(RequestFactory.java:131)
    at retrofit2.OkHttpCall.createRawCall(OkHttpCall.java:211)
    at retrofit2.OkHttpCall.enqueue(OkHttpCall.java:133)
    at app.pachli.core.network.retrofit.apiresult.ApiResultCall.enqueue(ApiResultCall.kt:32)
    at retrofit2.KotlinExtensions.await(KotlinExtensions.kt:36)
    at retrofit2.HttpServiceMethod$SuspendForBody.adapt(HttpServiceMethod.java:252)
    at retrofit2.HttpServiceMethod.invoke(HttpServiceMethod.java:160)
    at retrofit2.Retrofit$1.invoke(Retrofit.java:177)
    at java.lang.reflect.Proxy.invoke(Proxy.java:1006)

Trying to work around this with a value class:

@JvmInline
value class LongWrapper(private val id: Long)

@GET("some/path")
suspend fun foo(
    @Tag someParam: LongWrapper
    ...
)

results in (unsurprisingly) the same error.

Yeah we just need to use the boxed class type if the primitive type is in the signature. Surprised it's taken 10 years to find this.

(The value is auto-boxed when it goes through the Java Proxy machinery, as arguments come in as an Object[])