How to activate circular dependencies in Play 2.5? - scala

This question originates from a question that I asked two days ago. I implemented my own error handler which extends DefaultHttpErrorHandler. DefaultHttpErrorHandler extends HttpErrorHandler which is also used as a parameter errorHandler: HttpErrorHandler in the WebJarAssets class. First I thought I had a flaw in my design, but James Ward commented that it seems like that I am doing things right.
Long story short, I need to know how I can activate circular dependencies. Unfortunately, there is no example code listed in the Play documentation, so I have no idea where I should set disableCircularProxies(false).

You need a custom GuiceApplicationLoader like:
import play.api.ApplicationLoader
import play.api.inject.guice.{GuiceApplicationLoader, GuiceApplicationBuilder}
class CustomApplicationLoader extends GuiceApplicationLoader {
override protected def builder(context: ApplicationLoader.Context): GuiceApplicationBuilder = {
super.builder(context).disableCircularProxies(false)
}
}
And tell Play to use it in application.conf:
play.application.loader = "CustomApplicationLoader"
Full code example:
https://github.com/webjars/webjars-play/tree/cicular-deps

Related

Migrating Play Framework 2.5 - moving from Global.onStart to Dependency Injection

So I am trying to migrate a PlayFramework application from version 2.4.3 to 2.5.6. I am using Squeryl and akka-quartz-scheduler, and Squeryl requires setting up a session manually and akka-quartz-scheduler runs as its own entity, as none of the other modules really depend on it, though it will depend on others. So previously there has been a Global-object to handle them on start up:
import org.squeryl.{Session, SessionFactory}
object Global extends GlobalSettings {
private lazy val injector = Guice.createInjector(CustomModule)
override def onStart(app: Application) {
SessionFactory.concreteFactory = // Squeryl initialization http://squeryl.org/sessions-and-tx.html
injector.getInstance(classOf[CustomScheduler]).initialize()
}
}
This has worked before. However, on 2.5.6 I'm trying to shift away from Global.scala altogether. I'm not sure if this is the best way to do this, but from documentation it seems like it. So I'm trying to create Singleton classes, and load them eagerly before the application loads like instructed here as a replacement for onStart. So like instructed on eager bindings -page I have:
import com.google.inject._
class CustomModule extends AbstractModule {
override def configure() = { // or without override
println("configure called")
bind(classOf[SquerylInitialization]).to(classOf[SquerylInitialization]).asEagerSingleton()
bind(classOf[CustomScheduler]).to(classOf[CustomScheduler]).asEagerSingleton()
}
}
import play.api.{Configuration, Application}
import play.api.db.{DB, DBApi}
import org.squeryl.{SessionFactory, Session}
#Singleton
class SquerylInitialization #Inject()(conf: Configuration, dbApi: DBApi) extends Logging {
SessionFactory.concreteFactory = // Squeryl initialization http://squeryl.org/sessions-and-tx.html
}
import akka.actor.{ActorSystem, ActorRef}
#Singleton
class CustomScheduler #Inject()(system: ActorSystem) extends Logging {
val scheduler: QuartzSchedulerExtension = QuartzSchedulerExtension(system)
// other initialize code here
}
The CustomModule inheriting the AbstractModule and its configure()-method is never called. It is said in Guice documentation that "Alternatively, play will scan the classpath for classes that implement AbstractModule". Documentation might not be the most recent, but that seems to be the way it works.
If for instance on all classes using Squeryl I use dependency injection to load SquerylInitialization it works, but I'm not sure if that's good way to do it as it would have to be required by tons of Classes, and there is hardly any Class depending on the CustomScheduler.
So basically the questions are:
Why isn't the CustomModule calling the configure()-method and eager
loading the Classes, and how that should be fixed?
Is this the standard way to load this kind of functionality, or should some other way used?
So basically comments are correct and the documentation was just out of date, so including
play.modules.enabled += "module.CustomModule"
helped. Thought I tried that as well, but turns out I didn't. Answer just a comment so can't accept that.

How to get application.conf variable in an object using Scala and Play 2.5.x?

I used to get the application.conf variable in Play 2.4.x with Play.current.configuration.getString('NAME_HERE'), and it was working good in class, object and companion object too.
Now, I'm using Play 2.5.4 with Scala in a new project, and I won't use this Play.current, because it's deprecated, but there is an alternative using DI, like this :
class HomeController #Inject() (configuration: play.api.Configuration) extends Controller {
def config = Action {
Ok(configuration.underlying.getString("db.driver"))
}
}
This DI Injection works like a charm in class, but in this project, I need to get the variable db.driver in a object? And as far I know, with an object I can't use DI.
Maybe using Guice would help?
You can use #Singleton annotated class instead of object
trait Foo {}
#Singleton
class FooImpl #Inject()(configuration: play.api.Configuration)) extends Foo {
//do whatever you want
}
#Singleton makes the class singleton.It feels bit awkward because Scala itself natively have syntax object to create a singleton, But this is the easiest and probably best solution to DI into a singleton.
You also may create the singleton eagerly like the code below.
bind(classOf[Foo]).to(classOf[FooImpl])asEagerSingleton()
for more detail Info, You can look up Google Guice Wiki and Playframework site
EDIT
How you call it is exactly the same as how you DI in Playframework2.5.
class BarController #Inject()(foo: Foo) extends Controller {
//Do whatever you want with Foo
}
Guice basically generates new instance every time you DI, Once you put #Singleton, Guice use only one instance instead.
DI is for anti-high coupling.So when you want to use a class you defined from another class,You need to DI otherwise the classes are highly coupled which end up making it harder to code your unit test.
FYI, You can use them outside of Play with this technique.
Create an Instance of class which does DI via Playframework Guice Independently in Scala
Have you tried
import com.typesafe.config.ConfigFactory
val myConfig = ConfigFactory.load().getString("myConfig.key")
Above approach doesn't require you to convert your object to singleton class.
You can do
Play.current.configuration
however that will (probably) no longer be possible with Play 2.6.
Ideally, however, you would pass the configuration in as a parameter to that method of the object or, use a class instead of an object.
What I somtimes do to migrate 'from object to class':
class MyComponent #Inject() (config: Configuration) {
// here goes everything nice
def doStuff = ???
}
object MyComponent {
#deprecated("Inject MyComponent")
def doStuff = {
val instance = Play.current.injector.instanceOf[MyComponent]
instance.doStuff
}
}
This way, you're not breaking existing code while all users of your methods can slowly migrate to using classes.

Play Framework: Inject multiple dependencies using constructor injection in the controller

What is the right way to inject multiple dependencies using constructor injection for a controller in Play Framework (2.4.x, which provides guice based DI out of the box) in Scala?
For example,
class ExampleController #Inject() (serviceOne: ServiceOne, serviceTwo: ServiceTwo) extends Controller {
}
The above won't compile saying only one or no constructor arg can be injected.
Was not able to find any good references regarding as how to get this working. Any help is appreciated. Thanks.
You may need to prepend val to the parameters:
class ExampleController #Inject() (val serviceOne: ServiceOne, val serviceTwo: ServiceTwo) extends Controller {
And also check that you have the correct import:
import javax.inject.Inject
Here you also can find an example with multiple dependencies, maybe it helps.
Your code is correct. Additionally to that, you need to configure a module in your application.conf
play.modules.enabled += "com.example.HelloModule"
And then in this very Module you need to describe your dependency injected classes:
import play.api.inject._
class HelloModule extends Module {
def bindings(environment: Environment,
configuration: Configuration) = Seq(
bind[Hello].qualifiedWith("en").to[EnglishHello],
bind[Hello].qualifiedWith("de").to[GermanHello]
)
}
For the offical documentation see this link.

Where does one place a scala file in the Play Framework 2.0 so that it is compiled as part of the default package?

I am new to Play and Scala, and I am reading Play for Scala from Manning press. I would like to use the instructions to use Squeryl instead of Anorm.
The book mentions that I need to initialize Squeryl in a class that extends GlobalSettings.
import org.squeryl.adapters.H2Adapter
import org.squeryl.{Session, SessionFactory}
import play.api.db.DB import play.api.{Application, GlobalSettings}
object Global extends GlobalSettings {
SessionFactory.concreteFactory = Some(() =>
Session.create(DB.getConnection()(app), new H2Adapter) )
...
As this is an early edition (MEAP) it is not clear about where to place this code...
So I after a little digging on the play site I found the following example that extends GlobalSettings
import play.api._
object Global extends GlobalSettings {
override def onStart(app: Application) {
Logger.info("Application has started")
}
override def onStop(app: Application) {
Logger.info("Application shutdown...")
}
}
The play example gives a little more help but I am still unable to follow the directions, which state : This object must be defined in the default (empty) package.
Which leads to my question: Where does one place a scala file in the Play Framework 2.0 so that it is complied as part of the default package?
Thanks for any help...
GlobalSettings object typically resides in app/Global.scala. Look at zentasks sample.
This does not answer your specific asked question
But, if your question is about "how to use squeryl with Play2 ?", there are some resources you can have a look at :
How to make Squeryl work with the Play! Framework?
https://groups.google.com/d/topic/squeryl/d7hBDNUjE2Y/discussion
And an example : https://github.com/jamesward/play2bars/tree/scala-squeryl

Conditional class import/ load

In a Groovy script is it possible to do a conditional import statement?
if (test){
import this.package.class
} else {
import that.package.class
}
The background to this is wanting to use something on MacOS 10.5 which only has JDK1.5 so one specific class is unavailable, but I have found someone who has written a back-port for it.
There is no way to conditionally import a class, but you can achieve something similar by attempting to load the class and then load another class if that one is not found.
Here's just an example:
def someClass
try {
someClass = "org.apache.webdavlib.WebdavFile" as Class
} catch (Exception ex) {
someClass = "java.io.File" as Class
}
def someInstance = someClass.newInstance("~/project/temp.log")
assert "java.io.File" == someInstance.getClass().getName()
Jochen "blackdrag" Theodorou proposed the following on the groovy user list a while ago:
wsh = this.class.classLoader.loadClass("org.codehaus.groovy.scriptom.ActiveXObject").newInstance("WScript.Shell")
Then you do not need to use the import statement.
Here is the thread on the mailing list
No, conditional imports are not supported... Best I can think of atm would be to use reflection as you would need to in java...
An ast transform could also be used here to tag the class and wrap the code that uses the missing class with the required reflection code
I guess a class loader could do the trick, but will be complicated.
Have you considered to use a shadow class and jsut deploy different jars?
Something like
//jdk 1.5
somethingelse extends this {
}
.
//jdk 1.6
somtheingelse extends that {
}
=> compile both to two different jar files, which you deploy on one system but not the other...
not perfect, but could work
...wait: if your libraries just differ in the package name, then you don't need a shadow class. Can't you move the one or the other in the same package?