Play初心者がMongoDBを使えるようになるまでのメモ。
環境
Mac OS X - 10.9.2
play(java) - 2.2.3
MongoDB - 2.6.1
Eclipse - 4.3.2
ソースコード
Morphia
https://github.com/mongodb/morphia
"Morphia is a lightweight type-safe library for mapping Java objects to/from MongoDB."
どうやらこれを使えばよさそうなのでこれを使うことにします。
play-morphia
http://www.playframework.com/modules/morphia
playへmorphiaを組み込むための公式っぽいモジュールがあったっぽいですが
適用可能なplayのバージョンが1.xのみ、ということで使えません。
playMongoDemo
公式ドキュメントにMongoDB関連のドキュメントがあんまり無い気がしたので適当に検索してたら
https://github.com/czihong/playMongoDemo
playでしかもmorphiaを使っているデモを見つけられたのでcloneしてplayしようとしたら色々エラーが出て動きませんでした。
どうやらplay自体のバージョンが異なる事が原因でした。
"play migration"とかで検索するとなんだかバージョン間の移行に関するページが沢山出てきて、とりあえずそれに従って進めていましたがうまく行かないため挫折。
2.0, 2.1, 2.2でかなり変わっているようですね。playバージョン管理ツールが欲しくなりましたが存在してませんよね?
play new myapp
というわけでplayMongoDemoを参考にしつつ、自分で手探りで作っていくことにしました。
Global.java
playMongoDemoにあったのものをまるまるコピーします。
GlobalSettingsオブジェクトでアプリケーションの起動時にMongoDBに接続しているっぽいですね。
GlobalSettings
import java.net.UnknownHostException;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;
import controllers.MorphiaObject;
import play.GlobalSettings;
import play.Logger;
public class Global extends GlobalSettings {
@Override
public void onStart(play.Application arg0) {
super.beforeStart(arg0);
Logger.debug("** onStart **");
try {
MorphiaObject.mongo = new Mongo("127.0.0.1", 27017);
} catch (UnknownHostException e) {
e.printStackTrace();
}
MorphiaObject.morphia = new Morphia();
MorphiaObject.datastore = MorphiaObject.morphia.createDatastore(MorphiaObject.mongo, "test");
MorphiaObject.datastore.ensureIndexes();
MorphiaObject.datastore.ensureCaps();
Logger.debug("** Morphia datastore: " + MorphiaObject.datastore.getDB());
}
}
Global.javaで使われているMorphiaObjectもplayMongoDemoで以下のように定義されてるのでコピー。
package controllers;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;
public class MorphiaObject {
static public Mongo mongo;
static public Morphia morphia;
static public Datastore datastore;
}
build.sbt
import文で使われてる"com.google.code.morphia"とか"com.mongodb.Mongo"とかを使うためには、build.sbtに色々追記する必要があります。
libraryDependencies ++= Seq(
javaJdbc,
javaEbean,
cache,
"com.google.code.morphia" % "morphia" % "0.99",
"org.mongodb" % "mongo-java-driver" % "2.7.3",
"de.flapdoodle.embed" % "de.flapdoodle.embed.mongo" % "1.36" % "test"
)
libraryDependenciesに追記します。
デフォルトだとjavaJdbc,javaEbean,cacheのみが書かれていますが、以下の3個を追加します。一番下のやつはテストを書く時に使います。
その後、追加したライブラリを.classpathとかに反映させるためにplayコンソールに入って
eclipse with-source=true
とかしたりします。うまく行かない時はplay clean
してもう一度やったりして、今のところはうまく行きました。
モデル
https://github.com/brly/play-morphia-sample/blob/master/app/models/TestModel.java
playMongoDemoに沿って定義します。このソース例ではメンバ数を減らして、
{
name: String,
value: Int
}
こんな感じの簡単なやつです。
あとソースを見れば分かりますがRequiredアノテーションとかも使えます。
コントローラとルーティング
https://github.com/brly/play-morphia-sample/blob/master/conf/routes
https://github.com/brly/play-morphia-sample/blob/master/app/controllers/Application.java
playMongoDemoに沿って変更。play.data.Formあたりの仕様が変わってるので調整する。
ビュー
https://github.com/brly/play-morphia-sample/blob/master/app/views/index.scala.html
これはplayMongoDemoのままでも大丈夫だったような気がします。
実行
テスト
テストを書かないと色々言われるご時世なので書かないといけませんが、環境を整えなければなりません。
MySQLの場合だとplayのfakeApplication
とかinMemoryDatabase
を使えば良かったのですが、それは使えないので用意する必要があります。
という訳でまたぐぐったところ、以下の記事を見つけます。
http://www.cubeia.com/2012/03/using-mongodb-for-your-game-data/
見慣れたMorphiaという単語が安心感を与えてくれますが、新たな"EmbedMongo"という単語が出てきます。
EmbedMongo
というわけで"embedded mongo unit test"とかで検索するといかにもなページがあります。
http://quillbytes.com/display/JAVA/Setting+Up+An+Embedded+MongoDB+Database+for+Unit+Tests
でサンプル例があるのですが、サンプルのテストが書きたい感じとちょっと違います。
例ではDBCollectionとかいうオブジェクトを使ってread/writeをしてます。
TestModel.java
ではそんな感じに書いてなかったので、どうしたら良いのかよくわかりませんでしたがとりあえず以下のようにしたらfakeぽく動作するようになりました。
@Before
public void beforeTest() {
MorphiaObject.mongo = getMongoClient();
MorphiaObject.datastore = new Morphia().createDatastore(getMongoClient(), "test");
}
@Before
で毎回MorphiaObjectのmongoとdatastoreを初期化して書きたかった感じにテストを書きます。
@Test
public void 初期値は空リスト() {
assertThat(TestModel.all()).isEmpty();
}
@Test
public void addしたものが順番に取り出せる() {
TestModel ts0 = new TestModel();
ts0.name = "ほとココア";
ts0.value = 15;
TestModel.create(ts0);
TestModel ts1 = new TestModel();
ts1.name = "かふうチノ";
ts1.value = 13;
TestModel.create(ts1);
TestModel ts2 = new TestModel();
ts2.name = "てでざリゼ";
ts2.value = 16;
TestModel.create(ts2);
TestModel ts3 = new TestModel();
ts3.name = "うじまつチヤ";
ts3.value = 15;
TestModel.create(ts3);
TestModel ts4 = new TestModel();
ts4.name = "きりまシャロ";
ts4.value = 15;
TestModel.create(ts4);
assertThat(TestModel.all()).hasSize(5);
assertThat(TestModel.all().get(0).name).isEqualTo("ほとココア");
assertThat(TestModel.all().get(1).name).isEqualTo("かふうチノ");
assertThat(TestModel.all().get(2).name).isEqualTo("てでざリゼ");
assertThat(TestModel.all().get(3).name).isEqualTo("うじまつチヤ");
assertThat(TestModel.all().get(4).name).isEqualTo("きりまシャロ");
}
という訳で、なんとか環境が出来ました。