1+ package com.enginebai.base.extensions
2+
3+ import com.google.gson.*
4+ import com.google.gson.annotations.SerializedName
5+ import retrofit2.Converter
6+ import retrofit2.Retrofit
7+ import timber.log.Timber
8+ import java.lang.reflect.Type
9+
10+ /* *
11+ * Enable to serialize enum with Gson @SerializedName annotation to Retrofit HTTP query string.
12+ *
13+ * Example:
14+ * enum class MediaType {
15+ * @SerializedName("image-jpeg")
16+ * IMAGE_JPG,
17+ * @SerializedName("video-mp4")
18+ * VIDEO_MP4
19+ * }
20+ *
21+ * interface ApiService {
22+ * @GET
23+ * fun getMediaList(@Query("type") mediaType: MediaType): List<Media>
24+ * }
25+ *
26+ * val mediaList = apiService.getMediaList(MediaType.IMAGE_JPG)
27+ *
28+ * The actual HTTP request will be GET /medias?type=image-jpeg
29+ */
30+ object EnumGsonSerializedNameConverterFactory : Converter.Factory() {
31+ override fun stringConverter (
32+ type : Type ,
33+ annotations : Array <out Annotation >,
34+ retrofit : Retrofit
35+ ): Converter <* , String >? {
36+ if (type is Class <* > && type.isEnum) {
37+ return Converter <Any ?, String > { value -> getSerializedNameValue(value as Enum <* >) }
38+ }
39+ return null
40+ }
41+
42+ private fun <E : Enum <* >> getSerializedNameValue (e : E ): String {
43+ val exception = IllegalStateException (
44+ " You might miss the Gson @SerializedName annotation for " +
45+ " your enum class $e that is used for Retrofit request/response"
46+ )
47+ return e.javaClass.getField(e.name).getAnnotation(SerializedName ::class .java)?.value
48+ ? : throw exception
49+ }
50+ }
51+
52+ object EnumHasValueConverterFactory: Converter.Factory() {
53+ override fun stringConverter (
54+ type : Type ,
55+ annotations : Array <out Annotation >,
56+ retrofit : Retrofit
57+ ): Converter <* , String >? {
58+ if (type is Class <* > && type.isEnum && type.interfaces.contains(EnumHasValue ::class .java)) {
59+ return Converter <Any ?, String > { value -> (value as EnumHasValue ).value }
60+ }
61+ return null
62+ }
63+ }
64+
65+ // source: https://stackoverflow.com/a/45561053/2279285
66+ interface EnumHasValue {
67+ val value: String
68+ }
69+
70+ class EnumHasValueJsonAdapter <T > : JsonSerializer <T >, JsonDeserializer <T > where T : EnumHasValue {
71+ override fun serialize (
72+ src : T ,
73+ typeOfSrc : Type ? ,
74+ context : JsonSerializationContext ?
75+ ): JsonElement {
76+ return JsonPrimitive (src.value)
77+ }
78+
79+ override fun deserialize (
80+ json : JsonElement ,
81+ typeOfT : Type ? ,
82+ context : JsonDeserializationContext ?
83+ ): T ? {
84+ val parsedValue = (typeOfT as Class <T >).enumConstants?.associateBy { it.value }?.get(json.asString)
85+ parsedValue ? : kotlin.run { Timber .w(" Can not deserialize value ${json.asString} to $typeOfT " ) }
86+ return parsedValue
87+ }
88+
89+ }
0 commit comments