Saturday, 20 August 2011

Liftweb setup in 10 minutes - IDE and project configuration

Scala is one of the coolest programming languages out there and Lift is a revolutionary web framework that really leverages many scala features.

But it could be daunting at the beginning, even just getting your workspace setup. In this article I will go through the basic setup of your IDE, it really takes a few minutes!

Even though I've always been an eclipse person I'm using IDEA IntelliJ with scala cause I think is way superior.
Ok let's begin. You will need IntelliJ 10.5.1, Maven or SBT.

Create the project with maven

First step is to create the project and for that we will use lift maven archetype. For the persistence layer we will use the default lift mapper. Run this command
mvn archetype:generate   -DarchetypeGroupId=net.liftweb   
  -DarchetypeArtifactId=lift-archetype-basic_2.8.1   
  -DarchetypeVersion=2.3 
  -DarchetypeRepository=http:/scala-tools.org/repo-snapshots 
  -DremoteRepositories=http://scala-tools.org/repo-snapshots 
  -DgroupId=com.playamatch  -DartifactId=web
You can also create a JPA based project running the same command with
archetypeArtifactId=lift-archetype-jpa-basic_2.8.1

You already have a full liftweb project! You can even run it with maven itself using the command

mvn jetty-run

Download and configure IntelliJ

Next open IntelliJ and install the scala plugin. You need to go to File -> Setting. This is where you can access all the configuration options. The equivalent of Window -> Preferences in eclipse.
Now go to the plugins, pick scala right click "Download and Install" and once done restart the IDE.
You should be able to see your code with syntax highlights and navigate through the classes already.

If you want you can also download the SBT plugin for IDEA. In this tutorial I will use the command line.

Another configuration change you might want to do if you are coming from eclipse if the shortcuts. IDEA comes with an eclipse profile that will allow you to keep using all the handy shortcuts you've learned so far.


Configure SBT

I would recommend using SBT for your projects with the scala compiler is very fast ( well as fast as it gets really ;) ) Here I am using SBT 0.10.1

You need to create a build.sbt in the project root folder. This is what mine looks like, it is pretty much the standard dependencies.

/build.sbt
name := "liftplay"

scalaVersion := "2.8.1"

seq(webSettings: _*)



// If using JRebel uncomment next line
//jettyScanDirs := Nil


resolvers += "Java.net Maven2 Repository" at "http://download.java.net/maven/2/"


libraryDependencies ++= {

  val liftVersion = "2.3" // Put the current/latest lift version here

  Seq(

    "net.liftweb" %% "lift-webkit" % liftVersion % "compile->default",

    "net.liftweb" %% "lift-mapper" % liftVersion % "compile->default",

    "net.liftweb" %% "lift-wizard" % liftVersion % "compile->default")

}



// Customize any further dependencies as desired

libraryDependencies ++= Seq(

  "org.eclipse.jetty" % "jetty-webapp" % "7.3.0.v20110203" % "jetty", // For Jetty 7

  //"org.mortbay.jetty" % "jetty" % "6.1.22" % "jetty,test", // For Jetty 6, add scope test to make jetty avl. for tests

  "org.scala-tools.testing" % "specs_2.9.0" % "1.6.8" % "test", // For specs.org tests

  "junit" % "junit" % "4.8" % "test->default", // For JUnit 4 testing

  "javax.servlet" % "servlet-api" % "2.5" % "provided->default",

  "com.h2database" % "h2" % "1.2.138", // In-process database, useful for development systems

  "ch.qos.logback" % "logback-classic" % "0.9.26" % "compile->default" // Logging

)

Then create another file under project/plugins (create these folders in your root project directory if you don't have them) called again build.sbt

/project/plugins/build.sbt
resolvers ++= Seq(

  "Web plugin repo" at "http://siasia.github.com/maven2",

  Resolver.url("Typesafe repository", new java.net.URL("http://typesafe.artifactoryonline.com/typesafe/ivy-releases/"))(Resolver.defaultIvyPatterns)

)



//Following means libraryDependencies += "com.github.siasia" %% "xsbt-web-plugin" % "0.1.0-""

libraryDependencies <+= sbtVersion(v => "com.github.siasia" %% "xsbt-web-plugin" % ("0.1.0-"+v))

last file is the build.properties under the project folder
/project/build.properties
project.organization=com.playamatch
project.name=liftplay
project.version=1.0-SNAPSHOT
sbt.version=0.10.1
def.scala.version=2.8.1
build.scala.versions=2.8.1
project.initialize=false
That's it. All you need to do now is an update to download all the dependencies

Get dependencies and run application

sbt update

and then you can run your new application
sbt ~jetty-run

Enable Debug for your application

If you want to debug your application just add the following to your sbt script
Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

and then create a remote application debug configuration from Run -> Edit configurations. First check your defaults are like this then click on the plus sign

and name your run configuration!
Happy coding!!!

Tuesday, 9 August 2011

Hibernate Gotchas!

I've been using Hibernate for some time now and when I don't work on a hibernate project for a while I find myself doing the same mistakes I did the previous times

So here is a sort of watch list for my self hopefully will be useful to someone else as well.


Implement hashCode and equals


You should always implement these methods in general but for your entities you should pay a bit more attention.The first thing you think when I say equals is probably to use the Id to distinguish between instance. Well, that's gonna cause you a lot of troubles.
You need to keep in mind that you are working with db entities and not normal POJOs.

When Hibernate is fetching objects is your using collections and hence equals and hashCode to know if an object you are looking for is in the session. For new objects id will be null or 0.
That means when trying to save two objects of the same class the second is going to overwrite the first one.
Also when hibernate saves a new instance it will set the id, thus making it a different object while it is exactly the same.
You need to use some business keys. Unique codes are great but if you can't think of anything just use a meaningful field and some timestamp (like creation date) to make it unique.

This is a good reference if you want to understand a bit further what's happening.

Careful with One-to-One and Many-to-One relations


This is something you really need to know.
When mapping a relation as One-to-One or Many-to-One on the "One" side of the relation you can't have lazy loading unless you specify the field as not nullable.

Why is that?
Essentially on the many side of the relation hibernate can use collection proxies and lazily load instances when required.
On the "One" side there is no collection interface but instead a reference to one of your model classes.
Hibernate can proxy that one as well but only if it is sure the reference will never be null!
So remember if you want to have lazy loading use the not null on the one side together with the lazy annotation (or xml equivalent).
If your relation can be null but you still really want to make it lazy then you have some options:
  • Create a value to represent that. For example if you have a relation like Person -&amp;amp;gt;Partner  just use a specific instance of Partner that means "no partner".
  • Use build time instrumentation. Check this
  • Fake the one side using a List and getting the field with get(0)

Read more on the hibernate documentation

Enable the statement logging


This is the only way to verify Hibernate is really doing what you expect him to do. Luckily enough there are different logging parameters that you can use to find out what is happening both at the HQL or if you want at the SQL level. You'll be surprised how many times hibernate is running queries and you did not except it. Try to this from the very beginning and help the team understand the importance of having the best and least possible queries or you'll surely have performance issue when running the application on some real data. To enable logging just set this property in the session configuration file
hibernate.show_sql=true
If you want to see it nicely formatted add
hibernate.format_sql=true

Watch what goes in the toString method.

This one is again related to what Hibernate fetches for you without you really being aware. Lots of times when you see queries but can't figure out why some lazy list is being loaded then check the toString method.
It might be the culprit!



What are your hibernate gotchas?