I have following project in Github : https://github.com/alirezaeiii/TMDb-Paging
I have a generic solution in my classes using TmdbItem interface, such as :
abstract class BaseFragment<T : TmdbItem> : BaseNavTypeFragment() {
protected abstract val viewModel: BaseViewModel<T>
protected lateinit var tmdbAdapter: TmdbAdapter<T>
}
TmdbItem interface and the class implementations are as follow :
interface TmdbItem : Parcelable {
val id : Int
val overview: String
val releaseDate: String?
val posterPath: String?
val backdropPath: String?
val name: String
val voteAverage: Double
}
@Parcelize
data class Movie(
override val id: Int,
override val overview: String,
@SerializedName("release_date")
override val releaseDate: String?,
@SerializedName("poster_path")
override val posterPath: String?,
@SerializedName("backdrop_path")
override val backdropPath: String?,
@SerializedName("title")
override val name: String,
@SerializedName("vote_average")
override val voteAverage: Double) : TmdbItem
@Parcelize
data class TVShow(
override val id: Int,
override val overview: String,
@SerializedName("first_air_date")
override val releaseDate: String?,
@SerializedName("poster_path")
override val posterPath: String?,
@SerializedName("backdrop_path")
override val backdropPath: String?,
override val name: String,
@SerializedName("vote_average")
override val voteAverage: Double) : TmdbItem
As you see I have to use @SerializedName
in both classes even if the value is the same such as poster_path
and backdrop_path
. Is there anyway that I could write them in one place such as a base class instead of both class implementations?
CodePudding user response:
That is probably not easily possible with Gson. The closest you could get to avoid duplicating the name is to define the property names somewhere as const val
and then refer to them in @SerializedName
, e.g. @SerializedName(POSTER_PATH_NAME)
.
Another solution which is however quite complicated and error-prone would be:
Place @SerializedName
on the getter functions of the interface, e.g. @get:SerializedName("...")
. This is possible because @SerializedName
supports METHOD
as target, but Gson only considers it on fields by default. Then write a custom FieldNamingStrategy
which does the following:
- Check if the field has a
@SerializedName
annotation, in that case return its value - Otherwise, obtain the Kotlin property (if any) for the Java field and obtain its getter method:
field.kotlinProperty?.javaGetter
- Check if the getter has a
@SerializedName
, in that case return its value - Otherwise, go through the superclasses and then superinterfaces to check if any of them declare the getter (which is overridden) and have a
@SerializedName
This is how it might work in theory; I have not tried to fully implement this yet. And as you can see the logic would be quite complex, so I am not sure if that would really be worth it.
Otherwise you might have to look for external Gson extensions which support getter methods, or other JSON libraries.