結論からいうと別においしくない。
何故Androidでjava1.7が使えないか
javaをコンパイルして生成されるclassファイルの中には、「オレ、このバージョンでコンパイルされてるんでヨロ」という情報が入ってます。んでjavaの実行環境側でclassファイルをロードする時にサポートしているバージョンでコンパイルされたclassファイルかどうかをチェックして、もしサポート外ならエラーを投げる様になってます。
Androidだとclassを生成後、dexファイルに変換する所で以下の様に怒られます。
bad class file magic (cafebabe) or version (0033.0000)「このきたならしい阿呆がァーッ!!」
classファイルのversionが間違ってると言われてますね。
0x33は51です。java1.7でコンパイルするとclassファイルのバージョンは51になるんすねー。1.6なら50。
で、どうする
dexで怒られるのでAndroidで使えないのは分かりました。じゃあどうしたらええのか。長いjavaの歴史、互換性に関しても色々ノウハウあるんちゃうん、という事でありました。下位互換のオプションが。
Java7シンタックスで レガシーコードを快適メンテナンス
とか
javac - Java プログラミング言語コンパイラ
を見ますと、javacに-target付けてコンパチなclassファイルが作れるようですね
Eclipse+ADTでは無理
結論から言うとEclipseでは無理です。
設定で以下の様に生成するclassファイルのバージョン指定とか出来ますが、
ADTに怒られます。
Android requires compiler compliance level 5.0 or 6.0. Found '1.7' instead. Please use Android Tools > Fix Project Properties.
無理です。
antならいける
antではどうでしょうか。
Android用のbuild.xmlを見る
とりあえずANDROID_HOME/tools/ant/build.xmlの-compileタスクを見てみます。このbuild.xmlはandroidコマンドなどで生成したAndroidプロジェクトに生成されるbuild.xmlでimportされているAndroidアプリケーションをビルドする為のタスクが詰まっているファイルです。
<target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> <!-- merge the project's own classpath and the tested project's classpath --> <path id="project.javac.classpath"> <path refid="project.all.jars.path" /> <path refid="tested.project.classpath" /> </path> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" bootclasspathref="project.target.class.path" verbose="${verbose}" classpathref="project.javac.classpath" fork="${need.javac.fork}"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> <compilerarg line="${java.compilerargs}" /> </javac> ~~略~~
javacタスクの所にtargetというのがありますね。
値は${java.target}という変数です。
${java.target}の定義を見ると
<property name="java.target" value="1.5" /> <property name="java.source" value="1.5" />
1.5になってますねー。
java.sourceの方はjavaファイルがどのバージョンかを表すオプション-sourceに渡す値です。こちらも1.5になっています。
これらを以下の様にするとどうでしょうか
<property name="java.target" value="jsr14" /> <property name="java.source" value="1.7" />
antでビルドしてテスト走らしてみる
上の設定にした状態で、以下のテストコードをBuild&Runしてみます。
ちなみにJUnit4 works on Androidあたりを参考にしてjunit4に対応させています。
@Test public void Itemテーブルにレコードを1件追加する(){ String moge = "ふがふが"; switch(moge){ case "ふがふが": Log.d("tag", "hogeeeeee!"); break; case "moge": Log.d("tag", "moge"); break; default: Log.d("tag", "あれえ"); } }
はいビルド&実行
ant debug installd ant test
キタ━━━━(゚∀゚)━━━━!!
I/System.out(13216): org.junit.runners.Suite I/TestRunner(13216): started: Itemテーブルにレコードを1件追加する(jp.dip.sys1.yagi.amp.sample.dao.ItemDaoBaseTest) D/tag (13216): hogeeeeee! I/TestRunner(13216): finished: Itemテーブルにレコードを1件追加する(jp.dip.sys1.yagi.amp.sample.dao.ItemDaoBaseTest)
いけましたね。
ANDROID_HOME/tools/ant/build.xmlをいじるのは嫌だよね
基本的にANDROID_HOME配下のヤツをいじって何かに対応するのは緊急の場合を除いてしたくないっすね。もろに環境依存だし。つーことで、なんとかANDROID_HOME/tools/ant/build.xmlのプロパティを外部からいじれねーかと、もちろんいじれます。
ant debug -Djava.target=jsr14 -Djava.source=1.7
こうです。-Dオプションです。debugの所はreleaseとかinstrumentでももちいけますです。これでjava.targetとかが書き換えられます。
終わりに
java1.7の機能でめぼしいのってtry-with-resourcesと例外のマルチキャッチくらいだなーと思ってるけどjsr14では
try-with-resourcesは使えないようなので
なんだかなーと。(try-with-resourcesはAutoCloseableというjava1.7で追加されたinterfaceで実現しているので当然1.6以前には存在しないから無理ぽという事。これ以外でもjava1.7で追加されたAPIとかはもち使えないと思う。)あとEclipseで使えないので実用性はあんまりないなーと。
どーしても使いたい、という場合向けだけど微妙。
以上
参考になりました。ありがとうございます。
返信削除