No implementation for com.lightbend.lagom.javadsl.server.LagomServiceRouter was bound

It seemed to me it started when I introduced a dependency on a security module (sbt dependsOn). When I removed it everything worked fine. The security module itself doesn’t have any dependencies on any other lagom microservice. I couldn’t get it working with the dependency. I restructured the whole project to reduce dependencies between services (which was necessary anyhow). Didn’t help. So just for a test I duplicated the code from the security module into the web-gateway service and found that the problem now still persists even if I remove that dependency.

play.api.UnexpectedException: Unexpected exception[ProvisionException: Unable to provision, see the following errors:

1) No implementation for com.lightbend.lagom.javadsl.server.LagomServiceRouter was bound.
  while locating com.lightbend.lagom.javadsl.server.LagomServiceRouter
  while locating play.api.inject.RoutesProvider
  while locating play.api.routing.Router
    for the 1st parameter of play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:222)
  while locating play.api.http.JavaCompatibleHttpRequestHandler
  while locating play.api.http.HttpRequestHandler
    for the 6th parameter of play.api.DefaultApplication.<init>(Application.scala:236)
  at play.api.DefaultApplication.class(Application.scala:235)
  while locating play.api.DefaultApplication
  while locating play.api.Application

1 error]
	at play.core.server.LagomReloadableDevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$2.apply(LagomReloadableDevServerStart.scala:196)
	at play.core.server.LagomReloadableDevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1$$anonfun$2.apply(LagomReloadableDevServerStart.scala:149)
	at scala.Option.map(Option.scala:146)
	at play.core.server.LagomReloadableDevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(LagomReloadableDevServerStart.scala:149)
	at play.core.server.LagomReloadableDevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1$$anonfun$apply$1.apply(LagomReloadableDevServerStart.scala:147)
	at scala.util.Success.flatMap(Try.scala:231)
	at play.core.server.LagomReloadableDevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(LagomReloadableDevServerStart.scala:147)
	at play.core.server.LagomReloadableDevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(LagomReloadableDevServerStart.scala:139)
	at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
	at scala.concurrent.impl.Future$PromiseCompletingRunnable.run$$$capture(Future.scala:24)
	at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) No implementation for com.lightbend.lagom.javadsl.server.LagomServiceRouter was bound.

So my question is: How can I debug this further? I’ve no idea why a LagomServiceRouter is missing as my web gateway is a ServiceClientGuiceSupport and shouldn’t need one.

I’m back at the point where removing that (at the moment unused) dependency to my security module fixes the LagomServiceRouter Issue. To give you some further context:

The security module is very simple and containing two classes only which are to be used by every service and thus in a shared module with no dependencies to everything else:

public class Security {

    public static final String FORBIDDEN_MESSAGE = "User must be authenticated to access this service call";

    public static <Request, Response> ServerServiceCall<Request, Response> authenticated(
            Function<String, ServerServiceCall<Request, Response>> serviceCall) {
        return HeaderServiceCall.composeAsync(requestHeader -> {

            CompletionStage<Optional<String>> userLookup = requestHeader.getHeader(HttpHeaders.AUTHORIZATION)
                    .map(authString -> validateUser(Credentials.map(authString)))
                    .orElse(completedFuture(Optional.empty()));

            return userLookup.thenApply(maybeId -> {
                if (maybeComsiId.isPresent())
                    return serviceCall.apply(maybeId.get());
                else
                    throw new Forbidden(FORBIDDEN_MESSAGE);
            });
        });
    }

    private static CompletionStage<Optional<String>> validateUser(Credentials credentials) {
        if ("admin".equals(credentials.getLogin()) && "secretPassword".equals(credentials.getPassword()))
            return completedFuture(Optional.of(credentials.getLogin()));
        else
            return completedFuture(Optional.empty());
    }
}

Don’t worry about the hard coded password, etc. as this stuff is for verifying the architecture.

The security module definition in sbt:

lazy val `security` = (project in file("security"))
  .settings(
    libraryDependencies ++= Seq(
      lagomJavadslServer,
      junit5,
      lombok
    )
  )

And the web gateway:

lazy val `web-gateway` = (project in file("web-gateway"))
  .enablePlugins(PlayJava && LagomPlay)
  .settings(common: _*)
  .settings(
    watchSources ++= (baseDirectory.value / "public/ui" ** "*").get,
    libraryDependencies ++= Seq(
      lagomJavadslClient,
      lombok
    ),
    PlayKeys.playMonitoredFiles ++= (sourceDirectories in(Compile, TwirlKeys.compileTemplates)).value
  )
  .settings(BuildTarget.additionalSettings)
  .dependsOn(`user-api`,`security`)

I commented all the code in the web gateway which is using the Security class. So i can remove the dependency and readd it. Without the dependency it works just fine. With the dependency LagomServiceRouter Exception.

I really have no idea why or how to figure out what’s wrong here. It is pretty similar to the online-auction example as said. But something has to be different. Might as well be some classloading issue?!

Ok, I guess I found the problem.

It’s the dependency of the security module to JavaDslServer:

lazy val `security` = (project in file("security"))
  .settings(
    libraryDependencies ++= Seq(
      lagomJavadslServer,
      junit5,
      lombok
    )
  )

And that library contains a reference-overrides.conf and ServiceGuiceSupport which cause my exception above in the webgateway.

Marking the dependency as Optional solved the issue:

lazy val `security` = (project in file("security"))
  .settings(
    libraryDependencies ++= Seq(
      lagomJavadslServer % Optional,
      junit5,
      lombok
    )
  )

Took me quite a while to figure this out as I don’t know anything about lagom’s internals and had to dig through how the architecture works behind the scenes. Now I know more. Hope this helps people having the same problem.

@thomasbecker I think your security module should be reconsidered or split in two. IIUC, security is a library with tools you’ll use for authentication and/ authorization all over the place. The problem you are facing is that you are importing secutiry (which depends on lagomJavadslServer into web-gateway and webgateway is not a Lagom Service but a Play application.

I think you may have to split security into security-client and security-lagom-service for example. Or maybe security-client, security-play and security-lagom-service, I don’t know.

I also found a bit strange that security uses ServiceGuiceSupport somewhere. It sounded like security used bindService, bindClient… ? Can you share why did security use ServiceGuiceSupport ?

@ignasi35 It is working fine now even with that setup. But moving the “authenticated” ServerServiceCall wrapper to a module imported by the lagom services only would make sense anyhow.

And I didn’t add the ServiceGuiceSupport. It’s in the lagomJavaDsl dependency (reference-overrides.conf).

online-auction-java is doing it in a pretty similar way. Seems like it’s also adding the lagomJavadslServer dependency with the optional flag.

However I think it’s a good idea to split security anyhow. Will do so.