43617


scalikeJDBCを使ってformからmysql(docker上にあるdbなのでmariaDB)にinsertしたいのですが、以下のようなエラーが出てしまいます。

[code]

    Unexpected exception
    ProvisionException: Unable to provision, see the following errors:
    
    1) Error injecting constructor, java.lang.NullPointerException
      at controllers.SignupCustomerJson.<init>(SignupControllerSupport.scala:61)
      while locating controllers.SignupCustomerJson
      for the 3rd parameter of controllers.SignupController.<init> (SignupController.scala:29)    
      while locating controllers.SignupController
      for the 4th parameter of router.Routes.<init>(Routes.scala:55) 
      while locating router.Routes
      while locating play.api.inject.RoutesProvider
      while locating play.api.routing.Router
        for the 1st parameter of play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:201)
      while locating play.api.http.JavaCompatibleHttpRequestHandler
      while locating play.api.http.HttpRequestHandler
         for the 5th parameter of play.api.DefaultApplication.<init>(Application.scala:221)
      at play.api.DefaultApplication.class(Application.scala:221)
      while locating play.api.DefaultApplication
      while locating play.api.Application
    
    1 error
    
    No source available, here is the exception stack trace:
    ->com.google.inject.ProvisionException: Unable to provision, see the following errors:
    
    com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028)
    com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054)
            play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:405)
     play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:400)
     play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:123)
     play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:168)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$2.apply(DevServerStart.scala:164)
     play.utils.Threads$.withContextClassLoader(Threads.scala:21)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:164)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:131)
     scala.Option.map(Option.scala:146)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:131)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:129)
     scala.util.Success.flatMap(Try.scala:230)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:129)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:121)
     scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
     scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
     java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
     java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
     java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
     java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
     java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
    
[/code]

なおエラー文はこのように出ることもあります（関係なさそうなimport文をコメントアウトしたりするとメッセージが変わります）

[code]

    Unexpected exception
    UnsupportedOperationException: null
    No source available, here is the exception stack trace:
    java.lang.UnsupportedOperationException: 
    scalikejdbc.ConnectionPool.close(ConnectionPool.scala:337)
     scalikejdbc.ConnectionPool$$anonfun$close$1.apply(ConnectionPool.scala:257)
     scalikejdbc.ConnectionPool$$anonfun$close$1.apply(ConnectionPool.scala:257)
     scala.Option.foreach(Option.scala:257)
     scalikejdbc.ConnectionPool$.close(ConnectionPool.scala:257)
     scalikejdbc.ConnectionPool$$anonfun$closeAll$1.apply(ConnectionPool.scala:268)
     scalikejdbc.ConnectionPool$$anonfun$closeAll$1.apply(ConnectionPool.scala:266)
     scala.collection.mutable.HashMap$$anonfun$foreach$1.apply(HashMap.scala:99)
     scala.collection.mutable.HashMap$$anonfun$foreach$1.apply(HashMap.scala:99)
     scala.collection.mutable.HashTable$class.foreachEntry(HashTable.scala:230)
     scala.collection.mutable.HashMap.foreachEntry(HashMap.scala:40)
     scala.collection.mutable.HashMap.foreach(HashMap.scala:99)
     scalikejdbc.ConnectionPool$.closeAll(ConnectionPool.scala:266)
     scalikejdbc.PlayInitializer.onStop(PlayInitializer.scala:58)
     scalikejdbc.PlayInitializer$$anonfun$1.apply(PlayInitializer.scala:65)
     scalikejdbc.PlayInitializer$$anonfun$1.apply(PlayInitializer.scala:65)
     play.api.inject.DefaultApplicationLifecycle$$anonfun$clearHooks$1$1.apply(ApplicationLifecycle.scala:94)
     play.api.inject.DefaultApplicationLifecycle$$anonfun$clearHooks$1$1.apply(ApplicationLifecycle.scala:93)
     scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
     scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249)
     scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
     play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:70)
     scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
     scala.concurrent.impl.Promise$DefaultPromise.scala$concurrent$impl$Promise$DefaultPromise$$dispatchOrAddCallback(Promise.scala:280)
     scala.concurrent.impl.Promise$DefaultPromise.onComplete(Promise.scala:270)
     scala.concurrent.Future$class.flatMap(Future.scala:249)
     scala.concurrent.impl.Promise$DefaultPromise.flatMap(Promise.scala:153)
     play.api.inject.DefaultApplicationLifecycle.clearHooks$1(ApplicationLifecycle.scala:93)
     play.api.inject.DefaultApplicationLifecycle.stop(ApplicationLifecycle.scala:101)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$apply$3.apply(DevServerStart.scala:147)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1$$anonfun$apply$3.apply(DevServerStart.scala:147)
     scala.Option.foreach(Option.scala:257)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:147)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$1.apply(DevServerStart.scala:131)
     scala.Option.map(Option.scala:146)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:131)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(DevServerStart.scala:129)
     scala.util.Success.flatMap(Try.scala:230)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:129)
     play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:121)
     scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
     scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
     java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
     java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
     java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
     java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
     java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
    
[/code]

元のcontollerのファイルはこちらです（SignupControllerSupport.scala)import部分は全然整理がついてません・・・

[code]

    package controllers
    
    import javax.inject._
    import play.api._
    import play.api.mvc._
    import views.html._  
    import play.api.data._
    import play.api.data.Forms._
    import com.github.j5ik2o.spetstore.domain.model.customer._
    import com.github.j5ik2o.spetstore.application.controller.{ ControllerSupport }
    import com.github.j5ik2o.spetstore.application.controller.json._
    import java.time.LocalDateTime
    import util.control.Exception._
    import java.sql.Connection
    import scalikejdbc._
    import scalikejdbc.SQLInterpolation._
    import scalikejdbc.config._
    import com.mysql.cj.jdbc.Driver
    import io.circe.generic.auto._
    
    class SignupCustomerJson @Inject() extends Controller
       with LoanPattern {
    
     // ---------------------------
     // Preparing Connection Pool
     // ---------------------------
    
     // loading jdbc.properties
     private val props = new java.util.Properties
          props.load(classOf[CustomerJson].getClassLoader.getResourceAsStream("jdbc.properties"))
     // loading JDBC driver
     val jdbcDriver = props.getProperty("com.mysql.cj.jdbc.Driver")
     Class.forName(jdbcDriver)
     // preparing the connection pool settings
     val poolSettings = new ConnectionPoolSettings(initialSize = 100, maxSize = 100)
     // JDBC settings
     val url = props.getProperty("jdbc:mysql://127.0.0.1:3306/spetstore?characterEncoding=utf8")
     val user = props.getProperty("admin")
     val passwordjdbc = props.getProperty("admin")
    
     // create singleton(default) connection pool
     ConnectionPool.singleton(url, user, passwordjdbc, poolSettings)
     // named connection pool
     //  ConnectionPool.add('spetstore, url, user, passwordjdbc, poolSettings)
    
     // ---------------------------
     // Working with DBSession
     // ---------------------------
    
     val tableNamePrefix = "" + System.currentTimeMillis().toString.substring(8)
    
     val customer = tableNamePrefix + "_localTx"
    
     /** 登録 */
     def insert(customerJson: CustomerJson): Unit = {
    
    implicit val db = DB(ConnectionPool.borrow())
    
    val status = 0
    
    try {
    
        using(DB(ConnectionPool.borrow())) { db =>
    
          db.begin()
    
          DB localTx { implicit session =>
    
          SQL("""insert into" customer (pk, id, status, name, zipCode1 + zipCode2, prefCode, cityName, addressName, building, email, phone, loginName, password, favoriteCategoryId, version) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""").update.apply()
    
          }
    
          db.commit()
    
        }
    
      } finally { db.rollbackIfActive() }
    
      { db.close() }
    
     }
    
    }
    
[/code]

Actionメソッドを呼び出すのはこちらからになります(SignupController.scala)

[code]

    package controllers
    
    import javax.inject._
    import play.api._
    import play.api.mvc._
    import views.html._
    import play.api.data._
    import play.api.data.Forms._
    import com.github.j5ik2o.spetstore.domain.model.customer._
    import com.github.j5ik2o.spetstore.application.controller.{ ControllerSupport     }
    import com.github.j5ik2o.spetstore.application.controller.json._
    import controllers.{ SignupCustomerJson }
    import play.api.i18n.{ I18nSupport, MessagesApi }
    import play.api.i18n.Messages.Implicits._
    import scala.util.Random
    
    class SignupController @Inject() (val messagesApi: MessagesApi, val messagesApi2: MessagesApi, val signupCustomerJson: SignupCustomerJson) extends Controller
         with play.api.i18n.I18nSupport {
    
      val customerForm = Form(
      // Userフォームマッピング
      mapping(
        "id" -> optional(text),
        "name" -> nonEmptyText(minLength = 4),
        "sexType" -> number,
        "zipCode1" -> text(minLength = 3, maxLength = 3),
        "zipCode2" -> text(minLength = 4, maxLength = 4),
        "prefCode" -> number,
        "cityName" -> text,
        "addressName" -> text,
        "buildingName" -> optional(text),
        "email" -> text,
        "phone" -> text,
        "loginName" -> text,
        "password" -> text,
        "favoriteCategoryId" -> optional(text),
        "version" -> optional(longNumber)
    
       )(CustomerJson.apply)(CustomerJson.unapply)
      )
    
      // 入力ページを表示するAction
      def signup = Action {
       Ok(views.html.signup(messagesApi.toString, customerForm))
      }
    
      // 結果ページを表示するAction
      def signupresult = Action { implicit request => // リクエストオブジェクトを宣言
        customerForm.bindFromRequest().fold(
        SignupFailure => { // バインドエラー ＝ 入力エラーが発生した場合
        Ok(views.html.signup(messagesApi.toString, SignupFailure)) // 入力画面を再表示します。
        },
        SignupOK => { // バインド成功 ＝ 入力エラーがない場合
          val id = Random.nextInt(1000000).toString
          val signupstatus = 0
          signupstatus match {
            case 0 => insert(SignupOK)
            }
          Ok(views.html.signupresult(messagesApi2.toString, customerForm.fill(SignupOK))) // 結果画面を表示します。
          }
        )
     }
    
      def insert(customerForm: CustomerJson) = signupCustomerJson.insert(CustomerJson(customerForm.id, customerForm.name, customerForm.sexType, customerForm.zipCode1, customerForm.zipCode2, customerForm.prefCode, customerForm.cityName, customerForm.addressName, customerForm.buildingName, customerForm.email, customerForm.phone, customerForm.loginName, customerForm.password, customerForm.favoriteCategoryId, customerForm.version))
    
     }
    
[/code]

DBの初期化のファイルはこちらになります。(DBInitializer.scala)。githubに上がっていたサンプルをそのまま使わせて頂いているので手を加えていません。

[code]

    package com.github.j5ik2o.spetstore.infrastructure.db
    
    import com.typesafe.config.ConfigFactory
    import scalikejdbc._, SQLInterpolation._
    
    object DBInitializer {
      def run() {
        val config = ConfigFactory.load()
        val driverClassName = config.getString("db.default.driver")
        val url = config.getString("db.default.url")    
        val user = config.getString("db.default.user")
        val password = config.getString("db.default.password")
        Class.forName(driverClassName)
        ConnectionPool.singleton(url, user, password)
        DB readOnly {
           implicit s =>
           try {
               sql"select 1 from customer limit 1".map(_.long(1)).single().apply()
           } catch {
               case e: java.sql.SQLException =>
                 DB.localTx {
                   implicit s =>
                     sql"""
    DROP TABLE IF EXISTS `customer`;
    """.execute().apply()
                sql"""
    CREATE TABLE `customer` (
       `pk`                    BIGINT        NOT NULL AUTO_INCREMENT,
       `id`                    BIGINT        NOT NULL,
       `status`                INT           NOT NULL,
       `name`                  VARCHAR(256)  NOT NULL,
       `sex_type`              INT       NOT NULL,
       `zip_code`              VARCHAR(20)   NOT NULL,
       `pref_code`             INT           NOT NULL,
       `city_name`             VARCHAR(256)  NOT NULL,
       `address_name`          VARCHAR(256)  NOT NULL,
       `building_name`         VARCHAR(256),
       `email`                 VARCHAR(64)   NOT NULL,
       `phone`                 VARCHAR(64)   NOT NULL,
       `login_name`            VARCHAR(64)   NOT NULL,
       `password`              VARCHAR(64)   NOT NULL,
       `favorite_category_id`  BIGINT,
       PRIMARY KEY(`pk`),
       UNIQUE(`id`)
     );
     """.execute().apply()
    
[/code]

エラー一行目でコンストラクタがないと言われてる気はするんですが、いじってみたものの見当がつきません…。

4/28 大きな勘違いをしていたようで、connectionpoolの以下の一文を直しました。

[code]

       val props = new java.util.Properties props.load(classOf[Settings].getClassLoader.getResourceAsStream("jdbc.properties"))
    
[/code]

ですが今度は not found:type と言われてしまったので、

[code]

    class SignupCustomerJson @Inject() extends Controller
    with LoanPattern with Settings {
    
[/code]

としてみたのですが、やはり変化はありません。

ご回答いただければ幸いです。


CC BY-SA 3.0
2018-04-25T11:15:45.473
43546
2018-04-28T03:22:17.537
2018-04-28T03:22:17.537
28048
28048
question
mysql scala playframework scalikejdbc
ProvisionException: Unable to provision / Error injecting constructor, java.lang.NullPointerException


まずは、Play2.5でscalikejdbcをとりあえず使ってみたい場合、以下のハンズオン資料で勉強されることをお勧めします。  
<http://bizreach.github.io/play2-hands-
on/play2.5-scalikejdbc2.5/introduction.html>

* * *

<https://github.com/j5ik2o/spetstore>

おそらく上記のリポジトリをcloneして改変しながら学習されているものと思いますが、そもそも`DBInitializer.run()`はどこからも呼び出されていないので、これを変更しても意味は無いかと思います。

このリポジトリでは`scalikejdbc-play-
initializer`が使用されていますので、`conf/application.conf`にDBの接続情報を書いておけば、play起動時に自動的にDB接続設定が行われます。

<http://scalikejdbc.org/documentation/playframework-support.html>

また、MariaDBをお使いとのことなので、専用のDriverを使うように設定したほうが良いと思います。以下に設定例を記載しますが、url,
username, passwordは適宜変更してください。

**conf/application.conf**

[code]

    // 中略
    
    db {
      default.driver=org.mariadb.jdbc.Driver
      default.url="jdbc:mariadb://127.0.0.1:3306/spetstore?characterEncoding=utf8"
      default.username="admin"
      default.password="password"
    
      default.poolInitialSize = 10
      default.poolMaxSize = 10
      default.poolValidationQuery = "select 1 as one"
    }
    
    // 中略
    
[/code]

**build.sbt**

[code]

    libraryDependencies ++= Seq(
      // ...
      "org.mariadb.jdbc" % "mariadb-java-client" % "2.2.3",
      // ...
    }
    
[/code]

* * *

上記の通り、`scalikejdbc-play-initializer`でDB接続設定は自動的に行われますので、DB設定のコードはすべて不要です。  
また、`SignupCustomerJson`はControllerではないように見受けられますので、play.api.mvc.Controllerを継承する必要はありません。

質問に書かれてる最初のエラーは、Controllerを継承しているclassをControllerのコンストラクタ引数に渡してDependency
Injectionしていることが原因で出ているエラーかと思います。

※`conf/routes`ファイルでリクエストの種類に応じて処理を行うclassがControllerになります

また、シングルトンで問題ないと思いますのでobjectにするのが良いと思います。

[code]

    package com.github.j5ik2o.spetstore.application.controller
    
    import com.github.j5ik2o.spetstore.application.controller.json.CustomerJson
    
    import scalikejdbc._
    
    object SignupCustomerJson {
    
      /** 登録 */
      def insert(customerJson: CustomerJson): Unit = {
        try {
          DB localTx { implicit session =>
            val status = 0
    
            import customerJson._
            sql"""insert into customer (id, status, name, sex_type, zip_code, pref_code, city_name, address_name, building_name, email, phone, login_name, password, favorite_category_id)
                 |values ($id, $status, $name, $sexType, ${zipCode1 + zipCode2}, $prefCode, $cityName, $addressName, $buildingName, $email, $phone, $loginName, $password, $favoriteCategoryId)"""
              .stripMargin
              .update
              .apply()
          }
        } catch {
          case e: Exception => e.printStackTrace()
        }
      }
    
    }
    
[/code]

`SignupCustomerJson`をシングルトンにしたので、`SignupCustomerJson.insert()`で処理を呼び出せます。

`SignupController`のコンストラクタから`SignupCustomerJson`を削除してください。  
また、`insert()`にCustomerJsonを渡していますので、その変数をそのまま`SignupCustomerJson.insert()`に渡せるかと思います。

[code]

    class SignupController @Inject() (
        val messagesApi: MessagesApi,
        val messagesApi2: MessagesApi
    ) extends Controller with play.api.i18n.I18nSupport {
    
    // 中略
    
      def insert(customerJson: CustomerJson): Unit = SignupCustomerJson.insert(customerJson)
    
    }
    
[/code]

ここまで変更して頂いた後に別のエラーが出た場合は、新たに別の質問として投稿していただければ幸いです。


CC BY-SA 3.0
2018-04-27T18:41:03.900
43617
2018-04-27T18:55:11.677
2018-04-27T18:55:11.677
3068
3068
43546
answer