Использование предложения when в получателе перечислимого класса в Kotlin - PullRequest
0 голосов
/ 10 мая 2018

Я пытаюсь получить конкретный метод получения свойства в kotlin, основанный на значении перечисления, из которого оно вызывается. Вот что я получил до сих пор:

enum class Endpoint {
    EVENTS, GAMES;

    val baseUrl = "https://www.example.com/api"

    val path: String
        get() = when(this){
            EVENTS -> "$baseUrl/events"
            GAMES -> "$baseUrl/games"
        }
}

Вызывается так:

print(Endpoint.EVENTS.path)

Хотя это компилируется без проблем, как только я запускаю его, я получаю NullPointerException с ошибкой Attempt to invoke virtual method 'java.lang.Object [...].Endpoint[].clone()' on a null object reference

Я не уверен, что я делаю неправильно или как правильно выполнить то, что сказано выше.

РЕДАКТИРОВАТЬ: Полный журнал исключения:

05-09 22:51:33.793 15673-15673/com.filippovigani.eventvods E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.filippovigani.eventvods, PID: 15673
java.lang.ExceptionInInitializerError
    at com.filippovigani.eventvods.networking.Endpoint.getPath(Endpoint.kt:21)
    at com.filippovigani.eventvods.networking.Endpoint.<init>(Endpoint.kt:25)
    at com.filippovigani.eventvods.networking.Endpoint.<clinit>(Endpoint.kt)
    at com.filippovigani.eventvods.networking.EventvodsApi$Companion.getEvents(EventvodsApi.kt:8)
    at com.filippovigani.eventvods.MainActivity.onCreate(MainActivity.kt:19)
    at android.app.Activity.performCreate(Activity.java:5990)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
    at android.app.ActivityThread.access$800(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5254)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object com.filippovigani.eventvods.networking.Endpoint[].clone()' on a null object reference
    at com.filippovigani.eventvods.networking.Endpoint.values(Endpoint.kt)
    at com.filippovigani.eventvods.networking.Endpoint$WhenMappings.<clinit>(Unknown Source)
    at com.filippovigani.eventvods.networking.Endpoint.getPath(Endpoint.kt:21) 
    at com.filippovigani.eventvods.networking.Endpoint.<init>(Endpoint.kt:25) 
    at com.filippovigani.eventvods.networking.Endpoint.<clinit>(Endpoint.kt) 
    at com.filippovigani.eventvods.networking.EventvodsApi$Companion.getEvents(EventvodsApi.kt:8) 
    at com.filippovigani.eventvods.MainActivity.onCreate(MainActivity.kt:19) 
    at android.app.Activity.performCreate(Activity.java:5990) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
    at android.app.ActivityThread.access$800(ActivityThread.java:151) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:135) 
    at android.app.ActivityThread.main(ActivityThread.java:5254) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Исключение означает, что вы пытаетесь получить доступ к path в конструкторе перечисления.Это вызывает проблему, поскольку перечисление еще не готово к использованию во время построения.

Это означает, что следующая цепочка вызовов приведет к сбою:

  1. Init Endpoint
  2. Init Endpoint.EVENTS
  3. Позвоните на Endpoint.getPath() (Это не отображается в вашем коде)
  4. Использует Endpoint$WhenMapping, начните инициацию этого класса.
  5. Endpoint$WhenMapping использует EndPoint.values(), но, поскольку мы все еще инициализируем экземпляры перечисления, массив значений не может быть предоставлен, возвращая null.
  6. Чтобы гарантировать, что он не изменен, WhenMapping клонирует икэширует массив, но так как массив равен нулю, когда он никогда не должен находиться вне инициализации, это вызывает NPE.

Проще говоря, ваш код каким-то образом полагается на класс, который требует, чтобы он был полностью инициализирован для использования,Поскольку ваш код не отображает, как вы звоните Endpoint.EVENTS.path, это все, что можно сказать об этом.

0 голосов
/ 10 мая 2018

Я не могу воспроизвести вашу ошибку, код работает нормально. Тем не менее, я думаю, что решение слишком сложное, почему бы вам не использовать аргумент конструктора для предоставления значения, специфичного для константы:

enum class Endpoint(service: String) {
    EVENTS("/events"), GAMES("/games");

    private val baseUrl = "https://www.example.com/api"
    val path: String = baseUrl + service
}
...