I'm working through some compilation errors (in Scala / Play Framework) and one I can't resolve is a conflict error. This is the error:
class Games inherits conflicting members:
[error] method parse in trait BaseControllerHelpers of type => play.api.mvc.PlayBodyParsers and
[error] lazy value parse in trait BodyParsers of type
play.api.mvc.PlayBodyParsers [error] (Note: this can be resolved by
declaring an override in class Games.)
And this is the function (or class) signature for the class:
class Games #Inject() (cc: ControllerComponents, actorSystem: ActorSystem)(val reactiveMongoApi: ReactiveMongoApi)(implicit mat: Materializer) extends AbstractController(cc) with MongoController with ReactiveMongoComponents {
In the error message you'll notice that it says that:
this can be resolved by declaring an override in class Games
But after having tried a few things - I am not sure how. If anyone has any suggestions on this or any other technique that could resolve this error please post. Thanks
Related
I need to bind the implementation of this trait:
trait ClientRepository[F[_]] {
def list(): F[Iterable[ClientDTO]]
}
to this implementation:
import cats.effect.IO
#Singleton
class ClientRepositoryImpl #Inject()(db: OldDataBase, c: IOContextShift)
extends ClientRepository[IO] {
override def list(): IO[Iterable[ClientDTO]] = ???
}
I'm using Scala Play! v2.7.2 and Scala v2.12.8, with scala-guice v4.2.1. In order to bind the trait to its implementation I would like to do something like that in my Module.scala:
class Module(environment: Environment, configuration: Configuration)
extends AbstractModule
with ScalaModule {
override def configure() = {
bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
}
}
And the error I get is:
[error] app/Module.scala:37:9: kinds of the type arguments (ClientRepository) do not conform to the expected kinds of the type parameters (type T).
[error] ClientRepository's type parameters do not match type T's expected parameters:
[error] trait ClientRepository has one type parameter, but type T has none
[error] bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
[error] ^
[error] app/Module.scala:37:31: ClientRepositoryImpl does not take type parameters
[error] bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
[error] ^
[error]
I've also tried:
bind[ClientRepository[IO]].to[ClientRepositoryImpl].in[Singleton]
Module.scala:37:9: kinds of the type arguments (cats.effect.IO) do not conform to the expected kinds of the type parameters (type T).
[error] cats.effect.IO's type parameters do not match type T's expected parameters:
[error] class IO has one type parameter, but type T has none
[error] bind[ClientRepository[IO]].to[ClientRepositoryImpl].in[Singleton]
[error] ^
and bind[ClientRepository[IO[_]]].to[ClientRepositoryImpl].in[Singleton]
Module.scala:37:27: cats.effect.IO[_] takes no type parameters, expected: one
[error] bind[ClientRepository[IO[_]]].to[ClientRepositoryImpl].in[Singleton]
[error] ^
What's the correct way to fix this?
I found the proper solution using Guice's TypeLiteral, after reading this SO answer and this one.
The working solution is:
// In Module.scala configure()
bind(new TypeLiteral[ClientRepository[IO]] {}).to(classOf[ClientRepositoryImpl])
because we must provide a class that can be instantiated (with a type parameter, that in our case is IO). TypeLiteral, which is a special class that enables you to specify a full parameterized type, can be used to create the actual binding to a particular implementation of our Repo[F[_]]. A class with a generic parameter cannot be instantiated but we can force Guice to pick up a specific ClientRepository that has been constructed with the type parameter cats.effect.IO.
Last but not least whenever you have to inject the trait ClientRepository you have to specify the type parameter as well. For instance:
class ClientResourceHandler #Inject()(
routerProvider: Provider[ClientRouter],
clientRepository: ClientRepository[IO]
)
the ClientResourceHandler needs to call the repo, so we're injecting it using the trait ClientRepository[IO] (not just ClientRepository).
In my Module.scala I'm binding a concrete implementation of a trait defined as follows:
trait AccessGroupRepository[F[_]] {}
#Singleton
class AccessGroupRepositoryImpl #Inject()(db: OldDataBase, c: IOContextShift)
extends AccessGroupRepository[IO] {}
and the binding is done using TypeLiteral:
bind(new TypeLiteral[AccessGroupRepository[IO]] {}).to(classOf[AccessGroupRepositoryImpl])
Now, I need to override this binding when testing with a Mockito mock:
override val application: Application = guiceApplicationBuilder
.overrides(bind(new TypeLiteral[AccessGroupRepository[IO]] {}).to(agRepoMock))
but I get the following error:
overloaded method value bind with alternatives:
[error] [T](implicit evidence$1: scala.reflect.ClassTag[T])play.api.inject.BindingKey[T] <and>
[error] [T](clazz: Class[T])play.api.inject.BindingKey[T]
[error] cannot be applied to (com.google.inject.TypeLiteral[api.v1.accessgroup.AccessGroupRepository[cats.effect.IO]])
[error] .overrides(bind(repoTypeLiteral).to(agRepoMock))
[error] ^
How could I solve that?
This question relates to How to bind a class that extends a Trait with a monadic type parameter using Scala Guice?
TypeLiteral isn't available yet in scala implementation of Play Guice API.
Current valid solution for generics, is creating a test module with desired mock definitions, and passing it within overrides:
object CustomMockComponentModule extends AbstractModule {
val agRepoMock = ...
#Provides
#Singleton
def mockBean(): AccessGroupRepository[IO] = agRepoMock
}
...
override val application: Application = guiceApplicationBuilder
.overrides(CustomMockComponentModule)
.build()
I have the following piece of code
import play.api.i18n.{MessagesApi, Messages, I18nSupport}
import play.api.libs.json.Json
case class HttpMessage(key: String, message: String)
object HttpMessage {
implicit val jsonFormat = Json.format[HttpMessage]
def apply(key: String): HttpMessage = {
HttpMessage(key, Messages(key))
}
}
When compiled, it throws
[error] could not find implicit value for parameter messages: play.api.i18n.Messages
[error] HttpMessage(key, messages(key))
[error] ^
I made some research and it seems that it cannot find an implicit value for MessagesAPI. It seems it must be inject like in controllers but I do not know how because I am facing an object and case class here. #Inject annotation is not accepted.
How can I fix this?
Approach from https://stackoverflow.com/a/30843682/4496364 :
import play.api.Play.current
import play.api.i18n.Messages.Implicits._
The first line is deprecated since Play now uses DI everywhere possible.
My approach (can't say if good or bad):
case class HttpMessage(key: String, message: String)
object HttpMessage {
implicit val jsonFormat = Json.format[HttpMessage]
def apply(key: String)(implicit messages: Messages): HttpMessage = {
HttpMessage(key, Messages(key))
}
}
I had to create similar solution, so I used the implicit way, which Play uses also in it's templates. You must have implicit request in your controller for this to work. Also, in all service-like classes you need to forward this implicit messages: Messages...
I am still new enough to Scala that the typing system is destroying me. I haven't yet thought of a solution or discovered a pattern that gets around this particular problem that I am trying to solve. Consider the following program:
ShapeType.scala
package models
abstract class ShapeType {
val themes: ShapeThemes[ShapeTheme] // I think this is where the problem is...?
}
class CircleShapeType extends ShapeType {
val themes = CircleShapeThemes
}
object CircleShapeType extends CircleShapeType
ShapeThemes.scala
package models
abstract class ShapeThemes[T <: ShapeTheme] {
val themes: List[T]
}
class CircleShapeThemes extends ShapeThemes[CircleShapeTheme] {
val themes = List(
new CircleShapeTheme,
new CircleShapeTheme,
new CircleShapeTheme
)
}
object CircleShapeThemes extends CircleShapeThemes
ShapeTheme.scala
package models
class ShapeTheme
class CircleShapeTheme extends ShapeTheme
When I attempt to compile the program (using sbt), I get the following error:
[error] /Users/mjs/Projects/sandbox/shape-types/src/main/scala/ShapeType.scala:8: overriding value themes in class ShapeType of type models.ShapeThemes[models.ShapeTheme];
[error] value themes has incompatible type
[error] val themes = CircleShapeThemes
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 2 s, completed Mar 14, 2015 5:08:43 PM
However, as far as I can tell, CircleShapeThemes is a ShapeThemes[ShapeTheme]. What am I missing?
CircleShapeThemes is not a ShapeThemes[ShapeTheme], it's a ShapeThemes[CircleShapeTheme].
"But", you may object, "a CircleShapeTheme is a ShapeTheme! Indeed, but that subclass relationship isn't propagated by default. You have to ask for it by making the type parameter covariant: abstract class ShapeThemes[+T <: ShapeTheme]
I'm working on a simple test spec using spray and I can't get it to compile correctly, don't know if I'm doing anything wrong. My version of scala is 2.9.3 and spray 1.0.1 (Updating either of them is not a suitable option). Here's my test spec's code:
import org.specs2.mutable.Specification
import spray.testkit.Specs2RouteTest
import spray.http._
import akka.util.Duration
import java.util.concurrent.TimeUnit
import service.MyProxy
abstract class MyTestSpec extends Specification with Specs2RouteTest with MyProxy{
val duration = Duration(30, TimeUnit.SECONDS)
implicit val routeTestTimeout = RouteTestTimeout(duration)
"MyProxy" should {
"return a json for GET requests to the /api/getclass/classCode path for a regular request" in {
Get("/api/getclass/123/") ~> myRoutes~> check {
responseAs[String] must contain("classCode")
contentType === ContentTypes.`application/json`
}
}
} // end should...
} //end class
I'm getting this error when I run the test.
[error] C:\Users\Desktop\Project\MyTestSpec.scala:23: could not find implicit value for parameter ta: MyProxySpec.this.TildeArrow[spray.routing.RequestContext,Unit]
[error] Get("/api/getclass/123/") ~> myRoutes~> check {
[error] ^
[error] one error found
[error] (test:compile) Compilation failed
I've tried different solutions seen on another questions and nothing seems to work so far.
Spray.io: Can't compile test spec
how to make scalatest work with spraytestkit and HttpServiceActor
Basic Spray-Testkit usage to test a route does not work
https://groups.google.com/forum/#!topic/spray-user/H5hkXuDGWYQ
https://groups.google.com/forum/#!topic/spray-user/zFUJSVBPM5c
NOTE: Just for the record, I'm not using scalatest or scalacheck on this. Is purely a [spray] route test.And MyProxy extends Actor
I just struggled with this problem. To figure it out, I waded through the Akka HTTP codebase, which is a jungle of implicits.
My problem seemed to be that without the right secondary implicit in place, the correct TildeArrow instance wasn't being found. If you look at the code, the TildeArrow instance, which is required in the error message, is defined as an implicit def injectIntoRoute in the companion object and it requires a whole host of other implicits.
I suggest writing out your code without any of the implicit sugar. This should better help the compiler give you a proper error message:
"MyProxy" should {
"return a json for GET requests to the /api/getclass/classCode path for a regular request" in {
val request = Get("/api/getclass/123/")
val requestWithRoutes = request.~>(myRoutes)(TildeArrow.injectIntoRoute)
requestWithRoutes.~>(check {
responseAs[String] must contain("classCode")
contentType === ContentTypes.`application/json`
})
}
}
I think the reason is that since there's no concrete instance of the implicit available, the compiler is trying to satisfy the implicit resolution with the abstract class TildeArrow, and the completely unspecified abstract type, ta.Out, doesn't have a ~> defined.
In my specific case, I was missing an implicit ExecutionContextExecutor, whatever that means.
UPDATE
Actually, I looked into it further and the problem was that I had an implicit def ec: ExecutionContextExecutor declared in my route trait, but trait RouteTest defines its name as executor, and so when I defined my own to fulfill the missing implicit, I ended up with two of the same implicit.
It's a cute API, but the implicit magic is way out of control, IMO, especially given how cryptic the error messages tend to be.
The ScalatestRouteTest already provides an implicit ActorySystem. Remove the "implicit" modifier from your actorRefFactory method and the test should get executed.
Spray.io: Can't compile test spec
for akka http:
in my case which refer to akka-http-microservice
the implicit modifier of executionContext and also need to be removed
and should reorder the trait like this : class ServiceSpec extends FlatSpec with Matchers with Service with ScalatestRouteTest
In my case, the not found implicit error appeared when in my TestCase I also imported import monix.execution.Scheduler.Implicits.global (which is probably having some sort of ExecutionContext).
I fixed it adding the monix scheduler import just in the method where I needed it, not on the top imports.
I can reproduce the precise same error message with Scala 2.10 if myRoutes is not actually a route but a Directive[HNil].
I am therefore guessing that in your unshown service.MyProxy class your route does not complete.
ie
trait MyProxy extends HttpService {
val myRoutes = path("foo")
}
Gives this error
trait MyProxy extends HttpService {
val myRoutes = path("foo") {
complete(StatusCodes.Accepted)
}
}
Does not.
To expand a bit on previous answers given, there are some implicits which shouldn't be declared by any other Trait or class that is extends by your Test Class :
the ActorSystem
the ExecutionContext
the DefaultHostInfo (package akka.http.scaladsl.testkit)
the ActorMaterializer
if any of these is declared elsewhere than in ScalatestRouteTest, you'll have the following error thrown :
could not find implicit value for parameter ...TildeArrow[RequestContext, SomethingHereOther]
your build.sbt should have dependencies for akka-stream test along with akka test.
then it should get the whatever dependencies.
refer to this doc:-
scala route test doc