LoginSignup
3
1

More than 5 years have passed since last update.

[Java]JDKのコンパイラのバグを踏む

Last updated at Posted at 2018-05-08

たぶん踏んだやつ

[JDK-8143647] Javac compiles method reference that allows results in an IllegalAccessError

※後述のとおり、OpenJDK ではなく Oracle JDK で起きた事象なので、同じバグかどうかは正直微妙なところ。。。

追記

Oracle JDK の Bug Database にも、同じ Issue がありました。
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8143647

起きたこと

Solaris 上の Oracle JDK 8u92 でコンパイルしたクラスが、なぜか実行時に IllegalAccessError で落ちてしまう。

同じソースを Windows 7 (x64) 上の Eclipse Mars 2 (4.5.2) でコンパイルしたクラスだとちゃんと動く。。。

javap -c でバイトコードを覗いてみると、メソッド参照 を使っている箇所が、ソースコード上の具象クラスではなく、その親クラスである不可視(package private)な抽象クラスに置き換わっていた。

上記の issue の再現手順は以下の通り。

1) Create default-scoped abstract class with concrete method
2) Create a concrete public class extending the above class in the same package
3) Use a method reference to this inherited method in a class outside of the package 

対して、問題の起きたクラスとメソッド参照先のクラスを簡略化したソースは、

simplification
package inner;
abstract class AbstractHoge {
    public String getSomething() {
        ...
    }
}

package inner;
public class Hoge extends AbstractHoge {
}

package outer;
import inner.Hoge;
...
public class Fuga {
    public void doSomething(List<Hoge> list) {
        Map<String, List<Hoge>> map = 
            list.stream().collect(Collectors.groupingBy(Hoge::getSomething));
        ...
    }
}

といった感じで、見事に発動条件を満たしてしまっている。。。

解決策

上記の issue だと、8u102 だか 8u111 あたりでバックポート済みのようなので、それより新しいバージョンの Oracle JDK にアップデートする。
⇒実際に Oracle JDK 8u161 でコンパイルしたクラスでは問題が解消していた。

※何らかの制約があって JDK をアップデートができない場合は、抽象クラスのスコープを public に変更することで暫定的に回避可能。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1