2

Here is my model class

data class Article( val id: Int? = 0, val is_local: Boolean? = false, val comments: List<Comment?>? = listOf())

and here is json

  {
    "id": 33,
    "is_local": "true",
    "comments":
         [
          { "url": "aaa" },

          { "url": "bbb" },

          { "url": "ccc" )

     ]

}

i am using this custom Adapter to return default value in case of parsing error like in my case is is_local field

class DefaultOnDataMismatchAdapter<T> private constructor(private val delegate: 
   JsonAdapter<T>, private val defaultValue: T?) : JsonAdapter<T>() {

 @Throws(IOException::class)
  override fun fromJson(reader: JsonReader): T? =
        try {
            delegate.fromJsonValue(reader.readJsonValue())
        } catch (e: Exception) {
            println("Wrongful content - could not parse delegate " + 
delegate.toString())
            defaultValue
        }

@Throws(IOException::class)
override fun toJson(writer: JsonWriter, value: T?) {
    delegate.toJson(writer, value)
}

  companion object {
    @JvmStatic
    fun <T> newFactory(type: Class<T>, defaultValue: T?): 
    JsonAdapter.Factory {
        return object : JsonAdapter.Factory {
            override fun create(requestedType: Type, annotations: 
      Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
                if (type != requestedType) {
                    return null
                }
                val delegate = moshi.nextAdapter<T>(this, type, 
          annotations)
                return DefaultOnDataMismatchAdapter(delegate, 
     defaultValue)
             }

         }
      }
   }

}

and my test fail and boolean value is not false i have added the above adapter to moshi

@Before
fun createService() {

    val moshi = Moshi.Builder()


    .add(DefaultOnDataMismatchAdapter
                           .newFactory(Boolean::class.java,false))
            .add(KotlinJsonAdapterFactory())
            .build()

    val retrofit = Retrofit.Builder()
            .baseUrl(mockWebServer.url("/"))
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .build()

    service =  retrofit.create(ApiStores::class.java)



}




@Test
fun getBooleanParsingError() {

    enqueueResponse(case1)

    val article = service.getArticle().execute()

    assert(article.body()!!).isNotNull()
    assert(article.body()!!.is_local).isEqualTo(false)  // test fail here 

}

but when i change the datatype of is_local field in the model class to not nullable it works

shakil.k
  • 1,623
  • 5
  • 17
  • 27

1 Answers1

0

The issue is that types kotlin.Boolean and kotlin.Boolean? correspond to 2 different Java types:

  • kotlin.Boolean is boolean Java primitive type
  • kotlin.Boolean? is java.lang.Boolean Java type

In your test you created an adapter for a kotlin.Boolean (i.e., Java boolean type), while in your data model you have a kotlin.Boolean? (i.e., a java.lang.Boolean type). For this reason, when method create(...) of the Factory gets called, you are in a situation where type != requestedType, so your adapter is not created and the KotlinJsonAdapter is used instead. At this point, since the is_local field of the Json is not a boolean (but a string), Moshi should raise an Exception.

If you change your data model or your adapter to use the same type, you are in a situation where type == requestedType, so your adapter gets created, the exception is thrown as before, but you added a catch block that returns the default value.

user2340612
  • 10,053
  • 4
  • 41
  • 66
  • i am using Boolean::class.java how can i use kotlin.Boolean? type ? in order to compare type == requestedType – shakil.k Dec 02 '17 at 23:11
  • 3
    you can use `Boolean::class.javaObjectType` to get an instance of the Java Class for `java.lang.Boolean` – user2340612 Dec 03 '17 at 00:51