can't get abstract class out of package object in scala - scala

I have a package object with an abstract class in it like this:
package mainPackage
package object subPackage {
abstract class MyBase(val i: Int)
case class DerivedClass(override val i: Int) extends MyBase(i)
}
In another file, I import the package:
import mainPackage.subPackage._
This gives me access to DerivedClass, but for some reason, I can't see the abstract base class. Any idea why? I want to create a List[BaseClass], but it's not letting me.

The following worked for me:
package mainPackage
class Baba {
import mainPackage.subPackage._
new MyBase(1) {
}
val l: List[MyBase] = ???
}

Related

How to bind a class that extends a trait with a monadic type in Scala Guice

I've created simple Scala Play application that has traits with a monadic type and their respective implementation binded in Module configure as:
class Module extends AbstractModule {
override def configure() = {
bind(new TypeLiteral[UserDAO[DBIO]](){}).to(classOf[UserDAOImpl])
bind(new TypeLiteral[UserService[Future]](){}).to(classOf[UserServiceImpl[Future, DBIO]])
}
}
Those traits and implementations are:
///TRAITS
//UserDAO.scala
package models
trait UserDAO[DB[_]] {
def get(userId: Long): DB[Option[User]]
}
//UserService.scala
package services
import resources.UserResponse
import services.response.ServiceResponse
trait UserService[F[_]] {
def findUserById(id: Long): F[ServiceResponse[UserResponse]]
}
///IMPLEMENTATIONS
//UserDAOImpl.scala
package dao
import models.{DataContext, User, UserDAO}
import play.api.db.slick.DatabaseConfigProvider
import slick.dbio.{DBIO => SLICKDBIO}
import javax.inject.Inject
import scala.concurrent.ExecutionContext
class UserDAOImpl #Inject()(
protected val dbConfigProvider: DatabaseConfigProvider,
val context: DataContext
)(
implicit executionContext: ExecutionContext
) extends UserDAO[SLICKDBIO] {
import context.profile.api._
override def get(userId: Long): SLICKDBIO[Option[User]] = context.Users.filter(_.id === userId).result.headOption
}
//UserServiceImpl.scala
package services
import resources.Mappings.UserToResponseMapping
import cats.Monad
import cats.implicits._
import models.{DatabaseManager, UserDAO}
import resources.{NoModel, UserResponse}
import services.response.ServiceResponse
import util.Conversions.{errorToServiceResponse, objectToServiceResponse}
import javax.inject.Inject
class UserServiceImpl[F[_]: Monad, DB[_]: Monad]#Inject()(userRepo: UserDAO[DB],
dbManager: DatabaseManager[F, DB])
extends UserService[F] {
override def findUserById(id: Long): F[ServiceResponse[UserResponse]] = {
for {
user <- dbManager.execute(userRepo.get(id))
} yield user match {
case Some(user) =>user.asResponse.as200
case None => NoModel(id).as404
}
}
}
However, this fails to inject dependencies and throws the following errors:
play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:
1) models.UserDAO<DB> cannot be used as a key; It is not fully specified.
at services.UserServiceImpl.<init>(UserServiceImpl.scala:13)
at Module.configure(Module.scala:35) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
2) models.DatabaseManager<F, DB> cannot be used as a key; It is not fully specified.
at services.UserServiceImpl.<init>(UserServiceImpl.scala:13)
at Module.configure(Module.scala:35) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
3) cats.Monad<F> cannot be used as a key; It is not fully specified.
at services.UserServiceImpl.<init>(UserServiceImpl.scala:13)
at Module.configure(Module.scala:35) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
This question might be related to this one How to bind a class that extends a Trait with a monadic type parameter using Scala Guice?, and in my solution I've applied what is suggested as the answer, but it still fails.
Any suggestions?
If you look at the stacktrace, you can see the issue happens when Guice wants to create an instance of UserServiceImpl:
... at services.UserServiceImpl.<init> ...
I suspect that Guice cannot know what to "inject" when trying to create this class. It cannot infer that it has to inject a UserDao[DBIO] for instance, it only knows it has to inject a UserDao[DB] with DB being something unspecified.
How to fix that, I can't say for sure but I would look into either:
adding "concrete" class for UserServiceImpl and bind it instead of the generic one (like a class UserServiceFutureDBIO)
manually instantiating a UserServiceImpl and binding to an instance rather than binding to a class and letting Guice instantiate it

package object definitions are not in scope

Inside of my package com.example.common I have a package.scala file:
package com.example.common
import scala.concurrent.Future
package object common extends MyPackage {
}
trait MyPackage extends MyFutures {
}
trait MyFutures {
type Funit = Future[Unit]
}
Now inside of this file I thought I can have the above in scope:
com.example.common.email
class EmailService() {
def send(name: String): Funit = {
}
}
But my alias type Funit isn't in scope and I get the error:
no found: type Funit
Your EmailService is not in the package containing your package object.
Your package object is inside com.package.common.common
Also you should name name your package object according to the package:
A package object package object p extends t adds the members of template to the package p. There can be only one package object per package. The standard naming convention is to place the definition above in a file named package.scala that's located in the directory corresponding to package p.
So you should have the following
a file named com/example/common/package.scala
containing package object common
declared inside package com.example
import scala.concurrent.Future
package object common extends MyPackage {
}
trait MyPackage extends MyFutures {
}
trait MyFutures {
type Funit = Future[Unit]
}
// in the same file (you mentioned "Now inside of this file I thought I can have the above in scope:")
package common {
package email {
class EmailService() {
def send(name: String): Funit = ???
}
}
}
This way, since you're already in the common package:
package com.example.common
import scala.concurrent.Future
object `package` extends MyPackage {
}
trait MyPackage extends MyFutures {
}
trait MyFutures {
type Funit = Future[Unit]
}
and to make common._ visible:
package com.example.common
package email
class EmailService() {
def send(name: String): Funit = ???
}

Error importing trait in to worksheet

I have the following object and trait definitions in separate files in my package
object Bloxorz extends App // in Bloxorz.scala
trait Solver extends GameDef // in Solver.scala
trait GameDef // in GameDef.scala
There is a method in trait GameDef I wish to test out. So I create a worksheet in the root of my package and try to import it.
import streams.GameDef._
But I receive the following error
object GameDef is not a member of package streams. Note: trait GameDef exists, but it has no companion object
Since Solver extends GameDef, I figured I needed to import Solver instead, but that yielded the same error. Only importing Bloxorz object did not throw an error, but that did not expose the method I needed from GameDef.
Try this:
import streams.GameDef
Your code above is importing all classes of a package named GameDef. I'm guessing GameDef is a class,object or trait because it is capitalized. In fact, the error you are getting describes your problem pretty well:
object GameDef is not a member of package streams. Note: trait GameDef exists, but it has no companion object
I created code snippet based on what you say and my assumption. I thought you only want to test Pos, not GameDef.
GameDef.scala:
package test
trait GameDef {
case class Pos(x: Int, y: Int) {
// Pos will play with x and y here.
}
}
YourWorksheet.sc:
package test
object TestPosInsideGameDef extends GameDef {
def newPos(x: Int, y: Int): Pos = new Pos(x, y)
val pos = newPos(1, 2)
}

Guice, unable to bind ClassTag[T] (to know the name of T class)

I would like to know the name of a generic class.
The solution I use now is the following one. I defined the class class A[T: ClassTag] {...} to be able to do classTag[T].toString.
This compiles, but there is a problem with Guice. I get the error No implementation for scala.reflect.ClassTag<com.test.Person> was bound.
Is there :
Another solution to know the name of a generic class that could work with Guice ? or
A way to bind ClassTag[T] with Guice ?
Full code :
package com.test
case class Person(age: Int)
class A[T: ClassTag] {
// I need to know the (full) name of type T (e.g. com.test.Person)
val tClassName = classTag[T].toString
}
class B #Inject()(a: A[Person]) {
}
Thanks to #tavian-barnes help, I found the way to solve this problem.
The solution is to add to A an implicit value TypeLiteral[T]. Then, you just have to call typeLiteral.getType.getTypeName to get the full name of geneirc class T.
Full code :
package com.test
case class Person(age: Int)
class A[T]()(implicit val typeLiteral: TypeLiteral[T]) {
val tClassName = typeLiteral.getType.getTypeName
}
class B #Inject()(a: A[Person]) {
println(a.tClassName) // prints `com.test.Person`
}

Serialize class as its one member with Jackson

Sometimes the class has only one member to serialize (other members are transient), and I would like to serialize and deserialize this class as its only member.
Consider following code:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
case class Content(i:Seq[Int])
case class Wrap(content:Content)
object Main extends App {
val om = new ObjectMapper() with ScalaObjectMapper {
registerModule(new DefaultScalaModule)
}
val roots = Wrap(Content(Seq(1,2,3)))
val out = om.writeValueAsString(roots)
println(out)
val test = om.readValue(out, classOf[Wrap])
println(test)
}
The result of serialization of Wrapis {"content":{"i":[1,2,3]}}.
I would like to get {"i":[1,2,3]} only. I guess I could do this with custom serializer/deserializer, but given in real case the content is a complex class, this would mean I would have to serialize the content manually, if I am not mistaken. I would prefer some more straightforward solution.
Is it possible to "delegate" the serialization/deserialization to a member/constructor parameter?
It can be done using converters, which can be used to modify Jackson behaviour using JsonSerialize and JsonDeserialize properties.
import com.fasterxml.jackson.databind.annotation.{JsonSerialize, JsonDeserialize}
import com.fasterxml.jackson.databind.util.StdConverter
#JsonDeserialize(converter=classOf[WrapConverterDeserialize])
#JsonSerialize(converter=classOf[WrapConverterSerialize])
case class Wrap(content:Content)
class WrapConverterDeserialize extends StdConverter[Content,Wrap] {
override def convert(value: Content) = new Wrap(value)
}
class WrapConverterSerialize extends StdConverter[Wrap,Content] {
override def convert(value: Wrap) = value.content
}