Reputation: 2004
I'm working with an API that returns responses that look like:
{
"irrelevantStuff": {},
"data": []
}
I'd like to follow the approach demonstrated in this presentation from Jake, where he creates a Retrofit converter factory to handle and unwrap the envelope type. The only problem is that the approach shown uses Gson and Java, where as I'm trying to make use of Moshi and Kotlin.
I've declared my envelope type as:
data class Envelope<T>(val data: T)
Any my converter factory as:
object EnvelopeConverter : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *>? {
val envelopedType = Types.newParameterizedType(Envelope::class.java, type)
val delegate: Converter<ResponseBody, Envelope<Any>>? =
retrofit.nextResponseBodyConverter(this, envelopedType, annotations)
return Unwrapper(delegate)
}
private class Unwrapper<T>(
private val delegate: Converter<ResponseBody, Envelope<T>>?
) : Converter<ResponseBody, T> {
override fun convert(value: ResponseBody): T? {
return delegate?.convert(value)?.data
}
}
}
Retrofit has been configured as:
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(currentEndpoint.url)
.addConverterFactory(EnvelopeConverter)
.addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().add(KotlinJsonAdapterFactory()).build()))
.build()
However when a request is executed, I receive the exception shown below. It's worth noting that this converter works fine when using the moshi-kotlin-codegen
dependency. It's just the moshi-kotlin
reflection based library it has issues with. What's the cause of this?
java.lang.AssertionError: Built-in class kotlin.Any is not found
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns$3.invoke(KotlinBuiltIns.java:113)
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns$3.invoke(KotlinBuiltIns.java:108)
at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:440)
at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull.invoke(LockBasedStorageManager.java:515)
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getBuiltInClassByName(KotlinBuiltIns.java:362)
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getAny(KotlinBuiltIns.java:367)
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getAnyType(KotlinBuiltIns.java:642)
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getNullableAnyType(KotlinBuiltIns.java:647)
at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getDefaultBound(KotlinBuiltIns.java:652)
at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedTypeParameterDescriptor.resolveUpperBounds(DeserializedTypeParameterDescriptor.kt:45)
at kotlin.reflect.jvm.internal.impl.descriptors.impl.AbstractTypeParameterDescriptor$TypeParameterTypeConstructor.computeSupertypes(AbstractTypeParameterDescriptor.java:154)
at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:34)
at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:22)
at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:346)
at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:402)
at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor.getSupertypes(AbstractTypeConstructor.kt:23)
at kotlin.reflect.jvm.internal.impl.descriptors.impl.AbstractTypeParameterDescriptor.getUpperBounds(AbstractTypeParameterDescriptor.java:116)
at kotlin.reflect.jvm.internal.impl.types.typeUtil.TypeUtilsKt.getRepresentativeUpperBound(TypeUtils.kt:237)
at kotlin.reflect.jvm.internal.impl.resolve.jvm.InlineClassManglingRulesKt.isTypeParameterWithUpperBoundThatRequiresMangling(inlineClassManglingRules.kt:44)
at kotlin.reflect.jvm.internal.impl.resolve.jvm.InlineClassManglingRulesKt.requiresFunctionNameMangling(inlineClassManglingRules.kt:37)
at kotlin.reflect.jvm.internal.impl.resolve.jvm.InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters(inlineClassManglingRules.kt:23)
at kotlin.reflect.jvm.internal.KFunctionImpl.createConstructorCaller(KFunctionImpl.kt:145)
at kotlin.reflect.jvm.internal.KFunctionImpl.access$createConstructorCaller(KFunctionImpl.kt:36)
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:80)
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:36)
at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(Unknown Source:7)
at kotlin.reflect.jvm.ReflectJvmMapping.getJavaMethod(ReflectJvmMapping.kt:62)
at kotlin.reflect.jvm.KCallablesJvm.setAccessible(KCallablesJvm.kt:82)
at com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory.create(KotlinJsonAdapter.kt:221)
at com.squareup.moshi.Moshi.adapter(Moshi.java:138)
at com.squareup.moshi.Moshi.adapter(Moshi.java:98)
at retrofit2.converter.moshi.MoshiConverterFactory.responseBodyConverter(MoshiConverterFactory.java:91)
at retrofit2.Retrofit.nextResponseBodyConverter(Retrofit.java:352)
E/AndroidRuntime: at codes.chrishorner.socketweather.data.EnvelopeConverter.responseBodyConverter(EnvelopeConverter.kt:19)
at retrofit2.Retrofit.nextResponseBodyConverter(Retrofit.java:352)
at retrofit2.Retrofit.responseBodyConverter(Retrofit.java:335)
at retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:113)
at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:82)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:37)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:192)
at retrofit2.Retrofit$1.invoke(Retrofit.java:149)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy1.searchForLocation(Unknown Source)
at codes.chrishorner.socketweather.MainActivity$onStart$1.invokeSuspend(MainActivity.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:561)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:727)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:667)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:655)
Upvotes: 7
Views: 1403
Reputation: 2004
Turns out I was cursed by copy-pasting in some overzealous optimisations!
In my app module's build.gradle
file, I had included:
packagingOptions {
exclude 'kotlin/**'
exclude '**/*.kotlin_metadata'
exclude 'META-INF/*.kotlin_module'
exclude 'META-INF/*.version'
}
The exclude 'kotlin/**'
was the culprit.
Moral of the story: Be careful what you copy and paste!
Upvotes: 4