Binding/Injecting 使用 Guice 的 Scala 函数(不是整个 class)?
Binding/Injecting a Scala function (not whole class) using Guice?
我想将 UserDao
对象的 byId
方法注入到 Authentication
对象的构造函数中。我想避免注入整个 class.
// Has def byId(id: UserId): Option[User]
bind(classOf[UserDao]).asEagerSingleton()
// Something like this
bindMethod(classOf[UserDao], _.byId)
// Constructor takes a (UserId) => Option[User] function
bind(classOf[Authentication]).asEagerSingleton()
我在 Play Framework 中使用 Guice。任何建议表示赞赏
其实你要的是封装?
如果是这样,我建议使用这样的代码:
// User model
case class User(id: UUID, name: String)
trait AuthenticationUserDao{
def findById: Option[User]
}
class UserDao extends AuthenticationUserDao {
override def findById: Option[User] = ???
def add(user: User): Boolean = ???
def delete(userId: UUID): Boolean = ???
}
// ...
class Authentication @Inject() (
authenticationUserDao: AuthenticationUserDao
) extends Controller {
// Here only the method findById is available (not tested, but i guest it's the case here)
def findUser(userId: UUID) = Action {
authenticationUserDao.findById(userId)
}
}
// ...
bind(classOf[UserDao]).to(classOf[AuthenticationUserDao])
希望我已经明白了。
你问这个问题是对的,因为它可以大大简化测试。诀窍是使用 @Provides 注释:
TL;DR
class MyController @Inject() (byId: (UserId) => Option[User]) extends Controller { ... }
@Provides
def userDao(aDependency: Any): UserDao = // return UserDao, note aDependency will be injected
@Provides
def byId: (UserId) => Option[User] = userDao.byId // note: this method will call the other @Provides method 'userDao'
说明
最终 byId: (UserId) => Option[User]
转换为 scala.Function1[UserId, Option[User]]
但是您可以使用语法糖来声明函数依赖关系:
class MyController @Inject() (_addTwo: (Int, Int) => Int) extends Controller {
def addTwo(a: Int, b: Int) = Action {
Ok(_addTwo(a, b).toString) // call the injected function
}
}
然后在您的 Module.scala 中创建一个方法,其中 returns 函数:
@Provides
def addTwo: (Int, Int) => Int = (a, b) => a + b
您可以在 @Provides 方法中执行所有常见的 Scala 操作,例如返回部分应用的函数:
@Provides
def addTwo: (Int, Int) => Int = addThree(0, _:Int, _:Int)
def addThree(a: Int, b: Int, c: Int): Int = a + b + c
为避免冲突,您还可以使用 @Named 注释:
class MyController @Inject() (@Named("addTwo") _addTwo: (Int, Int) => Int,
@Named("subtractTwo") _subTwo: (Int, Int) => Int)
extends Controller { ... }
@Provides
@Named("addTwo")
def addTwo: (Int, Int) => Int = (a, b) => a + b
@Provides
@Named("subtractTwo")
def subTwo: (Int, Int) => Int = (a, b) => a - b
我想将 UserDao
对象的 byId
方法注入到 Authentication
对象的构造函数中。我想避免注入整个 class.
// Has def byId(id: UserId): Option[User]
bind(classOf[UserDao]).asEagerSingleton()
// Something like this
bindMethod(classOf[UserDao], _.byId)
// Constructor takes a (UserId) => Option[User] function
bind(classOf[Authentication]).asEagerSingleton()
我在 Play Framework 中使用 Guice。任何建议表示赞赏
其实你要的是封装?
如果是这样,我建议使用这样的代码:
// User model
case class User(id: UUID, name: String)
trait AuthenticationUserDao{
def findById: Option[User]
}
class UserDao extends AuthenticationUserDao {
override def findById: Option[User] = ???
def add(user: User): Boolean = ???
def delete(userId: UUID): Boolean = ???
}
// ...
class Authentication @Inject() (
authenticationUserDao: AuthenticationUserDao
) extends Controller {
// Here only the method findById is available (not tested, but i guest it's the case here)
def findUser(userId: UUID) = Action {
authenticationUserDao.findById(userId)
}
}
// ...
bind(classOf[UserDao]).to(classOf[AuthenticationUserDao])
希望我已经明白了。
你问这个问题是对的,因为它可以大大简化测试。诀窍是使用 @Provides 注释:
TL;DR
class MyController @Inject() (byId: (UserId) => Option[User]) extends Controller { ... }
@Provides
def userDao(aDependency: Any): UserDao = // return UserDao, note aDependency will be injected
@Provides
def byId: (UserId) => Option[User] = userDao.byId // note: this method will call the other @Provides method 'userDao'
说明
最终 byId: (UserId) => Option[User]
转换为 scala.Function1[UserId, Option[User]]
但是您可以使用语法糖来声明函数依赖关系:
class MyController @Inject() (_addTwo: (Int, Int) => Int) extends Controller {
def addTwo(a: Int, b: Int) = Action {
Ok(_addTwo(a, b).toString) // call the injected function
}
}
然后在您的 Module.scala 中创建一个方法,其中 returns 函数:
@Provides
def addTwo: (Int, Int) => Int = (a, b) => a + b
您可以在 @Provides 方法中执行所有常见的 Scala 操作,例如返回部分应用的函数:
@Provides
def addTwo: (Int, Int) => Int = addThree(0, _:Int, _:Int)
def addThree(a: Int, b: Int, c: Int): Int = a + b + c
为避免冲突,您还可以使用 @Named 注释:
class MyController @Inject() (@Named("addTwo") _addTwo: (Int, Int) => Int,
@Named("subtractTwo") _subTwo: (Int, Int) => Int)
extends Controller { ... }
@Provides
@Named("addTwo")
def addTwo: (Int, Int) => Int = (a, b) => a + b
@Provides
@Named("subtractTwo")
def subTwo: (Int, Int) => Int = (a, b) => a - b