Problem with PasswordInfoDAO implmentation in Silhouette version 6.1

Hi, I am migrating my app from Silhouette 5.0 to 6.1 and found trouble with PasswordInfoDAO implementation.

My class definition as follows:

class PasswordInfoDAO @Inject() (db: Database)( implicit val classTag: ClassTag[PasswordInfo]) extends DelegableAuthInfoDAO[PasswordInfo]

and in SilhouetteModule:

bind[DelegableAuthInfoDAO[PasswordInfo]].to[PasswordInfoDAO]

I am having the following execution error:

No implementation for scala.reflect.ClassTag<com.mohiva.play.silhouette.api.util.PasswordInfo> was bound.

while locating scala.reflect.ClassTag<com.mohiva.play.silhouette.api.util.PasswordInfo>

for the 2nd parameter of models.daos.PasswordInfoDAO.(PasswordInfoDAO.scala:18)

at modules.SilhouetteModule.configure(SilhouetteModule.scala:83) (via modules: com.google.inject.util.Modules$OverrideModule -> modules.SilhouetteModule)

This class was executing well in version 5.0. I should be missing something.

Please help

Thank you

Hi,

We had this topic a while back in the gitter channel:

https://gitter.im/mohiva/play-silhouette?at=5d47f9ab3d8f1f29e0157831

Thank you Akkie for your quick response

I have included a Provider in the class definition as follows:

class PasswordInfoDAO @Inject() (db: Database, classTagProvider: Provider[ClassTag[PasswordInfo]])
extends DelegableAuthInfoDAO[PasswordInfo] {

val classTag = classTagProvider.get()

and still getting the same execution error:

No implementation for scala.reflect.ClassTag<com.mohiva.play.silhouette.api.util.PasswordInfo> was bound.

while locating com.google.inject.Provider<scala.reflect.ClassTag<com.mohiva.play.silhouette.api.util.PasswordInfo>>

for the 2nd parameter of models.daos.PasswordInfoDAO.(PasswordInfoDAO.scala:19)

at modules.SilhouetteModule.configure(SilhouetteModule.scala:83) (via modules: com.google.inject.util.Modules$OverrideModule -> modules.SilhouetteModule)

Would you please provide an example of Silhouette 6.1 PasswordInfo DAO persistance implementation ? Any other path you might suggest ?

Thank you

You should use a Guice @Provides annotated method with a param classTag: ClassTag[PasswordInfo]. It will be filled automatically by the compiler.

I’ll add this to the migration guide if I’m home from vacation

Akkie, please tell me where the Guice @Provides annotated method should be defined. An implementation example of this will be very much appreciated.

Thanks.

@gObando Please see https://www.silhouette.rocks/docs/migration-guide

Akkie, thank you so much for your neat explanation in Silhouette migration guide. It allows me to move forward.

Hi there, sorry I’m not sure how to get this to work still. My previous code was:

@Singleton
class PasswordDAO @Inject()(dbConfigProvider: DatabaseConfigProvider, loginDAO: LoginDAO) extends DelegableAuthInfoDAO[PasswordInfo] {...}

and

bind[DelegableAuthInfoDAO[PasswordInfo]].to[PasswordDAO]

in my SilhouetteModule.

I changed this to:

@Singleton
class PasswordDAO @Inject()(dbConfigProvider: DatabaseConfigProvider, loginDAO: LoginDAO)(implicit val classTag: ClassTag[PasswordInfo]) extends DelegableAuthInfoDAO[PasswordInfo] {

removed the binding and put the following after override def config() { … }

@Provides @Named("password-repository")
  def providePasswordDAO(
    dbConfigProvider: DatabaseConfigProvider,
    loginDAO: LoginDAO): DelegableAuthInfoDAO[PasswordInfo] = {

    new PasswordDAO(dbConfigProvider, loginDAO)
  }

But can’t get it to work:


CreationException: Unable to create injector, see the following errors:

1) No implementation for scala.reflect.ClassTag<com.mohiva.play.silhouette.api.util.PasswordInfo> was bound.
  while locating scala.reflect.ClassTag<com.mohiva.play.silhouette.api.util.PasswordInfo>
    for the 3rd parameter of auth.models.PasswordDAO.<init>(Password.scala:31)
  while locating auth.models.PasswordDAO
    for the 1st parameter of auth.services.PasswordService.<init>(PasswordService.scala:13)
  while locating auth.services.PasswordService
    for the 2nd parameter of controllers.AuthenticationController.<init>(AuthenticationController.scala:27)
  while locating controllers.AuthenticationController
    for the 3rd parameter of router.Routes.<init>(Routes.scala:97)
  at play.api.inject.RoutesProvider$.bindingsFromConfiguration(BuiltinModule.scala:130):
Binding(class router.Routes to self) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$4)

Some help would be much appreciated and thanks for creating such an awesome library! :slight_smile:

Ok I found three solutions to this. Either by adding:

  @Provides
  def providePasswordService(
    passwordDAO: DelegableAuthInfoDAO[PasswordInfo]
  ): PasswordService = {

    new PasswordService(passwordDAO.asInstanceOf[PasswordDAO])
  }

OR by creating two providePasswordDAO:

  @Provides
  def providePasswordDAO(
    dbConfigProvider: DatabaseConfigProvider,
    loginDAO: LoginDAO
  ): DelegableAuthInfoDAO[PasswordInfo] = {

    new PasswordDAO(dbConfigProvider, loginDAO)
  }

  @Provides
  def providePasswordDAO2(
    dbConfigProvider: DatabaseConfigProvider,
    loginDAO: LoginDAO
  ): PasswordDAO = {

    new PasswordDAO(dbConfigProvider, loginDAO)
  }

OR by changing def provideAuthInfoRepository to:

  @Provides
  def provideAuthInfoRepository(
    passwordInfoDAO: PasswordDAO,
    oauth1InfoDAO: DelegableAuthInfoDAO[OAuth1Info],
    oauth2InfoDAO: DelegableAuthInfoDAO[OAuth2Info],
    openIDInfoDAO: DelegableAuthInfoDAO[OpenIDInfo]
  ): AuthInfoRepository = {

    new DelegableAuthInfoRepository(passwordInfoDAO, oauth1InfoDAO, oauth2InfoDAO, openIDInfoDAO)
  }

Is there a more elegant solution to this that I’m missing? Are all these solutions safe to use?

Thanks!

Hi,

Have you read: https://www.silhouette.rocks/docs/migration-guide

Best regards
Christian

For those who have just arrived and also fairly new to Guice (me inlcuded), one more clarification/context on this topic to make your delegate with @Inject()() to get to work are the following.

  1. The line that look like below in your modules.SilhouetteModule.scala should be removed after implmenting the @provides in the same file. This removal point has not been clear in posts and in the migration information. But glad both information was helpful.

    bind[DelegableAuthInfoDAO[PasswordInfo]].toInstance[new YourOwnAuthInfoDAOImpl[PasswordInfo]]

  2. Write the @Provides for the PasswordDAO that looks like below.

    @Provides
    def providePasswordDAO(dbs: XodusDbServiceImpl): DelegableAuthInfoDAO[PasswordInfo] = new XodusAuthInfoDAOImplPasswordInfo

In my situation, I have implemented an XODUS DB (a lightweight embedded no-SQL) as the DB provider.

(Any additional suggestions for possible mistkes I made will be very desirable and educational for me, but at this point doing this have worked.)

1 Like

While migrating my Play from 2.5 to 2.6 I migrated Silhouette from version 4 to 5. (initially I tried version 6 but then I read that Silhouette needs Play 2.7 for version 6). I came across the same issue about ClassTag error during run-time which was resolved as below:

/*NOTE: compiler adds ClassTag implicitly*/
  @Provides
  def providePasswordInfoDAO(dbch: DbConnectionHandler):
  DelegableAuthInfoDAO[PasswordInfo] = {
    new PasswordInfoDAO(dbch)
  }

Class definition is:

class PasswordInfoDAO @Inject()(dbch: DbConnectionHandler) extends DelegableAuthInfoDAO[PasswordInfo] {
...
}

NOTE: If I add (implicit val classTag: ClassTag[PasswordInfo]) in class constructor I get compile time error for specifying override keyword to this param. If I add it then compilation passes but run-time starts failing. Could you elaborate on this behaviour ?
Error as below:

[error] /git/play-scala-app.repo/app/utils/silhouette/PasswordInfoDAO.scala:30:73: overriding value classTag in class DelegableAuthInfoDAO of type scala.reflect.ClassTag[com.mohiva.play.silhouette.api.util.PasswordInfo];
[error]  value classTag needs `override' modifier
[error] class PasswordInfoDAO @Inject()(dbch: DbConnectionHandler)(implicit val classTag: ClassTag[PasswordInfo]) extends DelegableAuthInfoDAO[PasswordInfo] {

Thanks.

The link above leads to a unhelpful v7 migration guide with a broken link to v6 migration. The currently correct v6 migration guide is here Migration Guide

Also, as imanabu says:

The line that look like below in your modules.SilhouetteModule.scala should be removed after implmenting the @provides in the same file. This removal point has not been clear in posts and in the migration information.
bind[DelegableAuthInfoDAO[PasswordInfo]].toInstance[new YourOwnAuthInfoDAOImpl[PasswordInfo]]