Kotlin中twitter4j.StreamListner IllegalAccessError的原因是什么?

在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 } 

这个修改后的解决方案来自一个博客文章 ,我认为它试图解释的原因,但谷歌翻译不是我的朋友。 什么导致IllegalAccessError ? 是否有纯粹的Kotlin解决方案,还是我必须忍受这个解决方法?

是的,这是不行的。

addListener方法需要一个StreamListener参数,而StreamListener是非公开的(包私有的)。 我肯定会提出一个针对这个Kotlin编译器的bug。

Kotlin编译器生成的代码是:

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

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

我通过使用一个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调用这些方法,事情按预期工作。