RoboVMでシリアライズやリフレクションが使えるか試した（使えた）

　RoboVMは、JavaのコードをARMやX86のバイナリに出力してくれるすごいロボです。
　Java+libGDXで作ったAndroid用ゲームをRoboVMでiOS用バイナリ出力してAndroid/iOSマルチ対応作戦を目論んでいます。
　が、いざRoboVMにかけたら「リフレクションなんか対応してるわけないだろJK」とか言われても困るので検証してみました。

#とりあえずiOSアプリが生成できるか検証
以下のサイトを参考に、iOSアプリのソースをJavaで書いてRoboVMでiOS用バイナリーを生成、シミュレーターで実行してみました。
[JavaでiOSアプリ開発 RoboVM + eclipse](http://www.webcyou.com/?p=4663)

動いた！
![スクリーンショット 2014-04-24 21.26.26.png](https://qiita-image-store.s3.amazonaws.com/0/42140/48ee7182-d4f3-c361-8d23-5a635da6ad31.png)
「Click」というボタンをクリックすると数字がカウントアップされていきます。


XCodeのバージョンは、バージョン 5.1.1
iOSシミュレーターは、バージョン 7.1 (463.9.41)
OS Xは、バージョン 10.9.2
JDKは、バージョン 1.7.0_40
RoboVMは、バージョン 0.0.11

現時点での最新バージョン(ver.0.0.11)ではファイルネームが変わり、RoboVMのダウンロードとインストールの手順は以下のようになりますので注意。

```
curl http://download.robovm.org/robovm-0.0.11.tar.gz > robovm.tar.gz
sudo tar xvfz robovm.tar.gz -C /opt
sudo ln -s /opt/robovm-0.0.11 /opt/robovm
```

#本題：リフレクションなどが動くかテスト

## 検証用ソース

```java:HelloWorld.java
import java.io.Serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;


public class HelloWorld implements Serializable {
    private static final long serialVersionUID = 1L;

    String str = "HELLO!";
    int num = 123456;
    int num2 = 65;
    float pi = 3.14159265f;

    public enum Sound {
        ARRIVAL1("se_puu10.ogg"),
        ARRIVAL2("se_puu37.ogg"),
        ARRIVAL3("se_puu26.ogg");

        private String filename_;
        private Sound(String filename) {
            filename_ = filename;
        }
        public String getFilename() {
            return filename_;
        }
    };

    public static void main(String[] args) {
        System.out.println("Hello world!");

        HelloWorld hello = new HelloWorld();

        // serialize test
        System.out.println("serialize and sate serialize.dat");
        try {
            FileOutputStream fos = new FileOutputStream("serialize.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(hello);
            oos.close();
        } catch (Exception ex) {}

        // reflection test
        for (Field field: hello.getClass().getDeclaredFields()) {
            if (!Modifier.isStatic(field.getModifiers())) {
                System.out.println("name:" + field.getName() + " type:" + field.getType());
            }
        }
                                   
        // enum test
        for (Sound sound: Sound.values()) {
            System.out.println("sound filename:" + sound.getFilename());
        }

    }
}
```

## 実行結果

動きました。
![スクリーンショット 2014-04-24 22.22.53.png](https://qiita-image-store.s3.amazonaws.com/0/42140/33e24526-e351-6d74-0cf3-186668120310.png)


# 解説
## シリアライズ
コード

```java
public class HelloWorld implements Serializable {
    private static final long serialVersionUID = 1L;

    String str = "HELLO!";
    int num = 123456;
    int num2 = 65;
    float pi = 3.14159265f;

(中略)
        // serialize test
        System.out.println("serialize and sate serialize.dat");
        try {
            FileOutputStream fos = new FileOutputStream("serialize.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(hello);
            oos.close();
        } catch (Exception ex) {}
```

　HelloWorld クラスをシリアライズしてファイル「serialize.dat」に出力しています。
　出力結果は以下のとおりです。

```
0000000    ac  ed  00  05  73  72  00  0a  48  65  6c  6c  6f  57  6f  72
0000020    6c  64  00  00  00  00  00  00  00  01  02  00  04  49  00  03
0000040    6e  75  6d  49  00  04  6e  75  6d  32  46  00  02  70  69  4c
0000060    00  03  73  74  72  74  00  12  4c  6a  61  76  61  2f  6c  61
0000100    6e  67  2f  53  74  72  69  6e  67  3b  78  70  00  01  e2  40
0000120    00  00  00  41  40  49  0f  db  74  00  06  48  45  4c  4c  4f
0000140    21  
```

当たり前ですが、Javaとして実行した場合と同じ結果になりました。


## リフレクション

```Java
        // reflection test
        for (Field field: hello.getClass().getDeclaredFields()) {
            if (!Modifier.isStatic(field.getModifiers())) {
                System.out.println("name:" + field.getName() + " type:" + field.getType());
            }
        }
```

リフレクションでHelloWorldクラスのインスタンス「hello」のフィールドを列挙して表示しています。（フィールド名と型）

```
name:pi type:float
name:num2 type:int
name:num type:int
name:str type:class java.lang.String
```

Javaで実行したときと同じ結果になりました。

## Enumに独自メソッド実装
```java
    public enum Sound {
        ARRIVAL1("se_puu10.ogg"),
        ARRIVAL2("se_puu37.ogg"),
        ARRIVAL3("se_puu26.ogg");

        private String filename_;
        private Sound(String filename) {
            filename_ = filename;
        }
        public String getFilename() {
            return filename_;
        }
    };

（略）

        // enum test
        for (Sound sound: Sound.values()) {
            System.out.println("sound filename:" + sound.getFilename());
        }
```

列挙型Sound にコンストラクタとメンバー変数を追加し、文字列型でfilename_メンバー変数を追加しました。

追加したgetFilename()メソッドで、filenameメンバーの値を取得して表示しています。

```
sound filename:se_puu10.ogg
sound filename:se_puu37.ogg
sound filename:se_puu26.ogg
```

Javaで実行したときと同じ結果になりました。


## 追記：弱参照

```java
import java.lang.ref.WeakReference;

（略）

        // WeakReference
        WeakReference<HelloWorld> helloRef = new WeakReference<HelloWorld>(hello);
        HelloWorld hello2 = helloRef.get();
        System.out.println("hello2.str:" + hello2.str);
```
WeakReferenceもOK!

```
hello2.str:HELLO!
```


とりあえずコレで安心して、Android版を作ることが出来そうです。