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调用这些方法,事情按预期工作。