Allow generic types in responses when using Moshi as JSON parser
See original GitHub issueWhat kind of issue is this?
-
Question. This issue tracker is not the place for questions. If you want to ask how to do something, or to understand why something isn’t working the way you expect it to, use Stack Overflow. https://stackoverflow.com/questions/tagged/retrofit
-
Bug report. If you’ve found a bug, spend the time to write a failing test. Bugs with tests get fixed. Here’s an example: https://gist.github.com/swankjesse/6608b4713ad80988cdc9
-
Feature Request. Start by telling us what problem you’re trying to solve. Often a solution already exists! Don’t send pull requests to implement new features without first getting our support. Sometimes we leave features out on purpose to keep the project small.
Description of the issue:
I’m trying to achieve a scenario that is very common, but with Moshi isn’t so trivial as I thought (I’m coming from Gson, that is simpler to use, but I’m aware of its many disadvantages).
I have endpoint definitions that use generic types, like this:
@GET("api.json")
suspend fun <T> test(): Result<T>
This is used because Result<T> contains a standard structure, basically as defined below:
@JsonClass(generateAdapter = true)
data class Result<T> (
var data: T? = null,
var timestamp: OffsetDateTime? = null
)
As you may see, it is used to track common information (like the server timestamp and, eventually, in the future, may have the ID of the request to match logs or something like that).
But the problem is that Moshi adapter for this class isn’t called how it should by Retrofit (I explain below), which results in this error:
2020-01-18 15:38:59.913 7097-7202/com.example.myapplication E/MainActivity: Error handling JSON data:
java.lang.IllegalArgumentException: Unable to create converter for com.example.myapplication.api.Result<T>
for method RemoteService.test
at retrofit2.Utils.methodError(Utils.java:53)
at retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:115)
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:813)
at $Proxy4.test(Unknown Source)
at com.example.myapplication.MainActivity.handleWithMoshiRetrofitConverter(MainActivity.kt:72)
at com.example.myapplication.MainActivity$onCreate$1$1.invokeSuspend(MainActivity.kt:48)
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)
Caused by: java.lang.IllegalArgumentException: No JsonAdapter for T (with no annotations)
for T data
for com.example.myapplication.api.Result<T>
at com.squareup.moshi.Moshi$LookupChain.exceptionWithLookupStack(Moshi.java:349)
at com.squareup.moshi.Moshi.adapter(Moshi.java:150)
at com.example.myapplication.api.ResultJsonAdapter.<init>(ResultJsonAdapter.kt:29)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at com.squareup.moshi.internal.Util.generatedAdapter(Util.java:540)
at com.squareup.moshi.StandardJsonAdapters$1.create(StandardJsonAdapters.java:60)
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)
at retrofit2.Retrofit.responseBodyConverter(Retrofit.java:335)
at retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:113)
... 14 more
Caused by: java.lang.IllegalArgumentException: No JsonAdapter for T (with no annotations)
at com.squareup.moshi.Moshi.adapter(Moshi.java:148)
... 25 more
Firstly, I thought the problem was with Moshi generated adapter. But then I made a simple test code that uses Moshi directly to parse the text and then try the same with a Retrofit call. The Moshi part of handling it is a little bit confusing (maybe the generated adapter code could be improved for this kind of scenarios), but it works very well.
So I ended up thinking that this may be the way Retrofit call Moshi converter. Any thoughts or ideas?
PS: I know I could create a response model for each of my response possibilities, but I really don’t think that this would be a solution. I don’t see, at least right now, why Retrofit + Moshi couldn’t handle this kind of use case (except for the fact that it isn’t implemented yet, which seems to be the case).
Issue Analytics
- State:
- Created 4 years ago
- Comments:9 (1 by maintainers)

Top Related StackOverflow Question
Thanks for the suggestion, @20ali20.
I ended up, for now, using Gson as parser. I read all over that it isn’t a good library for many reasons, but it is more flexible than Moshi in some use cases.
Will try to replace Gson at some point and your suggestion will be taken into account!
I will close the issue, as it is answered and there is no point to keep it open (I think).
Thanks for the attention of you all.
Have you tried creating an instance of the generic class with the specific T type in mind and then passing the class of that ? This way you have a new class where T is defined.
Also another option is to replace T with Any/Object and convert it after the matter