EclipseLink-2.7.1とJava10でweaverが動かない(ことがある)

Java10上でEclipseLinkを動かすと、

Weaver encountered an exception while trying to weave class foo/bar/Baz. The exception was: null

という警告が出ることがあります。nullってなんだよおい。

調べた所、EclipseLinkが内部に保持しているASMのバージョンがJava10に対応していないために起きているようです。

masterブランチでは既にパッチが取り込まれた模様ですが、

github.com

これがリリースされるまでの凌ぎとして、おなじみのJavassistで無理やり解決してみました。

やったこと

まず、対象となるクラスは org.eclipse.persistence.internal.libraries.asm.ClassReader です。

該当箇所はここです。

public ClassReader(final byte[] b, final int off, final int len) {
    this.b = b;
    // checks the class version
    if (readShort(off + 6) > Opcodes.V9) { // ←コレ!!!
        throw new IllegalArgumentException();
    }
    // parses the constant pool
    items = new int[readUnsignedShort(off + 8)];
    int n = items.length;
    strings = new String[n];
    int max = 0;

        ...
}

確かにJava9までしか対応してませんね。(OpCodes.V9がJava9を表している)

というわけでJavassistthrow new IllegalArgumentException()を消せば… と思ったらどうやら、Javassistはthrow文の置き換えに対応していないようです。ナンテコッタイ。

そこで、引数のbyte[] bの中身を改変することにしました。だいたい次のような感じ。

CtClass ctc = ClassPool.getDefault().get(ClassReader.class.getName());

ctc.getDeclaredConstructors()[1].inserBeforeBody("{ " //

     // 中身を改変するので念のためコピーする
     + "$1 = (byte[]) $1.clone();" //

     // readShortで2バイト分見ている。先頭バイトは常にゼロなので2バイト目がバージョンを表す
     // 53はJava9のバージョン
    + "$1[$2 + 6 + 1] = (byte) 53;" //

    + "}");

これで例の警告は出ないようになりました。

2018-07-24追記

この問題はEclipseLink-2.7.2で解消されました。