5

Can anyone tell, why I'm getting a java.lang.StackOverflowError using this Kotlin class? Line 41 is if (instance == null) {

class TokenHelper protected constructor() {
    var token: String? = null
    var appId: String? = null
    var installationId: String? = null
    var userId: String? = null

    companion object {
        var instance: TokenHelper? = null
            get() {
                if (instance == null) {
                    instance = TokenHelper()
                }
                return instance
            }
    }
}

Stacktrace:

04-11 19:07:42.188 16142-16142/com.foo.bar.debug E/AndroidRuntime: FATAL EXCEPTION: main
  Process: com.foo.bar.debug, PID: 16142
  java.lang.StackOverflowError: stack size 8MB
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:0)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
    at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: exClass=java.lang.StackOverflowError
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: exMsg=stack size 8MB
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: file=TokenHelper.kt
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: class=com.foo.bar.helper.TokenHelper$Companion
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: method=getInstance line=0
04-11 19:07:42.282 16142-16142/com.foo.bar.debug D/Error: ERR: stack=java.lang.StackOverflowError: stack size 8MB
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:0)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
    at com.foo.bar.helper.TokenHelper$Companion.getInstance(
04-11 19:07:42.283 16142-16142/com.foo.bar.debug D/Error: ERR: TOTAL BYTES WRITTEN: 880768
04-11 19:07:45.527 16142-16142/com.foo.bar.debug D/Process: killProcess, pid=16142
04-11 19:07:45.528 16142-16142/com.foo.bar.debug D/Process: com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException:113 java.lang.ThreadGroup.uncaughtException:693 java.lang.ThreadGroup.uncaughtException:690 

Android Studio 2.0, Kotlin 1.0.1-2

user3105453
  • 1,881
  • 5
  • 32
  • 55

2 Answers2

8

You're calling instance getter method recursively. Change you getter definition to use field instead:

var instance: TokenHelper? = null
    get() {
        if (field == null) {
            field = TokenHelper()
        }
        return field
    }

The relevant excerpt from the documentation:

Classes in Kotlin cannot have fields. However, sometimes it is necessary to have a backing field when using custom accessors. For these purposes, Kotlin provides an automatic backing field which can be accessed using the field identifier:

var counter = 0 // the initializer value is written directly to the backing field
  set(value) {
    if (value >= 0)
      field = value
  }

The field identifier can only be used in the accessors of the property.

miensol
  • 39,733
  • 7
  • 116
  • 112
  • 1
    Thanks. I just googled "Kotlin Singleton" and came up with this solution (https://medium.com/@adinugroho/singleton-in-kotlin-502f80fd8a63#.64ssyu1by): `private object Holder { val INSTANCE = TokenHelper() } companion object { val instance: TokenHelper by lazy { Holder.INSTANCE } }` Do you think that's Kotlin compliant too? Btw: My initial code was generated by AS upon raising the "Convert to Kotlin" command. – user3105453 Apr 11 '16 at 17:28
  • 1
    Yes it is compliant. The IDE converter works well for very simple cases - it's outputs should always be reviewed before use. – miensol Apr 11 '16 at 17:34
1

Adapted from a comment on the original answer:

In Kotlin, you don't need all the boilerplate to declare a singleton. When declaring your class, simply make it an object like so:

object TokenHelper {
    var token: String? = null
    var appId: String? = null
    var installationId: String? = null
    var userId: String? = null
}

Then access it as follows: TokenHelper.token or from Java TokenHelper.INSTANCE.getToken().

Kirill Rakhman
  • 42,195
  • 18
  • 124
  • 148