Android Moshi Adapter For Gps Location (Kotlin)

May 14, 2018

We shall parse {"geo":"1.0, 2.0"} into a LocationType class to store the latitude and longitude.

LocationType.

class LocationType(
        @Transient var lat: Double? = null,
        @Transient var lng: Double? = null) {

    // accept android.location.Location
    constructor(location: Location?): this(location?.latitude, location?.longitude)

    companion object {
        fun fromJson(data: String): LocationType? {
            if (data.isEmpty()) {
                return null
            }

            val item = LocationType()
            item.fromJson(data)
            return item
        }
    }

    fun setValue(lat: Double, lng: Double) {
        this.lat = lat
        this.lng = lng
    }

    fun isNull(): Boolean {
        return lat == null || lng == null
    }

    private fun fromJson(data: String) {
        val tokens = data.split(",\\s?".toRegex())
        if (tokens.size == 2) {
            lat = tokens[0].toDouble()
            lng = tokens[1].toDouble()
        }
        else {
            lat = null
            lng = null
        }
    }

    fun toJson(): String? {
        if (isNull()) {
            return null
        }
        return "$lat, $lng"
    }
}

LocationAdapter.

class LocationAdapter {
    @ToJson
    @Nullable fun toJson(@Nullable value: LocationType?):  String? {
        return value?.toJson()
    }

    @FromJson
    fun fromJson(@Nullable data: String?): LocationType? {
        if (data == null) {
            return null
        }
        return LocationType.fromJson(data)
    }
}

Setup Moshi

val moshi = Moshi.Builder()
      .add(LocationAdapter())
      .add(KotlinJsonAdapterFactory())
      .build()

Test Code.

data class PhotoPin (
        @Json(name = "geo") var location: LocationType? = null
        )
@RunWith(AndroidJUnit4::class)
class MoshiTest {
    lateinit var moshi: Moshi
    lateinit var adapter: JsonAdapter<PhotoPin>

    @Before
    fun init() {
        moshi = Moshi.Builder()
            .add(LocationAdapter())
            .add(KotlinJsonAdapterFactory())
            .build()
        adapter = moshi.adapter<PhotoPin>(PhotoPin::class.java)
    }


    @Test
    fun testLocationEmpty() {
        var item = adapter.fromJson("""{"geo": ""}""")!!

        assertThat(item.location, Is(nullValue()))
    }

    @Test
    fun testLocationNull() {
        var item = adapter.fromJson("""{"geo": null}""")!!

        assertThat(item.location, Is(nullValue()))
    }

    @Test
    fun testLocationValue() {
        var item = adapter.fromJson("""{"geo":"1.0, 2"}""")!!

        assertThat(item.location, Is(notNullValue()))
        assertThat(item.location?.lat, Is(1.0))
        assertThat(item.location?.lng, Is(2.0))
    }

    @Test
    fun testLocationValueToJson() {
        var item = PhotoPin()
        item.location = LocationType(1.0, 2.0)
        val data = adapter.toJson(item)

        assertThat(data.contains(""""geo":"1.0, 2.0""""), Is(true))

        item = adapter.fromJson(data)!!
        assertThat(item.location?.lat, Is(1.0))
        assertThat(item.location?.lng, Is(2.0))
    }

    @Test
    fun testLocationEmptyToJson() {
        var item = PhotoPin()
        val data = adapter.serializeNulls().toJson(item)

        assertThat(item.location, Is(nullValue()))
        assertThat(data.contains(""""geo":null"""), Is(true))

        item = adapter.fromJson(data)!!
        assertThat(item.location, Is(nullValue()))
    }    
}
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.