Help us understand the problem. What is going on with this article?

[Scala] ActorMaterializerのDIがうまくいかない

@singleton
class Hoge @Inject() (implicit system: ActorSystem, materializer: ActorMaterializer) {
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}

で実行すると以下のエラー

ProvisionException: Unable to provision, see the following errors:

No implementation for akka.stream.ActorMaterializer was bound.

ActorMaterializer のimplicitがないってエラーになります。
IntelliJでもちゃんとあるって判定はされているのですが・・・

調べてみても同じ記述方法でやってる人はいますね。
* https://blog.colinbreck.com/integrating-akka-streams-and-akka-actors-part-ii/
* https://www.programcreek.com/scala/akka.stream.ActorMaterializer

ハマる(1回目)

色々試してみてわかったのですが、ActorMaterialは () の宣言で挙動が変わってきそうです。
一回外に出して確認してみます。

// これは通る
@singleton
class Hoge @Inject() (implicit system: ActorSystem) {
  implicit val materializer = ActorMaterializer()
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}
// これは通らない(ActorMaterializerにかっこがないだけ)
@Singleton
class Hoge @Inject() (implicit system: ActorSystem) {
  implicit val materializer = ActorMaterializer
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}

// 結果
could not find implicit value for parameter materializer: 
akka.stream.ActorMaterializer

つまり ActorMaterializer はActorMaterializerとして判断されておらず、 ActorMaterializer() で判断されるようになるみたいです。

理由として、 ActorMaterializer() は applyが呼ばれるのですが、 ActorMaterializer だとただオブジェクトを呼んでいるだけっぽいです。
applyできずに、エラーになっているっぽいですね。ただのオブジェクトをimplicitとして渡されても困るって感じでしょうか。

object ActorMaterializer {

  def apply(materializerSettings: Option[ActorMaterializerSettings] = None, namePrefix: Option[String] = None)(implicit context: ActorRefFactory): ActorMaterializer = {
    val system = actorSystemOf(context)

    val settings = materializerSettings getOrElse ActorMaterializerSettings(system)
    apply(settings, namePrefix.getOrElse("flow"))(context)
  }

  ...
}

ActorSystemがカッコ無しで通るのは、抽象クラスになっていてそもそもの作りが全然違うからでした。

abstract class ActorSystem extends ActorRefFactory {

  ...
}

更にハマる(2回目)

ならカッコ付きで宣言したらOK って思ったのですがここで新たな問題として @Inject() の後ろでimplicitとして定義したいのですがこの中で ActorMaterializer() という記述は使えません。カッコが使えないのです。(何故?)

ActorSystemはかっこなしとありで挙動が変わらなかったのでここに書いていますが、ActorMaterializerに関しては変わるので外に出すことにしました。やってることは同じなはず・・・

@singleton
class Hoge @Inject() (implicit system: ActorSystem) {
  implicit val materializer = ActorMaterializer()
  def fuga = Try {
    Http().singleRequest(
      HttpRequest(method = HttpMethods.GET, uri = "https://mikeneko.tk"
    )
  }
}

一旦これで。
毎回 ActorMaterializerを生成するのを防ぎたいという目標自体はクリアでき他のでこれでOKとします。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした