タイトル/名前 | 更新者 | 更新日 |
---|---|---|
Groovy/Maven/Java + TestNG Example | msakamoto-sf | 2013-07-15 11:39:26 |
Groovy | msakamoto-sf | 2013-07-15 10:50:51 |
Java/Maven3/ローカルのjarファイルを参照させるには | msakamoto-sf | 2013-07-15 10:49:15 |
Groovy/Gradle/ローカルのjarファイルを参照させるには | msakamoto-sf | 2013-07-15 10:48:23 |
Groovy/groovy.transform : "@Canonical", "@Immutable" | msakamoto-sf | 2013-07-14 23:13:51 |
Java/「現在ディレクトリ」(Current Working Directory)の変更 | msakamoto-sf | 2013-07-14 15:47:01 |
Java/OSの種類とバージョンの判別 | msakamoto-sf | 2013-07-14 15:25:00 |
Java/Maven3/${basedir}, ${project.*}, ${setting.*}, ${env.*}, and others in pom.xml | msakamoto-sf | 2013-07-14 12:53:26 |
Java/Maven3/tools.jarを使う時のトラブルシュート(<scope>=system, <systemPath>) | msakamoto-sf | 2013-07-14 12:48:20 |
Java/標準入力, コンソール入力の読み取り(System.in, System.console(), java.io.Console) | msakamoto-sf | 2013-07-14 12:03:47 |
Groovyの面白いところは、Javaのprivateフィールドに何も特別な操作なしで参照したり更新することが出来る点です。
これは、特にレガシーコードをJUnitやTestNGなどの単体テストフレームワークに組み込むときに大変便利な特性になります。
本記事ではJavaのコードをGroovyで記述したTestNGのテストケースを使ってテストしてみて、privateを操作するテストコードのごく簡単なサンプルをMavenで組んでみます。
※2013-04-27追記:本記事ではGMavenを使っています。MavenでのGroovy/Javaのビルド("Joint Compile")で、もう少し実践的な構成にしたり、GMavenでなくmaven-antrun-plugin + GroovyのAntTaskを使ったMavenビルドの例を Groovy/Maven/Examples (includes "Java Joint Compile") にまとめていますので、Maven設定の細かい調整はそちらを参照してください。
※2013-07-15追記:Maven3にて、JUnit(Java, Groovy) + TestNG(Java, Groovy) + Spock(Groovy)の5種類のテストケースを一気に実行するサンプルを用意しましたので、手っ取り早くコピペしたい場合はそちらを参照してみてください: Java/Maven3/JUnit, Spock, TestNGを同時実行する
Groovyに関するエントリや、役立ちリンクなど。
日記などより:
入門やチートシート:
リモートリポジトリ上のjarではなく、3rdパーティ製のライブラリなどを参照させたい場合、大雑把には以下の選択肢があります。
本記事では、ローカルファイルシステム上のjarを参照する方法についてごく簡単に紹介します。
解説に使うサンプル(JDK 1.7, Maven 3.0.5, Win7SP1にて動作確認):
https://github.com/msakamoto-sf/javasnack
サンプルではごく簡単なjarファイルをMavenプロジェクト内の専用ディレクトリにインストールします。
まず対象のjarファイルは以下に用意します。作成方法などは同じディレクトリ中にあるREADME.txtを参照してください。
javasnack/subprojects/jar1/testjar1-1.0.jar
続いて、Mavenプロジェクト内に、リポジトリとして参照するためのディレクトリを作成します。以下がサンプルでのディレクトリです:
javasnack/subprojects/subprojects/repo
あとは"-DlocalRepositoryPath"で上記ディレクトリを指定して、"mvn install:install-file"を実行します。"groupId", "artifactId", "version" は後でpom.xmlの依存性設定で使いますので、分かりやすい名前にしておきましょう。
cd javasnack/ mvn install:install-file \ -DlocalRepositoryPath=subprojects/repo \ -DcreateChecksum=true \ -Dpackaging=jar \ -Dfile=subprojects/jar1/testjar1-1.0.jar \ -DgroupId=subprojects \ -DartifactId=testjar1 \ -Dversion=1.0
サンプルでは、面倒臭いのでインストールした状態の"subprojects/repo"をGitリポジトリにUPしてしまってます。
あとはpom.xmlで依存性を追加します。まず<repositories>でローカルリポジトリを定義します。
<repositories> <repository> <id>projectlocalrepo</id> <url>file://${project.basedir}/subprojects/repo</url> </repository> </repositories>
依存性は、"mvn install:install-file" 時に指定したgroupId, artifactId, versionを指定します。
<dependency> <groupId>subprojects</groupId> <artifactId>testjar1</artifactId> <version>1.0</version> </dependency>
なお、試してないのでちょっと自信が無いのですが、"$HOME/.m2/"以下のリポジトリにインストールするには"mvn install:install-file"で"-DlocalRepositoryPath=subprojects/repo"のオプション指定を削除するとそちらにインストール出来るような気がします・・・。
またその場合は、pom.xmlにリポジトリの指定は要らなくなる・・・筈・・・。
以前の記事、 Java/Maven3/tools.jarを使う時のトラブルシュート(<scope>=system, <systemPath>) を参考にしてください。JDKのtools.jarが、外部3rdパーティのjarになるだけの筈です。
ただし"<scope>"をsystemに設定した場合、fatjarやonejar, war, earなどにアーカイブする際、ちゃんとまとめてくれるのかどうか怪しいので、確認が必要になると思います。
参考資料:
なお、Gradleを使うとリポジトリの用意など無しに、もっと簡単に実現出来ます: Groovy/Gradle/ローカルのjarファイルを参照させるには
リモートリポジトリ上のjarではなく、3rdパーティ製のライブラリなどを参照させたい場合、以下のように簡単に依存性を設定出来ます。
dependencies { runtime files('libs/a.jar', 'libs/b.jar') runtime fileTree(dir: 'libs', include: '*.jar') }
Gradle 1.6で確認済みです。
なお、"file('libs/a.jar')"はサポートしていないらしく、エラーになりました。1個だけでも"files()"を使う必要がありました。
参考資料:
Maven3で同じ事をしようとした場合: Java/Maven3/ローカルのjarファイルを参照させるには
"groovy.transform" パッケージをみてみると、色々とGroovy言語のコアに関わっていたり、プログラミングを省力化してくれそうなアノテーションがあります。
以下、"@Canonical", "@Immutable" のごく簡単な紹介。
参考資料:
Javaで、「現在ディレクトリ」(Current Working Directory)は変更出来るか?
→答え:「現在ディレクトリの変更」が、unixで言うところのchdir(2), WindowsAPIでのSetCurrentDirectory()を呼ぶ、という意味であれば、JDK 1.7現在でもJDKライブラリの世界だけでは出来ません。それらのAPIを叩くインターフェイスが用意されてないっぽい。
もちろんchdir(2)とかSetCurrentDirectory()を呼ぶJNIを作成して叩かせるとかすれば無理やり出来ると思いますが、そもそもJDKはそういう状況を想定していないため、アチコチで嵌りそうな気がします。
→ただし、「ファイル名解決に使う現在ディレクトリを変更する」という意味であれば回避策はあるようです。
Fileクラスのコンストラクタには、ファイル名解決に使う親ディレクトリの有無でバリエーションがあります。親ディレクトリが指定されていれば、そこを現在ディレクトリとして相対パスを解決します。指定されていない(むしろそちらのほうがよく使われる)コンストラクタでは、System.getProperty("user.dir")を使って相対パスを解決します。
つまり、Fileクラスのコンストラクタによるファイル名の解決においては、System.getProperty("user.dir")がデフォルトの「Current Working Directory」であり、「Current Working Directory」を変更したければ、単にFileクラスのコンストラクタでparentを指定するバージョンを使い、parentに自前で用意した「現在ディレクトリ」を指すFileオブジェクトを指定すればよい、という流れになります。
※System.setProperty("user.dir", ...)しちゃっても大丈夫かどうかはちょっと自信ないです・・・。
→もしも「外部プロセスを起動した時の現在ディレクトリを変更する」という意味であれば、ProcessBuilderを使うことで現在ディレクトリを明示的に指定して、外部プロセスを起動することが可能です。(多分、ProcessBuilderのdirectory()メソッドでイケる・・・筈・・・)
参考資料:
OSの種類とバージョンの判別ですが、JDKライブラリ単体だけですと "os.arch"/"os.name"/"os.version"のシステムプロパティ(System.getProperty())の値を自前で処理してそれぞれ判別する必要があります。
JDK7, Win7SP1(64bit), Corei5上:
os.arch -> "amd64" os.name -> "Windows 7" os.version -> "6.1"
Apache Commons の commons-lang3 を使うと、org.apache.commons.lang3.SystemUtils に "IS_OS_XXXX" というstaticなboolean値がセットされるので、これを使って
if (SystemUtils.IS_WINDOWS) { if (SystemUtils.IS_OS_WINDOWS_7) { ...
のようなコードが書けるようになります。
参考:
pom.xml中で
${basedir}
とか
${project.build.directory}
など、Mavenのプロジェクトの設定や、環境変数などを参照する方法の参考資料:
Mavenでtools.jarを参照するときに、主に環境面でトラブルに遭遇することがあります。
そこで主なトラブルと対処法についてまとめてみました。
"<dependency>"で"<scope>"に"system"を設定します。これはローカル上のjarファイルをコンパイル時に参照させたい(でもパッケージング時には含めない)場合に使います。"<systemPath>"によりローカル上のtools.jarを指定します。
pom.xmlの"<dependency>"の例(Windows or unix):
<dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>1.5</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency>
MacOSXの場合はtools.jarがclasses.jarに含まれているので不要のようです。
このようにOS毎に設定を切り替えるにはMavenの"profile"という機能を使います。
以下に2種類のバリエーションを紹介します。
<profiles> <profile> <id>windows_profile</id> <activation> <os> <family>Windows</family> </os> </activation> <properties> <toolsjar>${java.home}/../lib/tools.jar</toolsjar> </properties> </profile> <profile> <id>osx_profile</id> <activation> <os> <family>mac</family> </os> </activation> <properties> <toolsjar>${java.home}/../Classes/classes.jar</toolsjar> </properties> </profile> </profiles>
<profile> <id>excluding_mac</id> <activation> <os> <family>!mac</family> </os> </activation> <dependencies> <dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>1.5.0</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> </dependencies> </profile>
他、参照:
mvn単体で発生する場合と、mvnでは問題ないのにEclipse + m2eプラグインだと発生してしまう場合があります。
結論から言うと、mvn または Eclipse のランタイム環境がJDKであることを確認してください。
前述のとおり"<systemPath>"に ${java.home} からの相対パスを指定している場合は特にこれでトラブルになる可能性が高いと思われます。
> mvn -version Apache Maven 3.0.4 (r1232337; 2012-01-17 17:44:56+0900) Maven home: C:\in_vitro\apps\apache-maven-3.0.4\bin\.. Java version: 1.6.0_22, vendor: Sun Microsystems Inc. Java home: C:\Program Files\Java\jdk1.6.0_22\jre Default locale: ja_JP, platform encoding: MS932 OS name: "windows 7", version: "6.1", arch: "x86", family: "windows"
なおその上で、pom.xmlでjvmのバージョンや"<systemPath>"の指定を確認し、最終的に参照されるtools.jarの存在を確認してください。
まずEclipse + m2e環境でtools.jarへの参照を解決できない場合、問題やエラーログに詳細が表示されますので確認してください。
自分の場合、以下の様なログが出ていました。
Missing artifact com.sun:tools:jar:1.5.0 pom.xml コンテナー 'Maven 依存関係' が存在しないライブラリー 'C:\Users\xxxxxx\.m2\repository\com\sun\tools\1.5.0\tools-1.5.0.jar' を参照しています ビルド・パスのエラーが解決されるまで、プロジェクトをビルドできません
→ "${java.home}"でなく、"$HOME/.m2/repository"を参照している時点で明らかにJavaのランタイム環境がおかしくなっています。
EclipseのランタイムJava環境は「ヘルプ」→「Eclipseについて」→「インストール詳細」→「構成」タブから"-vm"行を確認します。これがJDKになっていない場合は、eclipse.ini(Winならeclipse.exeと同じフォルダにある)に"-vm"オプションを追加します。なお"-vm"オプションは"-vmargs"の前に設定することを忘れずに。"-vmargs"以下はJVMへの引数として解釈されてしまいます。
例:
... -vm C:/Program Files/Java/jdk1.6.0_xx/bin/javaw.exe -vmargs ...
参考:(最初m2eのバグの可能性も考えて色々調べたのですが、結局ランタイムがJDKになってなかったことが原因でした)
コマンドラインツールで、プロンプトを表示してユーザからの入力を読み取りたいときに。
JDK1.5まで:System.inから読み取る方式。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print("prompot:>"); String input = br.readLine().trim(); System.out.println("Input = [" + input + "]");
JDK1.6から:標準入力がコマンドプロンプトやターミナルであれば、System.console()が返すjava.io.Consoleクラスのインスタンスでプロンプト表示+一行入力読み取りのショートカットが提供されてる。
Console console = System.console(); if (null == console) { System.out .println("'System.console()' returns null, Console is disabled."); } else { console.printf("Console Output Example %s%n", "abcdefg"); String input = console.readLine("[%s %s]>", "abc", "def"); console.printf("Input = [%s]%n", input); char[] password = console.readPassword("input dummy password>"); console.printf("Input Password = [%s]%n", new String(password)); }
注意点:
サンプル(JDK 1.7で確認):
参考資料: