```data class Response<T>( ... val data:...
# announcements
e
Copy code
data class Response<T>(
  ...
  val data: List<T>
}
Has anyone using moshi to deal with this kind of object? I don't quite seems to find example for doing so..
n
e
Doesn't solve my issue, I still got
java.lang.ClassCastException: com.squareup.moshi.LinkedHashTreeMap cannot be cast to T
n
hm, something really strange, why is it LinkedHashTreeMap ?
e
I hv no idea about it as well
n
but how are you trying to parse it? why do you need generic there?
e
Cause the structure of the response can contain different type
n
hm, why not to create different data classes?
I’m also curious how your parser looks like because you still need somehow provide a T.
e
Yeah, how do you look up your adapter?
e
I've tried to write a custom parser for it, but I'm stuck with the
fromJson
part, cause there are other properties other then
val data: List<T>
.
Copy code
object CustomMoshiAdapterFactory: JsonAdapter.Factory {
    override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
        val rawType = Types.getRawType(type)
        if (rawType == PageResponse::class.java && type is ParameterizedType) {
            val subType = type.actualTypeArguments.first()
            val adapter: JsonAdapter<PageResponse<*>> = moshi.adapter(Types.newParameterizedType(rawType, subType))
            return adapter
        }

        return null
    }
}
e
That code looks like it would cause a stack overflow from reentry.
e
Yup it does, maybe changing the line
val adapter...
to
val adapter: JsonAdapter<Any> = moshi.adapter(subType)
?
n
so, I still don’t understand why you can not create different classes 🤔 I would really avoid generics here, and it is not the issue with moshi or kotlin, I think it won’t work on Java and GSON as well
e
Well the problem is it works fine when using Gson, but not when switched to Moshi
And it feels dumb for me to create different classes for this when generic should work
e
Why do you need to implement a custom adapter?
e
If not, I can't parse the
data class Response<T> ( ..., val data: List<T>)
thing properly, moshi gives me
java.lang.ClassCastException: com.squareup.moshi.LinkedHashTreeMap cannot be cast to T
for whatever
T
I put
I know gson is bad when compared with moshi, that's why I'm trying to use moshi to do the same thing. It is just frustrating that things work with gson does not work when switched to moshi.
e
Can you post the code that gives you the ClassCastException?
e
Copy code
val movieResponseList: MutableList<MovieResponse> = mutableListOf()

  override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
    val movie = movieResponseList[position].movie
    holder.bindData(movie)

    // set on click listener and delegate out
    if (onItemClickListener != null) {
      holder.itemView.setOnClickListener { it ->
        onItemClickListener!!.onItemClick(it, position)
      }
    }
  }
The stacktrace said it is the
val movie = movieResponseList[position].movie
gives such exception. Remark: The server api is returning
Response<MovieResponse>
in this case, where
data class MovieResponse(val movie: Movie)
and
Movie
is also some simple data class.
n
So, you are saying that such data class (with generic) works with Kotlin+GSON but not with Kotlin+Moshi? that really strange, because they are almost the same
e
@nikolay Yes, exactly. I feel strange as well, given all my code works fine when using GSON, it should work just fine with Moshi, but not when I actually replaced it😞
e
I need to see how you're looking up the adapter. If you can make a reprocible example, I can take a look on Stack Overflow.
n
yeah, maybe you could create a simple project that will show the issue?
I’m also interested to find solution, because thinking currently to switch to Moshi
could you show JSON response?
e
I will try to make a simple project to reproduce the issue, github link will be posted here once I've finished.
n
but could you for now post the JSON that comes from server?
e
Sample JSON is something like this
Copy code
{
  "content": [
    {
      "organisation": null,
      "movie": {
        "name": "Iron man",
        "posterUrl": "someUrl",
        "durationMin": 130,
        "openDate": "0999-01-01T00:00:00Z",
        "status": "ACTIVE",
        "publish": "RELEASE",
        "sort": 1000,
        "uuid": "e56e36d4-ab32-4a9a-8312-817860719847",
        "createAt": "2018-04-24T04:03:45Z",
        "updateAt": "2018-04-24T04:03:45Z"
      },
      "count": null
    },
    {
      "organisation": null,
      "movie": {
        "name": "Thor",
        "posterUrl": "someOtherUrl",
        "durationMin": 121,
        "openDate": "0999-01-01T00:00:00Z",
        "status": "ACTIVE",
        "publish": "RELEASE",
        "sort": 1000,
        "uuid": "ca74e40c-ef8b-4730-a2d2-4b87f6ac49f9",
        "createAt": "2018-04-24T04:03:45Z",
        "updateAt": "2018-04-24T04:03:45Z"
      },
      "count": null
    }
  ],
  "last": true,
  "totalPages": 1,
  "totalElements": 12,
  "sort": null,
  "first": true,
  "numberOfElements": 12,
  "size": 0,
  "number": 0
}
Damn it is just weird, when using
moshi.adapter(Types.newParameterizedType(PageResponse::class.java,  MovieResponse::class.java))
, it does actually parse without issue. But when it combined with
Retrofit
,
RxJavaCallAdapter
and
MoshiConverter
, the issue happens in my project.
n
but still, backing to the question why do you need generic. Looking on this JSON, I would suggest just simple data class like this:
Copy code
data class Response(
    val content: List<ContentItem>,
    val last: Boolean,
    val totalPages: Int,
    val totalElements: Int,
    val sort: Boolean?
) {
  data class ContentItem(
      val organization: String?,
      val movie: Movie,
      val count: Int?
  ) {
    data class Movie(
        val name:String,
        val poeterUrl: String
    )
  }
}
maybe I’m really missing something, but I don’t see why do you need to overcomplicate things with generics
e
Cause
MovieResponse
is not the only structure that can be inside
Response<T>
There are at least three different structure that are possible, such that it can be
Response<Foo>
,
Response<Bar>
,
Response<Whatever>
etc.
Well I finally solved my issue, turns out it is problem during serialise/deserialise between controllers(I'm using
Conductor
). Sorry for wasting so much time of you two gentleman.
n
but if you have
Response<Foo>
and so on, does it mean that one endpoint return different responses ?
e
Those are from different endpoint, I just don't want to write
FooResponse
,
BarResponse
so many times when I can express it using generics, and that's the purpose of generics.