14

I have backend that return me some json.

I parse it to my class:

class SomeData(
  @SerializedName("user_name") val name: String,
  @SerializedName("user_city") val city: String,
  var notNullableValue: String
)

Use gson converter factory:

Retrofit retrofit = new Retrofit.Builder()
  .baseUrl(ENDPOINT)
  .client(okHttpClient)
  .addConverterFactory(GsonConverterFactory.create(gson))
  .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  .build();

And in my interface:

interface MyAPI {
    @GET("get_data")
    Observable<List<SomeData>> getSomeData();
}

Then I retrieve data from the server (with rxJava) without any error. But I expected an error because I thought I should do something like this (to prevent GSON converter error, because notNullableValue is not present in my JSON response):

class SomeData @JvmOverloads constructor(
  @SerializedName("user_name") val name: String,
  @SerializedName("user_city") val city: String,
  var notNullableValue: String = ""
)

After the data is received from backend and parsed to my SomeData class with constructor without def value, the value of the notNullableValue == null.

As I understand not nullable value can be null in Kotlin?

bitvale
  • 1,959
  • 1
  • 20
  • 27

2 Answers2

17

Yes, that is because you're giving it a default value. Ofcourse it will never be null. That's the whole point of a default value.

Remove ="" from constructor and you will get an error.

Edit: Found the issue. GSON uses the magic sun.misc.Unsafe class which has an allocateInstance method which is obviously considered very unsafe because what it does is skip initialization (constructors/field initializers and the like) and security checks. So there is your answer why a Kotlin non-nullable field can be null. Offending code is in com/google/gson/internal/ConstructorConstructor.java:223

Some interesting details about the Unsafe class: http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

Strelok
  • 50,229
  • 9
  • 102
  • 115
  • No, as You read correct all works fine without ="". And notNullableValue == null – bitvale Aug 21 '17 at 09:48
  • I am sorry for misunderstanding, I am edit question. – bitvale Aug 21 '17 at 09:54
  • @jQuick I updated my answer. TLDR: Gson is using unsafe java magic classes. – Strelok Aug 21 '17 at 12:41
  • 1
    If you're unhappy with Gson behaviour of a non-nullable having a null value and prefer default value instead, you can use Jackson-kotlin-module. Refer: https://stackoverflow.com/questions/38426579/in-kotlin-jackson-deserialization-error-with-data-class – ChinLoong Apr 30 '18 at 09:33
  • This is not only affecting the non-nullable type, but also, all of the properties that are initiated in the class body instead of primary constructor will not be initialized, aka null. – katie Aug 15 '18 at 22:25
4

Try to override constructor like this:

class SomeData(
        @SerializedName("user_name") val name: String,
        @SerializedName("user_city") val city: String,
        var notNullableValue: String = "") {
    constructor() : this("","","")
}

Now after server response you can check the notNullableValue is not null - its empty

Yurii
  • 552
  • 3
  • 14