我正在使用Object参数实现一个带有很多方法的Java接口,在我的例子中,它实际上是包含用户名的字符串:
public interface TwoFactorAuthProvider {
boolean requiresTwoFactorAuth(Object principal);
... //many more methods with the same kind of parameter
}
我正在尝试使用隐式转换将这些转换为我的实现中的User
个对象:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
def requiresTwoFactorAuth(user: User): Boolean = {
...
}
}
当我在我的班级的伴侣对象中定义转换时,它被拾起就好了,我的班级编译:
object TwoFactorAuthProviderImpl {
implicit def toUser(principal: Any): User = {
null //TODO: do something useful
}
}
但是,为了能够进行转换,我需要访问TwoFactorAuthProviderImpl
实例所拥有的用户存储库,但是配对对象却没有。我以为我可以使用隐式参数传递它:
implicit def toUser(principal: Any)(implicit repo: UserRepository): User = {
val email = principal.asInstanceOf[String]
repo.findByEmail(email)
}
但是使用隐式参数,编译器不再接收转换(抱怨我没有实现接口)。
有没有办法获得我想要的隐式转换,或者这是否超出了你可以用implicits做的范围?
答案 0 :(得分:4)
这应该可以正常工作 - 你能提供确切的编译错误吗?没有实现什么接口?您似乎必须声明如下:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository)
以下是REPL的一个示例,表明implicits可能有隐含;我正在使用粘贴模式来确保module X
是class X
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class X(i: Int, s: String)
object X { implicit def Int_Is_X(i: Int)(implicit s: String) = X(i, s) }
// Exiting paste mode, now interpreting.
defined class X
defined module X
scala> val i: X = 4
<console>:9: error: value X is not a member of object $iw
val i: X = 4
^
但是如果我们在范围
中添加隐式字符串scala> implicit val s = "Foo"
s: java.lang.String = Foo
scala> val i: X = 4
i: X = X(4,Foo)
不要过度使用隐式转换 - 我认为你在这个意义上走得太远 - 主体隐含地是一种机制,通过它你可以发现用户,它不是隐含的用户本身。我很想做这样的事情:
implicit def Principal_Is_UserDiscoverable(p: String) = new {
def findUser(implicit repo: UserRepository) = repo.findUser(p)
}
然后你可以"oxbow".findUser
答案 1 :(得分:1)
感谢Oxbow's answer,我现在有了它的工作,这仅供参考。
首先,应该作为隐式传递的值本身必须标记为隐式:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository) ...
其次,隐式转换很好,但是方法实现签名仍然必须与其声明的签名相匹配。因此,即使存在从Any
到User
的转换:
def requiresTwoFactorAuth(principal: User): Boolean = { ... }
但是将参数保留为Any
,如声明中那样,然后将其作为用户使用就可以了:
def requiresTwoFactorAuth(principal: Any): Boolean = {
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
此外,在这种情况下,转换实际上不必在伴随对象中,所以最后,我将隐式参数保留了。
完整的源代码:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
private implicit def toUser(principal: Any): User = {
val email = principal.asInstanceOf[String]
userRepository.findByEmail(email)
}
def requiresTwoFactorAuth(principal: Any): Boolean = {
//using principal as a User
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
...
}