【问题标题】:What is the reason for twitter4j.StreamListner IllegalAccessError in Kotlin?Kotlin 中 twitter4j.StreamListner IllegalAccessError 的原因是什么?
【发布时间】:2017-11-16 09:31:31
【问题描述】:

在 Kotlin 中实现 twitter4j.StatusListner 时,我得到以下 IllegalAccessError 和相关的堆栈跟踪:

Exception in thread "main" java.lang.IllegalAccessError: tried to access class twitter4j.StreamListener from class rxkotlin.rxextensions.TwitterExampleKt$observe$1
    at rxkotlin.rxextensions.TwitterExampleKt$observe$1.subscribe(TwitterExample.kt:50)
    at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)
    at io.reactivex.Observable.subscribe(Observable.java:10700)
    at io.reactivex.Observable.subscribe(Observable.java:10686)
    at io.reactivex.Observable.subscribe(Observable.java:10615)
    at rxkotlin.rxextensions.TwitterExampleKt.main(TwitterExample.kt:8)

由以下代码产生:

val twitterStream = TwitterStreamFactory().instance
// See https://stackoverflow.com/questions/37672023/how-to-create-an-instance-of-anonymous-interface-in-kotlin/37672334
twitterStream.addListener(object : StatusListener {
    override fun onStatus(status: Status?) {
        if (emitter.isDisposed) {
            twitterStream.shutdown()
        } else {
            emitter.onNext(status)
        }
    }

    override fun onException(e: Exception?) {
        if (emitter.isDisposed) {
            twitterStream.shutdown()
        } else {
            emitter.onError(e)
        }
    }

    // Other overrides.
})
emitter.setCancellable { twitterStream::shutdown }

如果我不使用 Rx,它会使异常更简单:

twitterStream.addListener(object: twitter4j.StatusListener {
    override fun onStatus(status: Status) { println("Status: {$status}") }
    override fun onException(ex: Exception) { println("Error callback: $ex") }
    // Other overrides.
})

Exception in thread "main" java.lang.IllegalAccessError: tried to access class twitter4j.StreamListener from class rxkotlin.rxextensions.TwitterExampleKt
at rxkotlin.rxextensions.TwitterExampleKt.main(TwitterExample.kt:14)

但是,如果我实现 Java 包装函数,则不会引发错误并且行为符合预期:

包装器-

public class Twitter4JHelper {
  public static void addStatusListner(TwitterStream stream, StatusListener listner) {
    stream.addListener(listner);
  }
}

修改后的实现 -

val twitterStream = TwitterStreamFactory().instance
val listner = object: StatusListener {
    override fun onStatus(status: Status?) {
        if (emitter.isDisposed) {
            twitterStream.shutdown()
        } else {
            emitter.onNext(status)
        }
    }

    override fun onException(e: Exception?) {
        if (emitter.isDisposed) {
            twitterStream.shutdown()
        } else {
            emitter.onError(e)
        }
    }

    // Other overrides.
}

Twitter4JHelper.addStatusListner(twitterStream, listner)
emitter.setCancellable { twitterStream::shutdown }

这个修改后的解决方案来自blog post,我认为它试图解释原因,但谷歌翻译不是我的朋友。是什么导致了IllegalAccessError?是否有纯粹基于 Kotlin 的解决方案,还是我必须接受这种解决方法?

【问题讨论】:

  • 发布实际的堆栈跟踪怎么样?
  • 我已经添加了。

标签: kotlin twitter4j illegalaccessexception


【解决方案1】:

是的,那是行不通的。

addListener 方法采用 StreamListener 参数,StreamListener 是非公开的(包私有)。为此,我肯定会针对 Kotlin 编译器提出一个错误。

Kotlin 编译器生成的代码是:

TwitterStream twitterStream = (new TwitterStreamFactory()).getInstance();
twitterStream.addListener((StreamListener)(new StatusListener() {
         // ..overrides ...
      }));

StatusListener 已经实现了StreamListener,所以我不明白为什么需要强制转换。

【讨论】:

  • 是的,还有与此相关的 3 张门票。我猜JB并不急于修复它。
  • 我已将我的 tuppence 值添加到问题跟踪器中。
【解决方案2】:

我通过使用 java 实用程序类解决了这个问题:

public class T4JCompat {

  public static void addStatusListener(TwitterStream stream, StatusListener listener) {
    stream.addListener(listener);
  }

  public static void removeStatusListener(TwitterStream stream, StatusListener listener) {
    stream.removeListener(listener);
  }

} 

您可以从 Kotlin 中调用这些方法,一切都会按预期工作。

【讨论】:

    猜你喜欢
    • 2018-08-31
    • 2017-04-10
    • 2018-01-12
    • 1970-01-01
    • 2021-02-17
    • 2016-08-28
    • 2016-09-01
    • 2011-12-04
    • 2011-08-29
    相关资源
    最近更新 更多