Неявное преобразование с неявным параметром - PullRequest
1 голос
/ 17 февраля 2012

Я реализую Java-интерфейс с множеством методов с параметрами Object, которые в моем случае действительно являются строками, содержащими имена пользователей:

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)
}

Но с неявным параметром преобразование больше не воспринимается компилятором (жалуясь, что я не реализую интерфейс).

Есть ли способ получить неявное преобразование, которое я хочу, или это выходит за рамки того, что вы можете сделать с имплицитами?

Ответы [ 2 ]

4 голосов
/ 17 февраля 2012

Это должно работать просто отлично - вы можете указать точную ошибку компиляции?Не реализует какой интерфейс?Похоже, вы должны были бы объявить следующее:

class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository) 

Вот пример для REPL, чтобы показать, что последствия могут иметь последствия;Я использую режим вставки, чтобы убедиться, что 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 голос
/ 17 февраля 2012

Благодаря ответу Оксбоу , теперь он у меня работает, это только для справки.

Прежде всего, значение, которое должно быть передано как неявное, само должно быть помечено как неявное:

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
    }

    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...