I am using Scala bCrypt wrapper for encrypting user password, this wrapper provides an implicit class.
package object bcrypt {
implicit class Password(val pswrd: String) extends AnyVal {
def bcrypt: String = B.hashpw(pswrd, BCrypt.gensalt())
def bcrypt(rounds: Int): String = B.hashpw(pswrd, BCrypt.gensalt(rounds))
def bcrypt(salt: String): String = B.hashpw(pswrd, salt)
def isBcrypted(hash: String): Boolean = B.checkpw(pswrd, hash)
}
def generateSalt: String = B.gensalt()
}
But I am facing a strange problem, whenever I am using this Implicit converision in class it workes fine but converiosn doesnt work with object or case classes.
scala> import com.github.t3hnar.bcrypt._
import com.github.t3hnar.bcrypt._
scala> class Password(secret: String) {
| def validate(userSecret: String): Boolean = userSecret.isBcrypted(secret)
|
| override def toString = secret
| }
defined class Password
scala> object Password {
| def apply(secret: String): Password = new Password(secret)
|
| def getEncrypted(secret: String) = new Password(secret.bcrypt)
| }
<console>:18: error: value bcrypt is not a member of String
def getEncrypted(secret: String) = new Password(secret.bcrypt)
^
scala>
I am not sure what I am doing wrong here.
Any stable identifier shadows imported implicit
identifiers. Things that can shadow implicits include val
, def
, object
and the generated companion object of case class
. Simple class
es and type
s don't create identifiers and thus don't shadow imported implicit
identifiers.
implicit class Password
is just syntactic sugar for a class Password
and an implicit def Password
, and so an identifier in your code named Password
would shadow that implicit def
.
So while this code compiles OK:
object Foo {
import bcrypt._
class Password()
"123".bcrypt
}
All of the following snippets will fail to compile:
object Foo2 {
import bcrypt._
val Password = 1
"123".bcrypt
}
object Foo3 {
import bcrypt._
def Password() = 1
"123".bcrypt
}
object Foo4 {
import bcrypt._
case class Password()
"123".bcrypt
}
object Foo5 {
import bcrypt._
object Password
"123".bcrypt
}
The solution in your case is simple: rename the implicit class to something else, that would be unlikely to clash with other identifiers. For example, implicit class PasswordExtensions
.
If you can't rename the implicit class
in the original code, you can import it under a different name: import com.github.t3hnar.bcrypt.{Password => PasswordExtensions, _}