Play framework with Gzip not working - scala

As you know, play! introduced Gzip encoding in 2.2.0 version.
Unfortunately, after updating project and updating play, it doesn't work.
[error] ...\app\Global.scala:4: object filters is not a member of package play
[error] import play.filters.gzip.GzipFilter
[error] ^
[error] ...\app\Global.scala:8: not found: type GzipFilter
[error] object Global extends WithFilters(new GzipFilter) with GlobalSettings {
[error] ^
[error] two errors found
[error] (compile:compile) Compilation failed
It doesn't work even if I create project form console play new TEST.
However in C:\play-2.2.0\framework\src\play-filters-helpers\src\main\scala\play\filters\gzip I have both Gzip.scala and GzipFilter.scala.
My \app\Global.scala looks like that:
import play.api._
import play.api.mvc._
import play.api.mvc.Results._
import play.filters.gzip.GzipFilter
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object Global extends WithFilters(new GzipFilter) with GlobalSettings {
override def onStart(app: Application) {
Logger.info("Application has started")
}
override def onStop(app: Application) {
Logger.info("Application shutdown")
}
override def onError(request: RequestHeader, ex: Throwable) = Future { InternalServerError("{}") }
override def onBadRequest(request: RequestHeader, error: String) = Future { BadRequest("{}") }
override def onHandlerNotFound(request: RequestHeader) = Future { NotFound("{}") }
}
What am I doing wrong? Has anyone made that working?

In Build.scala, just add "filters" to your app dependencies
val appDependencies = Seq(
jdbc, cache, filters, ...
)
or, if you are doing it with build.sbt
libraryDependencies ++= Seq(
jdbc, cache, filters, ...
)

Related

Symbol 'type cats.MonadFilter' is missing fromthe classpath

I am reading this tutorial on tagless final.
Based on this I have defined my dependencies as
object Dependencies {
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.5"
lazy val cats = "org.typelevel" %% "cats-core" % "1.2.0"
lazy val monix = "io.monix" %% "monix" % "2.3.3"
lazy val monixCats = "io.monix" %% "monix-cats" % "2.3.3"
}
The following is my code
// future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.concurrent.duration._
// cats
import cats.Monad
import cats.implicits._
// monix
import monix.eval.Task
import monix.cats._
import monix.cats.reverse._
trait ProductRepository[M[_]] {
def findProduct(productId: ProductId) : M[Option[Product]]
def saveProduct(product: Product) : M[Unit]
def incrementProductSales(productId: ProductId, quantity: Long) : M[Unit]
}
class ProductRepositoryWithFuture extends ProductRepository[Future] {
def findProduct(productId: ProductId) : Future[Option[Product]] = {
Future.successful(Some(Product(productId, "foo")))
}
def saveProduct(product: Product) : Future[Unit] = {
Future.successful()
}
def incrementProductSales(productId: ProductId, quanity: Long) : Future[Unit] = {
Future.successful()
}
}
class ProductRepositoryWithTask extends ProductRepository[Task] {
def findProduct(productId: ProductId) : Task[Option[Product]] = {
Task.now(Some(Product(productId, "foo")))
}
def saveProduct(product: Product) : Task[Unit] = {
Task.unit
}
def incrementProductSales(productId: ProductId, quantity: Long) : Task[Unit] = {
Task.unit
}
}
But I get bunch of errors. It seems that the version of cats which I am using is not compatible with the one Monix uses.
I also tried to remove my cats dependency and just imported monix so that monix pulls in its own version of cats. but even that doesn't compile.
error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:54:24: Symbol 'type cats.MonadFilter' is missing fromthe classpath.
[error] This symbol is required by 'method monix.cats.MonixToCatsCore7.monixToCatsMonadFilter'.
[error] Make sure that type MonadFilter is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'MonixToCatsCore7.class' was compiled against an incompatible version of cats.
[error] repo.findProduct(id).flatMap{
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:54:23: diverging implicit expansion for type monix.types.Comonad[M]
[error] starting with method catsToMonixComonad in trait CatsCoreToMonix5
[error] repo.findProduct(id).flatMap{
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:54:28: value flatMap is not a member of type parameter M[Option[example.Application.Product]]
[error] repo.findProduct(id).flatMap{
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:56:30: value copy is not a member of Any
[error] val newProduct = p.copy(name = name)
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:56:40: reassignment to val
[error] val newProduct = p.copy(name = name)
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:57:27: diverging implicit expansion for type monix.types.MonadError[M,E]
[error] starting with method catsToMonixMonadError in trait CatsCoreToMonix3
[error] repo.saveProduct(newProduct).map(_ => Some(p))
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:57:40: value map is not a member of type parameter M[Unit]
[error] repo.saveProduct(newProduct).map(_ => Some(p))
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:59:16: diverging implicit expansion for type cats.Comonad[M]
[error] starting with method monixToCatsComonad in trait MonixToCatsCore5
[error] Monad[M].pure(None)
[error] ^
[error] 8 errors found
The errors are caused by incompatibilities between your dependencies.
For example monix 2.3.3 depends on cats 0.9.0 while you're trying to use 1.2.0 which is binary incompatible.
You should try either upgrading monix to 3.x or downgrading cats to 0.9.0.
P.S. The transition from cats 0.9.0 to 1.x has a lot of breaking changes and you have to make sure that all libraries you're using are compiled against the same (or at least binary compatible) version of cats.

Play Framework 2.5 Test ApplicationLifecycle Guice Specs2 setup

I am trying to run some functional tests with play2-reactivemongo. I will try to be as concrete as possible, but if something is missing please let me know.
My dependencies are here
libraryDependencies ++= Seq(
cache,
"org.reactivemongo" %% "play2-reactivemongo" % "0.12.0",
"com.mohiva" %% "play-silhouette" % "4.0.0",
"com.mohiva" %% "play-silhouette-testkit" % "4.0.0" % "test",
specs2 % Test
)
In MongoUserDao.scala
import play.modules.reactivemongo._
import play.modules.reactivemongo.json._
import reactivemongo.play.json.collection.JSONCollection
class MongoUserDao #Inject() (val reactiveMongoApi: ReactiveMongoApi) extends UserDao {
val usersFuture = reactiveMongoApi.database.map(_.collection[JSONCollection]("users"))
...
}
In DaoSpecResources.scala
trait DaoSpecResources {
val timeout = DurationInt(10).seconds
val fakeApp = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure(
"play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
"mongodb.uri" -> "mongodb://localhost:27017/test"
)
.build
val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
...
}
When I try to run the test I get this error
[error] cannot create an instance for class daos.UserDaoSpec
[error] caused by com.google.inject.CreationException: Unable to create injector, see the following errors:
[error]
[error] 1) No implementation for play.api.inject.ApplicationLifecycle was bound.
[error] while locating play.api.inject.ApplicationLifecycle
[error] for parameter 1 at services.ApplicationTimer.<init>(ApplicationTimer.scala:24)
[error] at Module.configure(Module.scala:23) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
[error]
[error] 1 error
This is caused by app/services/ApplicationTimer.scala, which depends on ApplicationLifecycle, but you haven't bound any implementation to ApplicationLifecycle. ApplicationTimer is a demo included in every new Play project. You should probably remove it completely if you don't need it, otherwise at least disable it if running in test mode. See disabling modules and overriding modules.
Solution
However, since DefaultReactiveMongoApi also depends on ApplicationLifecycle, you'll need to provide a binding to an implementation of ApplicationLifecycle. The easiest way:
import play.api.inject.{ ApplicationLifecycle, DefaultApplicationLifecycle }
import play.api.inject.bind
trait DaoSpecResources {
val timeout = DurationInt(10).seconds
val fakeApp = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure(
"play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
"mongodb.uri" -> "mongodb://localhost:27017/test"
)
.bindings(bind[ApplicationLifecycle].to[DefaultApplicationLifecycle])
.build
val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
val lifecycle = fakeApp.injector.instanceOf[DefaultApplicationLifecycle]
def stopApp = lifecycle.stop()
}
(added 5 lines: imports, bindings, lifecycle and stopApp)
Then, in your test spec, add step(stopApp) at the end, like so:
class FooSpec extends PlaySpecification with DaoSpecResources {
// Your examples...
step(stopApp)
}
Alternative solution
Personally, I'd create a specialized trait extending Specification or PlaySpecification which would set up and tear down everything automatically, like in this example from specs2 documentation.
trait PlayWithMongoSpecification extends PlaySpecification {
val timeout = DurationInt(10).seconds
val fakeApp = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure(
"play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
"mongodb.uri" -> "mongodb://localhost:27017/test"
)
.bindings(bind[ApplicationLifecycle].to[DefaultApplicationLifecycle])
.build
val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
val lifecycle = fakeApp.injector.instanceOf[DefaultApplicationLifecycle]
def stopApp = lifecycle.stop()
override def map(fs: =>Fragments) = fs ^ step(stopApp)
}
class FooSpec extends PlayWithMongoSpecification {
// Your examples...
}
You may consider making reactiveMongoApi a lazy val.

Specs2: how to test a class with more than one injected dependency?

Play 2.4 app, using dependency injection for service classes.
I found that Specs2 chokes when a service class being tested has more than one injected dependency. It fails with "Can't find a constructor for class ..."
$ test-only services.ReportServiceSpec
[error] Can't find a constructor for class services.ReportService
[error] Error: Total 1, Failed 0, Errors 1, Passed 0
[error] Error during tests:
[error] services.ReportServiceSpec
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 2 s, completed Dec 8, 2015 5:24:34 PM
Production code, stripped to bare minimum to reproduce this problem:
package services
import javax.inject.Inject
class ReportService #Inject()(userService: UserService, supportService: SupportService) {
// ...
}
class UserService {
// ...
}
class SupportService {
// ...
}
Test code:
package services
import javax.inject.Inject
import org.specs2.mutable.Specification
class ReportServiceSpec #Inject()(service: ReportService) extends Specification {
"ReportService" should {
"Work" in {
1 mustEqual 1
}
}
}
If I remove either UserService or SupportService dependency from ReportService, the test works. But obviously the dependencies are in the production code for a reason. Question is, how do I make this test work?
Edit: When trying to run the test inside IntelliJ IDEA, the same thing fails, but with different messages: "Test framework quit unexpectedly", "This looks like a specs2 exception..."; see full output with stacktrace. I opened a Specs2 issue as instructed in the output, though I have no idea if the problem is in Play or Specs2 or somewhere else.
My library dependencies below. (I tried specifying Specs2 version explicitly, but that didn't help. Looks like I need specs2 % Test as is, for Play's test classes like WithApplication to work.)
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
libraryDependencies ++= Seq(
specs2 % Test,
jdbc,
evolutions,
filters,
"com.typesafe.play" %% "anorm" % "2.4.0",
"org.postgresql" % "postgresql" % "9.4-1205-jdbc42"
)
There is limited support for dependency injection in specs2, mostly for execution environments or command-line arguments.
There is nothing preventing you from just using a lazy val and your favourite injection framework:
class MySpec extends Specification with Inject {
lazy val reportService = inject[ReportService]
...
}
With Play and Guice, you could have a test helper such as this:
import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag
trait Inject {
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T : ClassTag]: T = injector.instanceOf[T]
}
If you really need runtime dependency injection, then it's better to use Guice loading, I guess:
package services
import org.specs2.mutable.Specification
import scala.reflect.ClassTag
import com.google.inject.Guice
// Something you'd like to share between your tests
// or maybe not
object Inject {
lazy val injector = Guice.createInjector()
def apply[T <: AnyRef](implicit m: ClassTag[T]): T =
injector.getInstance(m.runtimeClass).asInstanceOf[T]
}
class ReportServiceSpec extends Specification {
lazy val reportService: ReportService = Inject[ReportService]
"ReportService" should {
"Work" in {
reportService.foo mustEqual 2
}
}
}
Alternatively you can implement Inject object as
import scala.reflect.ClassTag
import play.api.inject.guice.GuiceApplicationBuilder
object Inject {
lazy val injector = (new GuiceApplicationBuilder).injector()
def apply[T : ClassTag]: T = injector.instanceOf[T]
}
It depends whether you want to use Guice directly, or thru play wrappers.
Looks like you are out of luck ATM: The comment says
Try to create an instance of a given class by using whatever constructor is available and trying to instantiate the first parameter recursively if there is a parameter for that constructor.
val constructors = klass.getDeclaredConstructors.toList.filter(_.getParameterTypes.size <= 1).sortBy(_.getParameterTypes.size)
i.e. Specs2 doesn't provide own DI out-of-the box,
Or you can reimplement the functionality yourself, if Guice isn't working for you.
App code:
package services
import javax.inject.Inject
class ReportService #Inject()(userService: UserService, supportService: SupportService) {
val foo: Int = userService.foo + supportService.foo
}
class UserService {
val foo: Int = 1
}
class SupportService {
val foo: Int = 41
}
Test code
package services
import org.specs2.mutable.Specification
import scala.reflect.ClassTag
import java.lang.reflect.Constructor
class Trick {
val m: ClassTag[ReportService] = implicitly
val classLoader: ClassLoader = m.runtimeClass.getClassLoader
val trick: ReportService = Trick.createInstance[ReportService](m.runtimeClass, classLoader)
}
object Trick {
def createInstance[T <: AnyRef](klass: Class[_], loader: ClassLoader)(implicit m: ClassTag[T]): T = {
val constructors = klass.getDeclaredConstructors.toList.sortBy(_.getParameterTypes.size)
val constructor = constructors.head
createInstanceForConstructor(klass, constructor, loader)
}
private def createInstanceForConstructor[T <: AnyRef : ClassTag]
(c: Class[_], constructor: Constructor[_], loader: ClassLoader): T = {
constructor.setAccessible(true)
// This can be implemented generically, but I don't remember how to deal with variadic functions
// generically. IIRC even more reflection.
if (constructor.getParameterTypes.isEmpty)
constructor.newInstance().asInstanceOf[T]
else if (constructor.getParameterTypes.size == 1) {
// not implemented
null.asInstanceOf[T]
} else if (constructor.getParameterTypes.size == 2) {
val types = constructor.getParameterTypes.toSeq
val param1 = createInstance(types(0), loader)
val param2 = createInstance(types(1), loader)
constructor.newInstance(param1, param2).asInstanceOf[T]
} else {
// not implemented
null.asInstanceOf[T]
}
}
}
// NB: no need to #Inject here. The specs2 framework does it for us.
// It sees spec with parameter, and loads it for us.
class ReportServiceSpec (trick: Trick) extends Specification {
"ReportService" should {
"Work" in {
trick.trick.foo mustEqual 2
}
}
}
And that expectedly fails with
[info] ReportService should
[error] x Work
[error] '42' is not equal to '2' (FooSpec.scala:46)
If you don't need runtime dependency injection, then it's better to use cake pattern, and forget reflection all-together.
My colleague suggested a "low-tech" workaround. In the test, instantiate service classes with new:
class ReportServiceSpec extends Specification {
val service = new ReportService(new UserService, new SupportService)
// ...
}
This also works:
class ReportServiceSpec #Inject()(userService: UserService) extends Specification {
val service = new ReportService(userService, new SupportService)
// ...
}
Feel free to post more elegant solutions. I've yet to see a simple DI solution that works (with Guice, Play's default).
Does anyone else find it curious that Play's default test framework does not play well with Play's default DI mechanism?
Edit: In the end I went with an "Injector" test helper, almost the same as what Eric suggested:
Injector:
package testhelpers
import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag
/**
* Provides dependency injection for test classes.
*/
object Injector {
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T: ClassTag]: T = injector.instanceOf[T]
}
Test:
class ReportServiceSpec extends Specification {
val service = Injector.inject[ReportService]
// ...
}

`eventually` not found in scala.rx

Here is an example from the scala.rx doc:
package tutorial.webapp
import rx.core.{Rx, Var}
import rx._
import rx.ops._
import scala.concurrent.Promise
import scala.concurrent.duration._
import scala.scalajs.js.JSApp
import scala.scalajs.js.annotation.JSExport
import scala.concurrent.ExecutionContext.Implicits.global
/**
* Created by IDEA on 29/10/15.
*/
object RxAddtionalOps extends JSApp {
#JSExport
override def main(): Unit = {
mapDemo
filterDemo
asyncDemo
async2
timer1
}
def delay1: Unit = {
val a = Var(10)
val b = a.delay(250 millis)
a() = 5
println(b())
eventually{
println(b)
}
}
}
I got this error on sbt when compiling:
[error] /Users/kaiyin/personal_config_bin_files/workspace/scalajsHandson/src/main/scala/tutorial/webapp/RxAddtionalOps.scala:43: not found: value eventually
[error] eventually{
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 1 s, completed 30 oct. 2015 11:15:07
Where does the eventually function come from? Am I missing any imports?
It's defined in utest, which is a author's framework for tests. Since it's a test dependency it doesn't come bundled with scalarx. BTW, the very same functionality presented in scalatest.

scala Play Framework 2.4: sending email

I trying to send an email from scala Play framework 2.4 while using play-mailer, I have followed the instruction from their sample page but with no success.
I have added the dependency to build.sbt:
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-mailer" % "3.0.1"
)
In application.conf the I have added the following:
play.mailer {
host=smtp.gmail.com
port=465
ssl=true
tls=true
user="testme#gmail.com"
password=abracadabra
}
And finally, the Mailing Class:
package controllers
import java.io.File
import javax.inject.Inject
import org.apache.commons.mail.EmailAttachment
import play.api.Configuration
import play.api.Play.current
import play.api.libs.mailer._
class Mail(mailer: MailerClient) {
def send = {
val cid = "1234"
val email = Email(
"Simple email",
"Mister FROM <from#email.com>",
Seq("Miss TO <to#email.com>"),
bodyText = Some("A text message"),
bodyHtml = Some("some data....")
)
mailer.send(email)
}
}
So far without compilation errors, however I don't understand how to initialize this class.. how should I get the "MailerClient" instance?
In the documentation it is written "Then in your router definition, use the trait MailerComponents", with the following code example:
import play.api._
import play.api.ApplicationLoader.Context
import router.Routes
import play.api.libs.mailer._
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new ApplicationComponents(context).application
}
}
class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) with MailerComponents {
lazy val myComponent = new MyComponent(mailerClient)
// create your controllers here ...
lazy val router = new Routes(...) // inject your controllers here
}
(I have added "play.application.loader=SimpleApplicationLoader" in application.conf)
but I get the following compilation errors:
D:\myApp\app\SimpleApplicationLoader.scala:12: not found: type MailerComponents
[error] class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) with MailerComponents {
[error] ^
[error] D:\myApp\app\SimpleApplicationLoader.scala:13: not found: value mailerClient
[error] lazy val applicationController = new controllers.Mail(mailerClient)
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
Any ideas?
You can go with the run-time dependency injection, as the other answer has suggested. But if you want to go with your current approach, read on...
The problem is, the MailerComponents trait doesn't exist in the 3.x branch. it does seem to exist in the master branch, but not in their next branch. I am not sure what they are doing there.
If you want to continue with the example, you'll need to do a bit of fiddling and figure out how to make it compile. For ex. with a bit of looking around, I came up with the following.
import play.api._
import play.api.ApplicationLoader.Context
import router.Routes
import play.api.libs.mailer._
class SimpleApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new ApplicationComponents(context).application
}
}
class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) {
val mailerClient = new CommonsMailer(configuration)
lazy val applicationController = new controllers.ApplicationScala(mailerClient)
lazy val assets = new controllers.Assets(httpErrorHandler)
lazy val router = new Routes(httpErrorHandler, applicationController)
}
Basically, instead of relying on the non-existent MailerComponent to create a mailerClient for me, I just did it myself.
If you have the following line in controllers.ApplicationScala
val id = mailer.configure(Configuration.from(Map("host" -> "typesafe.org", "port" -> 1234))).send(email)
Replace it with:
val id = mailer.send(email)
And it will compile. Meanwhile, I think I should raise an issue on github about this. And maybe you should.
I believe you could simply let play framework inject the mail client. Setting up the configuration and annotating your constructor with #Inject() should work.
Declaration of your Mail controller would look like this:
class Mail #Inject() (mailer: MailerClient) {