Friday, May 25, 2012

Play2 Project Dependency

I have recently started to use Play framework, and I quite like it. It may have its issues, but all in all it is a neat framework. Like many other developers out there I want to use it from within my favourite IDE - Eclipse. And Play makes that happen via it "eclipsify" command.
All is good, when you are working on a single application. But what happens when you want to create more than one application and you realize that you don't want to copy the boiler plate code in each of the project. Take the security feature for example. Each app will have to implement it and Play does provide the basics but there is still some code to be written. And I don't want to copy the file(s) each time a I create a new app.
Now Eclipse does have a neat feature where you can create project dependencies which means that all the classes from the project you depend on are added to the classpath of your current project. Great! That works fine for regular Java projects, but Play does its own building behind the scenes which has nothing to do with Eclipse's build.
There is however a way out. And it is quite simple. You see, each Play 2.x project will create the .class files in the [project_dir]/target/scala-2.9.1/classes. (I suspect that the location will change later, when the scala version is updated).
Now let's say you have a project called "common" where you add all the utilities and boiler plate code. Then you have "myApp" where you want to use the code from "common" without copying it. In Eclipse, you go to Project Properties for "myApp", "Java Build Path", select "Project" tab and add the "common" project in the list of required projects. That takes care of the Eclipse side.
To make it work in Play, there is one other thing you need to do. Locate "Build.scala" file from "myApp" project (this will be in myApp/project/ directory). This is the file that controls the Play build. you want to modify it and add the classes generated by "common" project to both runtime and compile classpaths. This is how you can do it:

val wsdir = (new java.io.File("./..")).getCanonicalPath // workspace dir
val appDependencies = Seq(
    // Add your project dependencies here,
)


val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA)
      .settings( 
          dependencyClasspath in Runtime ++= Seq(file(wsdir+"/common/target/scala-2.9.1/classes"))
      )
      .settings(
          dependencyClasspath in Compile ++= Seq(file(wsdir+"/common/target/scala-2.9.1/classes"))
      )
Note that this code snippet assumes that projects "myApp" and "common" share a common parent directory.
And that's it for development. Creating the final build for production is another story and that depends on how you want to deploy your projects.

No comments: