Skip to content

Commit 399c2da

Browse files
committed
Add enum extensions for serialization/deserialization
1 parent 32f8472 commit 399c2da

File tree

2 files changed

+94
-2
lines changed

2 files changed

+94
-2
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
}

base/src/main/java/com/enginebai/base/view/BaseActivity.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.annotation.LayoutRes
55
import androidx.appcompat.app.AppCompatActivity
66
import io.reactivex.disposables.CompositeDisposable
77
import io.reactivex.disposables.Disposable
8+
import timber.log.Timber
89

910
abstract class BaseActivity : AppCompatActivity() {
1011

@@ -13,8 +14,6 @@ abstract class BaseActivity : AppCompatActivity() {
1314
@LayoutRes
1415
abstract fun getLayoutId(): Int
1516

16-
abstract fun handleErrorMessage(message: String)
17-
1817
override fun onCreate(savedInstanceState: Bundle?) {
1918
super.onCreate(savedInstanceState)
2019
setContentView(getLayoutId())
@@ -25,6 +24,10 @@ abstract class BaseActivity : AppCompatActivity() {
2524
super.onDestroy()
2625
}
2726

27+
open fun handleErrorMessage(message: String) {
28+
Timber.w(message)
29+
}
30+
2831
protected fun Disposable.disposeOnDestroy(): Disposable {
2932
disposables.add(this)
3033
return disposables

0 commit comments

Comments
 (0)