Search code examples
nullkotlindata-class

Is there a better way other than setting data class constructor values to null if its possible the data cannot be set


I have a situation whereby I am creating a rest client in kotlin as a practical learning exercise and have recently come up against this:

             data class ai constructor(val statusCode: Int,
                                       val a: Long? = null,
                                       val b: Long? = null,
                                       val c: Date? = null,
                                       val d: Long? = null,
                                       val e: String? = null,
                                       val f: String? = null)

The issue is this, if I get a 200 returned i will have the data to populate 'a' through 'f' but if instead i get a 401 or pretty much any other status code i will not have the data to populate 'a' through 'f' and therefore i have opted for the above solution where I only force the status code which i will always get back to not be null and then defaulted every other value to null.

I don't want to go down the route of setting defaults to things like "" or -1 because then there is always the chance that this data will somehow get through if a user does not check the status code.

Really i want to convey that the information is not present, it seems like this would do that but I wondered if there is a better way.


Solution

  • You could consider using a sealed class for this:

    sealed class Result
    
    data class Success constructor(val statusCode: Int = 200,
                                   val a: Long,
                                   val b: Long,
                                   val c: Date,
                                   val d: Long,
                                   val e: String,
                                   val f: String): Result()
    
    data class Failure(val statusCode: Int): Result()
    

    (I don't know if the explicit constructor for your class was intentional, if there are annotations on it, etc.)

    This way if you have a successful call, you'll create a Success instance, and if you have a failed call, you can create a Failure instance which doesn't even contain the properties representing the data received (come to think of it, you could move statusCode to the Result class, that's another choice to make).

    Here's how you could then handle these results:

    fun processResult(result: Result) {
        when (result) {
            is Success -> { /* Use result, which is smart cast to a Success now */ }
            is Failure -> { /* Use result, which is smart cast to a Failure now */ }
        }
    }