Scala - Using guice multibinder on a generic interface fails - scala

I have the following interface:
trait Subject[T] {
def fetch() :Future[Option[T]]
}
And class:
class ChildSubject#Inject()(dao:Dao) extends Subject[String]{
def fetch(): Future[Option[String]] ={
dao.find("10").map{ name => Some(name)
}
}
And a module:
class SubjectModule extends AbstractModule with ScalaModule{
override def configure(): Unit = {
val subMulti = ScalaMultibinder.newSetBinder[Subject](binder)
subMulti.addBinding.to[ChildSubject]
}
}
And I try to inject this Set:
#Singleton
class SomeClass #Inject()(subjects: Set[Subject]){
subjects.map{
//do somthing
}
}
And I get the following error:
play.sbt.PlayExceptions$CompilationException: Compilation error[kinds
of the type arguments (com.test.Subject) do not conform to the expected
kinds of the type parameters (type T).
com.test.Subject's type parameters do not match type T's expected
parameters:
trait Subject has one type parameter, but type T has none]
Any idea??
Thanks!

You need a new TypeLiteral<Subject<String>>() for binding - generically typed interface like Subject<T> in Guice from Java. It's very likely that Scala requires the same in some form.
Something like this may work:
class SubjectModule extends AbstractModule with ScalaModule{
override def configure(): Unit = {
val subMulti = ScalaMultibinder.newSetBinder[Subject[String]](binder)
subMulti.addBinding.to[ChildSubject]
}
}

Related

Scala inherited type doesn't satisfy parent type requirement

Have been using Scala for a while, and hoping to get into domain modeling using type constraints. In the following code, I am trying to design a domain. Excuse the cryptic classnames, wanted to focus on the specific problem I am facing at hand.
Here is the code:
import scala.collection.mutable
class ClassTypeTest
{
trait TSM
{
def fit[T <: TSM](): FR[T]
}
abstract class FM extends TSM{}
trait MP[T <: TSM]
{
def name: String
}
trait FiM[T <: TSM]
{
val fittedParams = mutable.HashMap[String, MP[T]]()
}
class FR[T <: TSM](fm: FiM[T])
// Now define classes related to SMA
//===================================
abstract class SMAP extends MP[SMA]
class SMAO(n: String) extends SMAP
{
override def name = n
}
class SMAM(smao: SMAO) extends FiM[SMA]
{
fittedParams(smao.name) = smao
}
class SMA extends FM
{
override def fit[SMA]() =
{
val fim = new SMAM(new SMAO("x"))
//*******************************
// Following line shows the error:
// Error:(40, 25) type mismatch;
// found : ClassTypeTest.this.SMAM
// required: ClassTypeTest.this.FiM[SMA]
// new FR[SMA](fim)
//*******************************************
new FR[SMA](fim)
}
}
}
I am defining SMAM as extends FiM[SMA], so why is the compiler complaining about Type mismatch. Required FiM[SMA], found: SMAM. Have I ill-defined one of the type parameters or constraints?
I am trying to constrain the type of fit method, and the FR object to one of the subclasses of TSM. How do I achieve this?
I am defining SMAM as extends FiM[SMA], so why is the compiler complaining about Type mismatch. Required FiM[SMA], found: SMAM.
SMA in def fit[SMA]() = ... in
class SMA extends FM
{
override def fit[SMA]() =
{
val fim = new SMAM(new SMAO("x"))
new FR[SMA](fim)
}
}
is a type parameter. It's arbitrary type, not the class SMA (the type parameter SMA hid class SMA). You could use arbitrary identifier here, e.g. T
class SMA extends FM
{
override def fit[T]() =
{
val fim = new SMAM(new SMAO("x"))
new FR[T](fim)
}
}
So I guess the error
type mismatch;
found : SMAM
required: FiM[T]
is clear now.
trait TSM
{
def fit[T <: TSM](): FR[T]
}
This defines a trait with a method fit that for any type T returns an instance of FR[T]
class SMA extends TSM
{
override def fit[SMA]() =
{
val fim = new SMAM(new SMAO("x"))
new FR[SMA](fim)
}
}
This overrides method fit defined in the trait. SMA in method definition is a type parameter, not a reference to the class name. You can (probably, should) replace it with T, it'll be equivalent, but a bit less confusing:
override def fit[T <: TSM](): FR[T] = new FR(new SMAM(new SMAO("x")))
This will give you a more descriptive error - something to the effect that you are trying to return FR[SMA] where FR[T] is expected.
The bottom line is you cannot make a method in subclass less "generic" than it is declared in a superclass. To better understand why that is the case, consider this:
abstract class Foo extends TSM
val sma: TSM = new SMA()
val foo: FR[Foo] = sma.fit[Foo]()
This should work: sma is an instance of TSM, and TSM.fit is supposed to work for any type parameter which is a subclass of TSM, which Foo clearly is.
But your SMA.fit as written can only return FR[SMA], so the snippet above would not work if it was allowed.
How to fix this?
Well, that depends on what you actually want. One possibility is to parametrize the trait itself rather than the method:
trait TSM[T <: TSM[_]] {
def fit(): FR[T]
}
class SMA extends TSM[SMA]
{
override def fit() = new FR(new SMAM(new SMAO("x")))
}

How can I explicitly tell the compiler what the return type is?

Suppose I have an abstract class and an object of the same name in the same file.
How can I explicitly tell the compiler that the return type of run is the abstract class CommandResult type not the object CommandResult type?
Base.scala
trait Base {
def run[T]: Future[T]
}
X.scala
class X extends Base {
override def run[CommandResult]: Future[CommandResult] = {
// here return CommandResult, Success or Failure
}
}
sealed abstract class CommandResult(val exitCode: Int)
object CommandResult {
case object Success extends CommandResult(0)
case object Failure extends CommandResult(1)
}
When you write def run[CommandResult], it means "run takes a type one parameter named CommandResult", that's why you are getting error like:
On line 3: error: type mismatch;
found : CommandResult.Success.type
required: CommandResult <--- The type parameter,
not the class or object.
The error indeed is very misleading. For example try override def run[X]: Future[X] and will see "required: X`.
If you do as Luis suggests:
trait Base[T] {
def run: Future[T]
}
class X extends Base[CommandResult] {
override def run: Future[CommandResult] = {
Future(CommandResult.Success)
}
}
It will work.

Scala generics function call

I have the following trait in scala:
trait BaseDao {
type T <: BaseModel
def saveModel(model: T)
}
I created a class which extends BaseDao:
class Sample (dynamoDBMapper: DynamoDBMapper) extends BaseDao with LazyLogging {
checkNotNull(dynamoDBMapper)
protected def classType: Class[T] = implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]]
override def saveModel(model: T): Unit ={
model.validate()
dynamoDBMapper.save(model)
}
Now, when I create the instance of above class and try to call save method:
val testModel = new TestModel();
testModel.setHashKey("a")
testModel.setSortKey("b")
testModel.setCreatedOn(new Date())
testModel.setModifiedOn(new Date())
sample.saveModel(testModel)
It gives the following error:
Type mismatch expected: Sample#T, actual: TestModel model class extends BaseModel class
I am new in scala and I am not able to figure out what is wrong here?
You haven't defined type T in Sample.
Rewrite your Sample class to look somewhat like this:
class Sample (dynamoDBMapper: DynamoDBMapper) extends BaseDao with LazyLogging {
checkNotNull(dynamoDBMapper)
type T = TestModel
override def saveModel(model: T): Unit ={
model.validate()
dynamoDBMapper.save(model)
}
}

How can I implement concrete class which extends trait defining a method with type by the type parameter's type alias

I would like ask for some help for advanced scala developers. My problem is that I would like to access a type alias belonging to a type parameters of a class' parent.
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait Module[M, D] {
type Dispatcher = D
type Model = M
}
trait MySpecificModule[A <: Module[_, _]] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module[MyModel, MyDispatcher] {
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
So basically MySpecificModule extends a generic trait, and should know the type of the dispatcher method. In this case of MySpecificModuleClass it should be MyDispatcher. But when I try to compile this code I am getting compilation error because the type of the method, is not the same as defined: A#Dispatcher, however in the reality it is.
Error:(21, 18) overriding method dispatcher in trait MySpecificModule of type ()_$2;
method dispatcher has incompatible type
override def dispatcher(): MyDispatcher = MyDispatcher()
^
I would appreciate any advice you suggest. Thanks in advance,
Gabor
Resolved
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait AbstractModule {
type Dispatcher
type Model
}
trait Module[M, D] extends AbstractModule {
type Dispatcher = D
type Model = M
}
trait MySpecificModule[A <: AbstractModule] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module[MyModel, MyDispatcher] {
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
I don't fully understand Scala's reasoning here, but if you get rid of type parameters, things start to work:
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait Module {
type Dispatcher
type Model
}
trait MySpecificModule[A <: Module] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module {
type Model = MyModel
type Dispatcher = MyDispatcher
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
And if you really want to have those type params, you can introduce a helper trait:
trait AbstractModule[M, D] extends Module {
type Model = M
type Dispatcher = D
}
class ModuleClass extends AbstractModule[MyModel,MyDispatcher]

Define an abstract class or trait that depends on an implicit

I have this play framework 2 code (simplified):
import formatters.json.IdeaTypeFormatter._
object IdeaTypes extends Controller {
def list = Action { request =>
Ok(toJson(IdeaType.find(request.queryString)))
}
def show(id: Long) = Action {
IdeaType.findById(id).map { ideatype =>
Ok(toJson(ideatype))
}.getOrElse(JsonNotFound("Type of idea with id %s not found".format(id)))
}
}
IdeaType class extends Entity, and it's companion object, IdeaType, extends EntityCompanion.
As you may expect, I have this kind of code in every controller, so I'd like to extract the basic behavior to a trait, something like this:
abstract class EntityController[A<:Entity] extends Controller {
val companion: EntityCompanion
val name = "entity"
def list = Action { request =>
Ok(toJson(companion.find(request.queryString)))
}
def show(id: Long) = Action {
companion.findById(id).map { entity =>
Ok(toJson(entity))
}.getOrElse(JsonNotFound("%s with id %s not found".format(name, id)))
}
}
But I get the following error:
[error] EntityController.scala:25: No Json deserializer found for type List[A].
[error] Try to implement an implicit Writes or Format for this type.
[error] Ok(toJson(companion.find(request.queryString)))
[error] ^
[error] EntityController.scala:34: No Json deserializer found for type A.
[error] Try to implement an implicit Writes or Format for this type.
[error] Ok(toJson(entity))
[error] ^
I don't know how to tell that the implicit Writes will be implemented by the classes implementing the EntityController trait (or inheriting the abstract class EntityController)
-- edit
so far now I'm doing it like this:
abstract class CrudController[A <: Entity](
val model: EntityCompanion[A],
val name: String,
implicit val formatter: Format[A]
) extends Controller {
and use it like this
object CrudIdeaTypes extends CrudController[IdeaType](
model = IdeaType,
name = "type of idea",
formatter = JsonIdeaTypeFormatter
)
I could't get scala to automatically pick it using implicits. I tried with this import but it didn't work
import formatters.json.IdeaTypeFormatter._
If you want the controler classes themselves to define the implicit, then just declare abstract implicit values, and define them in the derived classes.
abstract class EntityController[A<:Entity] extends Controller {
protected implicit def entityWriter: Writes[A]
protected implicit def entityListWriter: Writes[List[A]]
...
}
class MyEntity extends Entity {
...
}
class MyEntityController extends EntityController[MyEntity] {
protected def entityWriter: Writes[MyEntity] = ...
protected def entityListWriter: Writes[List[MyEntity]] = ...
}
However, it is much more practical to define these implicits outside the controller, typically in the companion object of your entity, so that they the compiler can find them automatically without import.
Then, pass the implicit values to the constructor of EntityController:
abstract class EntityController[A<:Entity](implicit entityWriter: Writes[A], entityListWriter: Writes[List[A]] ) extends Controller {
...
}
class MyEntity extends Entity {
...
}
object MyEntity {
protected implicit def entityWriter: Writes[A]
protected implicit def entityListWriter: Writes[List[A]]
}
class MyEntityController extends EntityController[MyEntity] {
...
}
Final note, the implicit to List[MyEntity] is probably unneeded( thus only the implicit for MyEntity would need to be explicitly defined). I have not checked, but usually when using this "typeclass pattern",
the framework will already define an implicit for each List[T], provided that there is an implicit for T. This is probably the case, though I have not checked.