CreationException: Unable to create injector

原因:jdbcとplay-slickが依存性に含まれていると、それぞれがplay.api.db.DBApiを使用するので、競合してエラーとなる。

対策:jdbcの除去

参考:play-framework > [play 2.4.0-RC5 Scala] evolutions and injector error with play-slick

! @6mk485065 - Internal server error, for (GET) [/] ->

play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:

1) A binding to play.api.db.DBApi was already configured at play.api.db.slick.evolutions.EvolutionsModule.bindings(EvolutionsModule.scala:14):
Binding(interface play.api.db.DBApi to ConstructionTarget(class play.api.db.slick.evolutions.internal.DBApiAdapter) in interface javax.inject.Singleton) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1).
  at play.api.db.DBModule.bindings(DBModule.scala:25):
Binding(interface play.api.db.DBApi to ProviderConstructionTarget(class play.api.db.DBApiProvider)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

1 error]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:165) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:121) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at scala.Option.map(Option.scala:146) ~[scala-library-2.11.6.jar:na]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:121) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:119) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at scala.util.Success.flatMap(Try.scala:230) ~[scala-library-2.11.6.jar:na]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:119) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:111) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.6.jar:na]
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.6.jar:na]
    at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423) ~[na:1.8.0_05]
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) ~[na:1.8.0_05]
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:902) ~[na:1.8.0_05]
    at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1689) ~[na:1.8.0_05]
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1644) ~[na:1.8.0_05]
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) ~[na:1.8.0_05]
Caused by: com.google.inject.CreationException: Unable to create injector, see the following errors:

1) A binding to play.api.db.DBApi was already configured at play.api.db.slick.evolutions.EvolutionsModule.bindings(EvolutionsModule.scala:14):
Binding(interface play.api.db.DBApi to ConstructionTarget(class play.api.db.slick.evolutions.internal.DBApiAdapter) in interface javax.inject.Singleton) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1).
  at play.api.db.DBModule.bindings(DBModule.scala:25):
Binding(interface play.api.db.DBApi to ProviderConstructionTarget(class play.api.db.DBApiProvider)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

1 error
    at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:466) ~[guice-4.0.jar:na]
    at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:155) ~[guice-4.0.jar:na]
    at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:107) ~[guice-4.0.jar:na]
    at com.google.inject.Guice.createInjector(Guice.java:96) ~[guice-4.0.jar:na]
    at com.google.inject.Guice.createInjector(Guice.java:73) ~[guice-4.0.jar:na]
    at com.google.inject.Guice.createInjector(Guice.java:62) ~[guice-4.0.jar:na]
    at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:126) ~[play_2.11-2.4.1.jar:2.4.1]
    at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:93) ~[play_2.11-2.4.1.jar:2.4.1]
    at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21) ~[play_2.11-2.4.1.jar:2.4.1]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:153) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:150) ~[play-server_2.11-2.4.1.jar:2.4.1]
    at play.utils.Threads$.withContextClassLoader(Threads.scala:21) ~[play_2.11-2.4.1.jar:2.4.1]
    at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:150) ~[play-server_2.11-2.4.1.jar:2.4.1]
    ... 15 common frames omitted

Crashlytics Invocation Error

チームメンバーがCrashlyticsをインストールしてくれたのだが、ビルドに失敗したので、どうすればいいのか調べた。

エラーメッセージはこちら

Shell Script Invocation Error
Command /bin/sh failed with exit code 1
Crashlytics: You must install Crashlytics to continue. https://api.crashlytics.com/api/v1/******************/confirm/jp.app.appName

If this machine is a build server please remove Crashlytics.app if present and use xcodebuild so that ukissAlarm.app.dSYM is uploaded.

解決方法は単純で、Crashlyticsのビルドツールをインストールしていなかったことが原因であった。

https://crashlytics.com/downloads

Crashlyticsはなかなか良いツールだけれど、導入方法の説明ページを見つけづらくて参った。Qiita等を見てやっと解決に辿り着いた。


Crash Report解析サービスのCrashlyticsを試してみた

今回の不正解ルート
パーミッションの変更:iOS xcode 5 crashlytics error - Shell Script Invocation Error - ./Crashlytics.framework/run: Permission denied

試していないもの
Crashlytics.appを一旦削除:Crashlytics build script fails on Xcode Server CI

Scala: ファイルの内容を一行ずつ処理したい

java.nio.file.Filesで一行ごとに処理(ただしScala)

Java SE 7のjava.nio.file.Filesがとても便利な件

ファイルの内容を一行ずつ読み込んで処理したい場合に、今まではこちらのページ:(Fileの読み込み - Scala覚書)を参考に実装していましたが、nioを使えば簡単だったので、メモしておきます。

val file = Paths.get(path)
Files.readAllLines(file, Charset.defaultCharset())
     .foreach(println)

Charset.defaultCharset()が鬱陶しいですがそれに目を瞑ればシンプルです。 scala.io.Sourcejava.io.BufferedReadercommons.io.FileUtils だといずれもバッファをクローズする必要があるので、それに比べればだいぶ良いのではないでしょうか。

巨大なファイルのとき

これは、scala.io.Sourceを利用するのがよさそう。構造的部分型を利用したローンパターンを使わなければならないので、そのぶんコードが膨らみますが、そのぶん使用箇所はシンプルにまとまります。

using(Source.fromFile("file.txt")) {
     _.getLines().foreach(println)
}

def using[A <% { def close():Unit }](s: A)(f: A=>Any) {
     try f(s) finally s.close()
}

また、using内でSourceのもつメソッドを十分に活用したい場合は、構造的部分型での一般化を諦める必要があります。
参考:Scala using(ローンパターン)-Hishidama's Scala Memo-

Logbackで設定ファイルを読み込む

Logbackで設定ファイルが意図したとおりに読み込まれないという現象に遭遇したので、改めてまとめる。

読み込み順序

優先順位の高いものから順に読み込まれる。上位の条件にヒットした場合は、次の条件へは進まない。

  1. クラスパスから logback.groovy を検索する。
  2. クラスパスから logback-test.xml を検索する。
  3. クラスパスから logback.xml を検索する。
  4. JVMが ServiceLoader (JDK 6 and above) を実行している場合、ServiceLoaderは、インターフェース com.qos.logback.classic.spi.Configurator の実装のうち、最初に発見されたものを使用する。
  5. 以上がいずれも存在しなかった場合、 BasicConfigurator を使用する。

クラスパスは、起動オプション -classpath (推奨)または環境変数 ${CLASSPATH} で指定する。クラスパスで指定したディレクトリ直下のみを読み込む。

BasicConfigrator を使用する場合、ログの出力先は標準出力に向けられる。

参考: 公式

xmlファイルをjarに含めない場合

設定が変わるたびに毎度ビルドするのは面倒なので、起動オプションで指定する方法。
あらかじめjarファイルの生成時にlogback.xmlを除外したうえで、以下のオプションを指定しつつ起動すればよい。

-Dlogback.configurationFile=./logback.xml

controlling logback configuration in standalone app
Exclude logback.xml in Jar file