LoginSignup
4
5

More than 5 years have passed since last update.

JavaでScalaのライブラリを使うためTraitをデコンパイルした

Last updated at Posted at 2016-10-11

とある事情でJavaからScala用のライブラリを使わなければならなくなりました。

そのライブラリはあるTraitをミックスインすることで、機能を自分でカスタマイズできます。そして今回、そのカスタマイズが必要になったため、JavaでそのTraitをimplementsしようと試みました。

しかしすんなりとはいかず苦戦を強いられました。そこでJavaではTraitとはどういった扱いになるのかをちょっと調べることにしました。

JavaでTraitをimplements

まずこのScala用ライブラリの機能をカスタマイズするためにTraitをJava側で使うことにしました。
そのTraitは下記のようなものでした。(実際のソースコードではありません)

trait Trait_1 {

  val a: String

  val b: Int

}
trait Trait_1_1  extends Trait_1{

  val a: String = "a"

  val b: Int = 1

}

JavaではTraitというものはありませんが、書籍でTraitはinterfaceのようなものとあったのでとあったのでclassにimplementsしてみました。

Class_1.java
public class Class_1 implements Trait_1_1 {
}

しかし、下記のエラーが。
Class 'Class_1' must either be declared abstract or implement abstract method 'a()' in 'Trait_1_1'

しかしTrait_1_1にはa()なんてメソッドはありません。

このメソッドなんだ?どこから出てきたんだ?
そういえばscalaではフィールドへのgetterやsetterが暗黙的に作られると聞いた気がする。

ここでようやくclassファイルをデコンパイルすることを思いつきました。

Traitをデコンパイル

Traitの中身を知るために、ScalaでTraitを実装してコンパイルした後、作成されたclassファイルをjadを使ってデコンパイルしてみました。

まずはval変数を宣言しただけのTrait_1をデコンパイル。

public interface Trait_1
{

    public abstract String a();

    public abstract int b();
}

おお、a()メソッドが出てきましたね。これはおそらくgetterメソッドでしょう。
あとinterfaceになりました。

次に、Trait_1_1ですが、こちらはコンパイルしたところ、
Trait_1_1.class
Trait_1_1$class.class
と2つののclassファイルが作成されました。

それぞれをデコンパイルした結果がこちら。

public interface Trait_1_1
{

    public abstract void Trait_1_1$_setter_$a_$eq(String s);

    public abstract void Trait_1_1$_setter_$b_$eq(int i);

    public abstract String a();

    public abstract int b();
}
public abstract class Trait_1_1$class
{

    public static void $init$(Trait_1_1 $this)
    {
        $this.Trait_1_1$_setter_$a_$eq("a");
        $this.Trait_1_1$_setter_$b_$eq(1);
    }
}

Trait_1_1はinterfaceに、Trait_1_1$classはabstractクラスになりました。

Trait_1_1には新しいメソッドが出てきましたね。setterと書いてあることから、setterメソッドでしょう。 
Trait_1_1$classにはそのsetterメソッドを使用したinitメソッドがあります。scalaでval変数の定義をしたことが、javaではこういう形になるようです。 

ここまでの結果をまとめると、Trait_1はval変数の宣言しかせず、何の値も定義していないためgetterだけ、Trait_1_1は値を定義したためsetterが出てきたということでしょうか。

そして、これらのメソッドはabstractなので、実装を書かなければならないというのがエラーの原因だったようです。

ではこれらのabstractメソッドの実装をすればいけるのでしょうか?
それをしたのがこちら。

Class_1.java
public class Class_1 implements Trait_1_1 {

    public String a () {
        return "a";
    }

    public int b () {
        return 1;
    }

    public void Trait_1_1$_setter_$a_$eq(String s){};

    public void Trait_1_1$_setter_$b_$eq(int i){};
}

getteメソッドは値を返すように、setterメソッドはひとまず中身なしのメソッドにしてみました。
一応これでコンパイルが通るようにはなりました。

4
5
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
4
5