Thursday, February 25, 2010

How to Convert a Java List to a Scala List (actually... let's not do that)

If you're using Scala and still making use of pretty much any Java library, you'll pretty soon come up against this problem: you're Java library has returned you a java.util.List, but you want to use the awesome methods contained in Scala's scala.List (soon to be scala.collection.immutable.List).

I'll show you how to do what you want in a second, but first, and importantly, I need to explain that what you actually want to do is NOT convert a Java List to a Scala List. Why? It's because, despite the name similarity, they're actually very different things...

The difference is that Java's List is an interface, while Scala's List is an implementation. The List interface in Java represents a concept: a collection of elements that maintains insertion order (i.e. a sequence) and allows, among other things, random access to its elements. The most commonly used implementation is ArrayList, which is mutable (i.e. invoking add(element) changes the existing list) and has constant-time random access. Unlike Java's List interface, Scala's List is a specific implementation of a sequence. In that sense, it is a parallel to ArrayList, but in many other senses, it's nothing like it. The List class imported by default in Scala is an immutable linked list - it can't be changed after it's been created and operations requiring random access take linear time. Scala's List is not a direct substitute for Java's List and it's extremely different to ArrayList as well. So, what to do?

Most people want to convert their Java List to a Scala List just so they can use cool Scala functions like map(), filter(), find(), foreach(), foldLeft() and flatMap(). And that's a perfectly good excuse. But if you look into the Scala API, you'll see that all of these useful methods are available on any class that implements the Iterable trait. (From Scala 2.8, they are also available on the Traversable trait, which the Iterable trait extends.)

If we look a bit further into the Scala API, we'll see that there's also a trait called Seq, which is a slightly better parallel to Java's List than the Iterable or Traversable traits. So what you really want to end up with when you bring your Java List into your Scala code is a Scala Seq, not a Scala List.

That's enough jibber-jabber. I'm sure you've learnt your lesson.

Here's a great way to convert a Java List to a Scala Seq in Scala 2.7:

scala> var javaList = new java.util.ArrayList[Int]()
javaList: java.util.ArrayList[Int] = []

scala> javaList.add(3)
res0: Boolean = true

scala> javaList.add(4)
res1: Boolean = true

scala> javaList.add(5)
res2: Boolean = true

scala> val scalaSeq = new collection.jcl.BufferWrapper[Int]() {
def underlying = javaList
}
scalaSeq: java.lang.Object with scala.collection.jcl.BufferWrapper[Int]{def underlying: java.util.ArrayList[Int]} = [3, 4, 5]

scala> println(javaList)
[3, 4, 5]

scala> println(scalaSeq)
[3, 4, 5]

In Scala 2.8, the EPFL LAMP guys have realised the importance of this kind of conversion and gone one better by providing a class full of conversions that do exactly what we want, like this:


scala> var javaList = new java.util.ArrayList[Int]()
javaList: java.util.ArrayList[Int] = []

scala> javaList.add(3)
res0: Boolean = true

scala> javaList.add(4)
res1: Boolean = true

scala> javaList.add(5)
res2: Boolean = true

scala> val scalaSeq = scala.collection.JavaConversions.asBuffer(javaList)
scalaSeq: scala.collection.mutable.Buffer[Int] = Buffer(3, 4, 5)

scala> println(javaList)
[3, 4, 5]

scala> println(scalaSeq)
Buffer(3, 4, 5)

Of course, so much of the appeal of Scala is attributable to having to write less code, so it would be nice to not even have to invoke these operations within functions but instead to have implicit functions that will perform the conversions whenever they're necessary.

In Scala 2.7, the implicit conversion can be defined like this:

implicit def javaList2Seq[T](javaList: java.util.List[T]) : Seq[T] =
new BufferWrapper[T]() { def underlying = javaList }

And in Scala 2.8, all you need to do is import the existing implicit functions!

import scala.collection.JavaConversions._

Friday, January 29, 2010

Why Your Company Should Let You Use Scala at Work

Java at Work: An Increasingly Frustrating Experience

A colleague and I were writing a test in Java today and I had one of those "I can't believe it takes this much work to write this stupid function" moments. If you do any Scala programming but still do a lot of Java programming, you'll know exactly what I mean. I'll walk you through a mock of what we were doing and you can see why Scala just pummels Java when it comes to expressiveness. (Early warning: do not use the word "expressive" when trying to convince your manager to let you use Scala at work.)

So, here's the gist of the code that we were testing:

import java.util.ArrayList;
import java.util.List;

class AccountSummaryService {
public List<CustomerSummaryDTO> getAccountSummaries() {
return new ArrayList<CustomerSummaryDTO>();
}
}

class CustomerSummaryDTO {
private String name;
private List<AccountSummaryDTO> accountSummaries;

public String getName() {
return name;
}

public List<AccountSummaryDTO> getAccounts() {
return accountSummaries;
}
}

class AccountSummaryDTO {
private String name;
private int balance;

public String getName() {
return name;
}

public int getBalance() {
return balance;
}
}
and here's the gist of the test that we wrote:

import org.junit.Test;

import java.util.List;
import java.util.NoSuchElementException;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

class AccountSummaryServiceJavaTest {
AccountSummaryService service = new AccountSummaryService();

@Test
public void getAccountSummaries() {
List<CustomerSummaryDTO> result = service.getAccountSummaries();
assertThat(balanceFor("Customer 1", "Account #2", result),
is(1000000));
}

private int balanceFor(String customerName, String accountName,
List<CustomerSummaryDTO> result) {
for (CustomerSummaryDTO customer : result) {
if (customer.getName().equals(customerName)) {
for (AccountSummaryDTO account : customer.getAccounts()) {
if (account.getName().equals(accountName)) {
return account.getBalance();
}
}
}
}
throw new NoSuchElementException("Account not found");
}
}
As you can see, I'm a bit of a fan of fluent interfaces, hence the use of Hamcrest matchers and the balanceFor() method. This makes for a nice, readable test, but boy is that balanceFor() method ugly! Considering the simple job it's doing, there is a lot of code and - the thing I especially hate - a lot of noise. I would say this code has a relatively low signal-to-noise ratio.

The lack of visual appeal isn't the only problem. Another problem is that, despite being trivial, it took more than a few seconds to write. An even more disturbing problem is that my colleague and I both spent another 30 seconds triple-checking this code to make sure it was doing what we wanted it to. Not because it's complex (it's not) or because we're stupid (we're not). We were checking it over because (a) it took too long to write for such a simple operation, so we thought maybe it could be simplified, and (b) there is so much noise in the code that it just LOOKED like a bear trap for stupid errors.

I quipped that the same function in Scala would be much shorter and easier to read. My colleague called me on it and asked what the Scala would look like, so I wrote some hacky Scala in a comment to give him the feel of it. It was, of course, slightly wrong, and turned out to be more complex than it needed to be, but I wrote it again when I got home and compiled it just to prove my point. Here's the balanceFor() method rewritten in Scala:

def balanceFor(customerName : String, accountName : String, result :
Iterable[CustomerSummaryDTO]) =
result.find(_.getName == customerName).get
.getAccounts().find(_.getName == accountName).get
.getBalance
You can see straight away that this function is shorter. Just syntactically, using Scala has removed a lot of the noise: theres no type declarations in the implementation; there's no verbose but meaningless local variable names because we can use _ to create anonymous functions; we're able to use == instead of .equals() with the same effect; the exception is thrown by the API because find() returns an Option; and, thanks to the power of Scala's API, we can even lose the braces because the whole function is just one expression.

But its endearing qualities don't end at the reduced demands on screen lines and hard drive. The Scala implementation reads in a way that is so much closer to the intent of the function - so much closer than a for loop with a nested if, with a nested for, with a nested if, followed by four closing braces and a throw statement. The find() function expresses what we are trying to do exactly; to a reader attempting to comprehend the code, its simplicity is profound when compared to the for statement and if statement that combined do the same thing but are spread over two lines in the Java version.

To make a fair comparison, I will highlight that Scala has added one piece of noise to the implementation that wasn't present in the Java: the .get call at the end of each of the first two lines, used to access the contents of the Option returned by find(). To anyone who has read an introductory Scala book, this will make immediate sense and to anyone that hasn't even seen Scala before, a 30-second explanation of Option should make everything pretty clear.

Note: Some people believe that you should never use the .get function on Option - never, ever! I don't agree with them absolutely. In general, this function is probably not a good one to call if you're writing production Scala code, but I think it can still be useful in certain circumstances. See the comments if you want to know more.


For me, the best part about this code is that the combination of its succinctness, expressiveness and almost total lack of noise means that we wouldn't need to spend 30 seconds triple-checking it. Not only did it take such a short time to write that I could still remember the first key-stroke by the time I'd finished, but I can look at this code and see what it does without having to read it.

Hang On, I Thought This Blog Was About Using Scala at Work?

Actually, so far it's been about not using Scala at work, and how annoying that can be.
How can we change this situation?

Well, imagine you go to your boss and you say, "Hey, Boss. Can we start using Scala?" and he says, "Why?" and you say, "Um, 'cause it's a functional language so it's more expressive and it has monads and everything's immutable so it might help us to write better multi-threaded code" and he'll say? ... "Get back to work".

Well, the silly little method above, along with the issues it solved, is a perfect little use case for why Scala could be great for your company's software development. Forget all the functional paradigms and monadic, higher-kinded academia - these are just buzz words that dumb people use to sound important. (Kidding.) No, there are real, practical, business reasons your company should let you code in Scala. My experience, as demonstrated in the code here, is that Scala lets me write code faster and also makes it harder for me to get things wrong. Or, to rephrase that in managerese, it increases output and improves quality.

So, instead of pitching technical buzzwords at your boss, imagine trying this out: "Hey, Boss. How would you like it if I could write twice as much code in a day and have more confidence that it actually does what I intend it to?" Now you're speaking his language: Output and Quality. But why not go one better than imagining? Why not go and ask your boss now!

If your boss says YES, and you need to get up to speed with Scala, you'll probably want to grab one of these books:

From Amazon




From The Book Depository


Programming in Scala - Martin Odersky, Lex Spoon & Bill Venners (Artima)

Programming Scala - Venkat Subramaniam (The Pragmatic Programmers)

Programming Scala - Dean Wampler & Alex Payne (O'Reilly)

Beginner Scala - David Pollak (Apress)

Pro Scala - Gregory Meredith (Apress)


Disclaimer:
It's not my intention to represent Scala as being better than Java for every project in every organisation, or for any particular one at all. Obviously there are many more issues to consider when adopting a language than just those presented here. My claims that Scala increases output and quality are based only on my own anecdotal observations and not on any empirical evidence. You should make your own investigations before making any commitment to using Scala in a commercial context.

Monday, January 18, 2010

How To Create a Webapp with Scala, Spring, Hibernate and Maven

Update: I've written a new blog entry with a link to code on GitHub that combines the latest versions of Scala, Spring, Hibernate and Maven. The original blog entry below is still a great walk-through for learning how to put together all the technologies from scratch.


The Technologies

So, this post is simply a recipe for combining four of today's most popular technologies: Spring, Hibernate, Maven and Scala.

In case you're new to some of these technologies, here's a REALLY quick overview:

Spring is a framework for creating enterprise applications that uses Inversion of Control, Dependency Injection, Aspect-Oriented Programming (including annotation-based transaction boundaries) and lots of flexible, highly-extensible components for building pretty much anything. Its Model-View-Controller (MVC) web framework has been a popular replacement for Struts.

Hibernate is an Object-Relational Mapping library, used to store data from Java objects into relational databases (and retrieve it again).

Maven is a Java-based and -focussed build tool that uses a common project lifecycle and a declarative Project Object Model (POM) to make it simple to build applications by defining only what needs to happen, rather than how it happens (which remains in the implementation details of its plugins).

Scala is a Functional/Object-Oriented hybrid language that executes on the Java Virtual Machine (JVM) and is becoming increasingly popular, especially with Java developers, mostly due to its concise syntax, static typing and seamless integration with the Java SE API.

The Task

The task is to write a simple webapp that can persist and retrieve an entity. The goal is to use the latest of everything, including Scala 2.8, Hibernate 3.2.7 with annotations and Spring 3 and it's annotation-based controllers for creating REST-ful webapps.

The first part of this tutorial is basically just a diary of the steps I took to create a working application using Maven, Scala, Spring and Hibernate. I won't do a lot of explaining because different readers will obviously have different knowledge about different technologies, but I've documented every single web page that gave me a useful piece of information in putting the whole thing together.

The second part is a documentation of all the little things that went wrong while creating the "how to". Including these in the main introduction would just be a distraction but I'm sure the fixes I had to discover and correct will be useful to a few people scouring the internet for solutions one day.

Enough chatter, let's write some code…

No, wait!
Let's GENERATE some code! :)

Step 1: Use Maven to Create a Project

If you don't already have Maven installed, you'll need to download and install it and put its bin/ directory on your path.

References:
Download Maven

I already had it installed (although I don't remember installing it - is it standard on a Mac?) so I went to the directory where I wanted the project to live and created a new Maven project using the Scala archetype with this command:
mvn org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create \
-DarchetypeGroupId=org.scala-tools.archetypes \
-DarchetypeArtifactId=scala-archetype-simple \
-DarchetypeVersion=1.1 \
-DremoteRepositories=http://scala-tools.org/repo-releases \
-DgroupId=au.com.belmonttechnology -DartifactId=scala-spring-hibernate

References:
Scala Blogs: maven for scala

Then I went into the directory and built the project:
mvn clean package

After downloading lots of plugin code, it successfully compiled the App and AppTest classes and then the AppTest.testKO test case failed. No need to panic - the implementation of this generated Test shows that it's meant to fail. It proves that Maven is running the test.

Too easy. Onwards and upwards...

Step 2: Get Scala and Maven Working in Your IDE

I'm using IntelliJ IDEA 9 Community Edition (it's free!). I was dead-simple to create a new IDEA project using the Maven POM that was just generated. Here are the steps:

1. New Project
2. Import project from external model
3. Maven
4. Choose directory
5a. Only tick 'Import Maven projects automatically' and 'Use Maven output directories'
5b. Use 'process-test-resources'
6. Finish!

You'll also need to make sure you've got a Scala plugin for your IDE installed and working. In IDEA, you can get one just by going into the Plugins config pan, searching for Scala and downloading the one that pops up.

To make sure the IDE was set up properly, I opened the App class, and changed it to look like this:
object App {
def main(args: Array[String]) {
println( "Hello World!" );
}
}
and then ran it (in IDEA use: CTRL-SHIFT-F10)

I like to live on the edge, and I noticed that the Scala version that the Maven archetype had delivered me was 2.6.1. Pfh!

So, I opened up http://scala-tools.org/repo-releases/org/scala-lang/scala-library/ in Firefox and found the latest and greatest (and hopefully somewhat stable) Scala release version, which was 2.8.0.Beta1-RC7 at the time of writing. I copied this version into the top of pom.xml, where the archetype had written:
<scala.version>2.6.1</scala.version>
I ran the App class again to make sure it's still working

Having proved that the App class was working - I DELETED IT!

Step 3: Create a Spring Web Application

I added the following two entries into the <repositories> section of the POM:
<repository>
<id>com.springsource.repository.bundles.release</id>
<name>EBR Spring Release Repository</name>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
<repository>
<id>com.springsource.repository.bundles.external</id>
<name>EBR External Release Repository</name>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>

References:
Obtaining Spring 3 Artifacts with Maven

Then I added the following line to the <properties> section:
<org.springframework.version>3.0.0.RELEASE</org.springframework.version>

and added the following dependencies to the <dependencies> section:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.context</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.transaction</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web.servlet</artifactId>
<version>${org.springframework.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>

I wanted to get Spring working before I tried to integrate Hibernate, so I created a new package, au.com.belmonttechnology.spring.web, and created a new Scala class in there called HelloWorldController, and wrote this code:
@Controller
class HelloWorldController {
@RequestMapping(Array("/hello.html"))
def showHello = "helloPage"
}

References:
Mapping requests with @RequestMapping

I ran mvn clean package again to make sure this little guy compiled.

Then I created a src/main/webapp/WEB-INF directory and created a web.xml file with a basic DispatcherServlet setup:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="scala-spring-hibernate"
version="2.5">

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>

</web-app>

References:
DispatcherServlet reference documentation
DispatcherServlet javadoc
Introduction to Spring MVC Web Framework
JSTL 1.2 and maven-jetty-plugin

Then I created the web-context.xml file that is used to initialise the Spring context for the DispatcherServlet. I set up a component-scan for the package that contains the HelloWorldController and inserted the same UrlBasedViewResolver configuration that everyone else in the world is using:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan
base-package="au.com.belmonttechnology.spring.web"/>

<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

</beans>

References:
Annotation-Based Autowiring in Spring 2.5
Annotation-based controller configuration
Spring Web MVC Views and resolving them

Then I created the JSP that the HelloWorldController was returning as it's view: src/main/webapp/WEB-INF/jsp/helloPage.jsp
<%@page contentType="text/html;"%>
<html>
<body>
<h1>Hello from ${pageContext.request.serverName}</h1>
</body>
</html>

References:
JSTL Implicit Objects
ServletRequest javadoc

And, finally, I changed the POM's packaging to be 'war':
   <packaging>war</packaging>

At this point, I was able to mvn clean install the project and everything builds, but there's no way of running the webapp...

Step 4: Start the Webapp with Maven using the Jetty Plugin

One of the easiest ways I've found of getting a webapp to run for testing is to use the Jetty Maven Plugin. All I had to do was add the Jetty plugin to the POM:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.0.2.v20100331</version>
</plugin>

References:
Jetty Maven Plugin

Then on the command line I simply ran:
mvn clean package jetty:run
and it all started up brilliantly.
I accessed http://localhost:8080/hello.html and saw a beautiful thing:

Hello from localhost

So, with my Spring 3 / REST / Scala app running on Jetty, I moved onto Hibernate…

Step 5: Get Hibernate Running in Spring

I added a dependency for the latest version of Hibernate and Hibernate Annotations to the POM:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.4.0.GA</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
I also added a couple of dependencies that Hibernate would need:
       <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.8</version>
</dependency>
Then I created a very simple Hibernate @Entity class in Scala:
package au.com.belmonttechnology.data

import javax.persistence.{GeneratedValue, Id, Entity}
import reflect.BeanProperty

@Entity
class Customer() {
@Id @GeneratedValue
var id: Long = 0

@BeanProperty
var name: String = null;
}

References:
Hibernate Annotations
JavaBean Properties in Scala

Next, I created a controller that would be able to serve a "Create New Customer" form, receive the POST submission from the form and redirect to a JSP that would display the newly-stored entity:
package au.com.belmonttechnology.spring.web

import org.springframework.stereotype.Controller
import au.com.belmonttechnology.data.Customer
import org.springframework.beans.factory.annotation.Autowired
import org.hibernate.SessionFactory
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.{PathVariable, ModelAttribute, RequestMapping}
import org.springframework.web.bind.annotation.RequestMethod._
import org.springframework.web.servlet.ModelAndView

@Controller
class CustomerController {
implicit def sessionFactory2Session(sf: SessionFactory) =
sf.getCurrentSession();

@Autowired
var sessionFactory: SessionFactory = null

@ModelAttribute("command")
def createCustomerForFormBinding = new Customer

@RequestMapping(value = Array("/customers/new"), method = Array(GET))
def showNewCustomerForm() = "newCustomer"

@Transactional
@RequestMapping(value = Array("/customers/new"), method = Array(POST))
def createNewCustomer(@ModelAttribute("command") customer: Customer) =
"redirect:/customers/" + sessionFactory.save(customer) + ".html"

@Transactional(readOnly = true)
@RequestMapping(
value = Array("/customers/{customerId}"), method = Array(GET))
def viewCustomer(@PathVariable customerId: Long) =
new ModelAndView("customer", "customer",
sessionFactory.get(classOf[Customer], customerId))
}

References:
Spring @Autowired Annotation
Annotation-based controller configuration
Hibernate Session javadoc
Understanding the Spring Framework's declarative transaction implementation
Scala for accessing a Class at runtime
Spring ModelAndView javadoc

Then I created JSPs to match the views that I'd specified in the controller - newCustomer.jsp for submitting a POST to create a new Customer in the database:
<%@page contentType="text/html;"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<body>
<h1>New Customer</h1>
<form:form>
<form:label path="name">Name</form:label>
<form:input path="name"/>
<input type="submit" label="Create Customer"/>
</form:form>
</body>
</html>
and customer.jsp for viewing a Customer entity that's been retrieved from the database:
<%@page contentType="text/html;"%>
<html>
<body>
<h1>${customer.name}</h1>
<p>Might I suggest enhancing the system to support more than just a customer's name?</p>
</body>
</html>
References:
Spring Form Tag Library

I decided I need a quick and dirty in-memory database to test with, so I added the dependency for HSQLDB to the POM, as well as the Apache Commons Database Connection Pool:
       <dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2</version>
</dependency>
Then I wrote the Spring config for Hibernate, and a BasicDataSource (using HSQLDB) in a file called spring-context.xml…
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<tx:annotation-driven/>

<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:scala-spring-hibernate"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>au.com.belmonttechnology.data.Customer</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
</beans>
.. and wired it into the web.xml using Spring's ContextLoaderListener:
   <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml</param-value>
</context-param>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Lastly, I added an OpenSessionInViewInterceptor into the Spring configuration in web-context.xml and specified this as an interceptor on the DefaultAnnotationHandlerMapping:
...

<bean id="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list><ref bean="openSessionInViewInterceptor"/></list>
</property>
</bean>

...


References:
Understanding the Spring Framework's declarative transaction implementation
Spring Hibernate Tutorial
Unit-Testing Hibernate With HSQLDB
Introduction to Spring MVC Web Framework
OpenSessionInViewInterceptor

Then I fired it all up again with mvn clean package jetty:run, browsed to http://localhost:8080/customers/new.html and voila! I happily spent the rest of my evening delighting in entering new customers into my in-memory database. (Not.)

If you'd like to get your hands on this fantastic new application, you can download the source code from Belmont Technology (MIT licence).

Here's some books you might find useful if you plan to go further with Spring, Hibernate, Scala or Maven:

From Amazon









From The Book Depository


Spring in Action - Craig Walls & Ryan Breidenbach (Manning)

Hibernate in Action - Gavin King & Christian Bauer (Manning)

Spring Recipes - Gary Mak (Apress)

Programming in Scala - Martin Odersky, Lex Spoon & Bill Venners (Artima)

Maven - A Developer's Notebook - Vincent Massol & Timothy M. O'Brien (O'Reilly)


Problems, Problems, Problems

Okay, in all honesty, it was nowhere near as straightforward to create this simple webapp as the journal above makes out. There were a number of compilation errors, thrice as many runtime exceptions, and the number of Google searches required was approaching a googol. But for your benefit - either by help or by humour - I've documented below the error, cause and solution to all of the hitches I encountered along the way.

Problem 1: NoClassDefFound when running Scala App in IntelliJ

When I first tried to run the App class in IntelliJ, I got a NoClassDefFoundError as output.
At this point, I opened the Maven tab and tried to run the 'test' phase, which told me that I didn't have a Maven Home Directory set, so I went into the project settings and fixed that.
After this, I was able to run the 'test' phase successfully, and then the App class ran successfully, too.

Problem 2: Invalid URI / Invalid Authority trying to access the Maven repository

After first adding Spring to the POM, I got some errors in my Maven pane in IDEA. I tried running the compile goal and got the following Maven error in the console:
Invalid uri 'http:// repository.springsource.com/maven/bundles/release/org/springframework/org.springframework.context/3.0.0.RELEASE/org.springframework.context-3.0.0.RELEASE.pom': Invalid authority
I copied and pasted this URL into Firefox, upon which it did a Google search, which is an unusual thing to do with a URL. Looking closer, I realised there was a space after http:// in the repository URL that I'd pasted into the POM. I deleted the space and was able to run the compile goal successfully (although, at this point, there was nothing to compile!)


Problem 3: Type Mismatch in Scala annotation

When I first created the HelloWorldController and tried to run the mvn package phase, I got the following compilation error:
[ERROR] /Users/graham/Code/scala-spring-hibernate/src/main/scala/au/com/belmonttechnology/spring/web/HelloWorldConroller.scala:16: error: type mismatch;
[INFO] found : java.lang.String("/hello.html")
[INFO] required: Array[java.lang.String]
[INFO] @RequestMapping("/hello.html")

It was easy enough to figure out how to fix this - in Scala, annotation parameters that are an array require Array(…) around them. In Java, you're allowed to leave the curly braces out when there's only one value for an array in an annotation, but Scala (at the moment) always requires an actual array.

References:
Arrays in Scala annotation arguments

Problem 4: IntelliJ IDEA not compiling Scala code

While I was fixing the problem with the annotation, I noticed a much more worrying problem, which was that IDEA wasn't compiling my Scala code. Pressing CTRL-F9 (Command-F9, actually) did nothing, even if I changed the code and saved the file and tried again.

Coincidentally, I also noticed at this point that controller was actually spelled 'Conroller'. So I renamed it, and just after I did a little box flashed up saying a Scala file had been detected and did I want to install the Scala facet. I wasn't quick enough to click it the first time, so I had to rename the controller again and hit the 'Create Scala facet' link.

Then I tried to compile again and I was shown a dialog box with the message "Cannot compile Scala files. Please attach a scala-compiler.jar to any project module." Seeing as I'm using Maven, I decided to add the Scala compiler dependency to the POM instead of directly into IntelliJ (which I assumed might remove it on the next POM update anyway):
       <dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>${scala.version}</version>
<scope>provided</scope>
</dependency>
I don't want to package the Scala compiler into my WAR, so I've used the 'provided' scope because this makes the artefacts available at compile time, but NOT at runtime. Now I compiled in IDEA, and finally I get the same error in IDEA that Maven was giving me earlier, and I fix the annotation on the controller to use an Array:
 @RequestMapping(Array("/hello.html"))



Problem 5: AppTest.testKO fails (even though I deleted it)

After getting IDEA compiling Scala properly, I executed the Maven package goal again and that silly AppTest.testKO caused my build to fail, but I'd deleted the test class! I realised I hadn't run the 'clean' task for a while, so I did that and then it was all building successfully again.

Problem 6: Spring Web requires Commons Logging

When I first tried to start Jetty, I got this error:
2010-01-16 13:59:12.392:WARN::FAILED ContextHandlerCollection@58a1a199: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
2010-01-16 13:59:12.392:WARN::FAILED HandlerCollection@5b787144: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
2010-01-16 13:59:12.392:WARN::Error starting handlers
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:179)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
It appears that spring-web requires commons-logging, but doesn't declare it as a dependancy. I solved it by adding this to the POM:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>

Problem 7: DispatcherServlet's Context Configuration File

Having fixed the commons-logging problem, I started Jetty again and got this error:
INFO: Loading XML bean definitions from ServletContext resource [/WEB-INF/dispatcher-servlet.xml]
Jan 16, 2010 2:01:07 PM org.springframework.web.servlet.FrameworkServlet initServletBean
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/dispatcher-servlet.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:341)
By default, the DispatcherServlet will look for a config file with the name of the servlet entry ('dispatcher', in my web.xml) with "-servlet.xml" tacked on the end. I got the DispatcherServlet to read my configuration file by adding this to the <servlet> in web.xml:
       <init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-context.xml</param-value>
</init-param>

References:
Spring FrameworkServlet javadoc

Problem 8: Scala Syntax for Accessing a Class object at Runtime

When I first wrote the CustomerController.viewCustomer method, I tried to use the Java syntax to access the Customer's corresponding (runtime) class object:
sessionFactory.get(Customer.class, customerId)
which didn't compile. After realising I'd never had to do this before in Scala, I went searching and found that the syntax for getting the class object representing a type at runtime in Scala is:
classOf[Customer]

References:
Scala for accessing a Class at runtime


Problem 9: Hibernate Depends on the javax.transaction / JTA

When I first added Hibernate to the POM, I tried to compile (without adding any Hibernate code) and Maven gave me the following error:
Missing:
----------
1) javax.transaction:jta:jar:1.0.1B

Try downloading the file manually from:
http://java.sun.com/products/jta
Since I was pretty sure that wouldn't be using any JTA features, I simply added an exclusion for it to the <dependency> in the POM:
       <dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.7.ga</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>

I should mention that IntelliJ's POM integration here was AWESOME, allowing me to auto-complete the group and artefact IDs of the exclusion by showing me a list of all Hibernate's transitive dependencies! If any IDEA developers are reading this - you guys ROCK!

Problem 10: Spring can't find HttpServletRequest

When I tried to compile the CustomerController for the first time, I received this compilation error:
Error: error while loading View, Missing dependency 'class javax.servlet.http.HttpServletRequest', required by /Users/graham/.m2/repository/org/springframework/org.springframework.web.servlet/3.0.0.RELEASE/org.springframework.web.servlet-3.0.0.RELEASE.jar(org/springframework/web/servlet/View.class)
The problem this time was that spring-web, while relying heavily on the Servlet API, declares the dependency with the 'provided' scope, which is the right thing for the Spring guys to do but a small gotcha for people trying to use it. The solution is just to add a sevlet-api dependency into your own POM (which should ALSO use the 'provided' scope):
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

References:
Maven Repository: javax.servlet::servlet-api


Problem 11: Incompatible version of SLF4J

After adding the javax.servlet dependency, I started up Jetty again and Spring spewed out the following error along with a massive stack trace:
2010-01-16 21:47:54.804:WARN::Nested in org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring-context.xml]: Invocation of init method failed; nested exception is java.lang.IllegalAccessError: tried to access field org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory:
java.lang.IllegalAccessError: tried to access field org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory
I found a forum saying that the slf4j-api distribution had a different implementation of StaticLoggerBinder to the one in the slf4j implementation JARs, and that to get it to work you need to include both in your classpath (with the API having priority). The solution was to add the SLF4J API to the POM:
       <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.8</version>
</dependency>

References:
StaticLoggerBinder.SINGLETON IllegalAccessError on Hibernate forum

Problem 12: NoSuchMethodError in Hibernate Annotations

I was originally using Hibernate version 3.1.3, as there was some repository indexing page I had browsed suggested that was the latest. When I started up Jetty, I got this error message:
2010-01-16 21:52:06.913:WARN::Nested in org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring-context.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.hibernate.cfg.SecondPass.doSecondPass(Ljava/util/Map;)V:
java.lang.NoSuchMethodError: org.hibernate.cfg.SecondPass.doSecondPass(Ljava/util/Map;)V

I found a page where someone had the same problem and a respondent suggested they try a newer version of Hibernate, so I used IntelliJ's Maven integration to download the whole index of repo1.maven.org and then auto-complete the version for the Hibernate dependency, which showed me that the newest version of hibernate-annotaions was actually 3.4.0.ga. Switching to the latest version made the error go away.


Problem 13: Spring Form Binding Requires a Command object

When I first tried to view the newCustomer JSP, Jetty returned an error page showing this:
2010-01-16 21:54:19.068:WARN::/customers/new.html
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
I had, as I often do, forgotten to provide a blank form object for the new form, which was easily solved by adding this method to the CustomerController:
 @ModelAttribute("command")
def createCustomerForFormBinding = new Customer

Problem 14: Can't Access a Scala 'var' from JSP

After providing the blank form object for the JSP to bind from, I got this error:
Invalid property 'name' of bean class [au.com.belmonttechnology.data.Customer]: Bean property 'name' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

I was actually expecting this one to happen! It occurred because a var in a Scala object, while publicly accessible, does not conform to the JavaBeans specification, which is what JSPs and JSTL use to inspect beans and retrieve data from them. Scala provides the @BeanProperty annotation that can be used to tell the compiler to generate getter and setter methods for a variable in order to make it accessible by JavaBeans-reliant tools.
 @BeanProperty
var name: String = null;

References:
JavaBean Properties in Scala


Problem 15:

When I first submitted a request to CustomerController.createNewCustomer, I got the following error:
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I remembered that I had decided to experiment and see whether my OpenSessionInViewInterceptor would be automagically picked up by the default annotation handler mappings (some Spring beans do this for some of their dependenices). But, they weren't. Solution: define the mappings bean explicitly and inject the interceptor as a property:
   <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list><ref bean="openSessionInViewInterceptor"/></list>
</property>
</bean>


Problems solved.
Hope you enjoyed that.

Graham.

Saturday, November 28, 2009

Scala: Under The Hood of Hello World

The exercise of printing 'Hello World' from a new programming language is so popular because it allows you to see quite a few things about a language straight away, including the style of the syntax, how to print output and the amount of boilerplate required just to start a simple application.

After getting Hello World to work, there's really two directions you could go: you can go forward, and start doing other stuff with the language, or you can go down, drill deeper, by asking the question "How does it work?"

While moving forward is certainly more productive and exciting in the short term, understanding what's going on underneath the covers of your code can be very beneficial and can lead to insights that may affect the way you write code for the rest of your programming life. For instance, if you've done a bit of Java and a bit of Scala, it may have occurred to you that Scala allows you to define objects (as opposed to classes), while Java has no concept of compile-time objects, so how does the Scala compiler map the concept of an object into Java's single-minded view of classes? We'll find out…

Opening the Hood with Scala
Unless you've managed to run a Scala Hello World program accidentally, you have probably read enough of some Scala tutorial, book or blog to know that Scala is compiled to Java Bytecode - the binary language that is read and executed by the Java Virtual Machine (JVM). This means that a good way to get an idea of what actually happens when we run a Scala program is to have a look at the bytecode that is generated when we compile the application.

So, here's your standard Scala Hello World program:

object HelloWorld {
def main(args: Array[String]) {
println("Hello World!")
}
}

If we compile this program and have a look at the output directory for classes, we'll find two Java class files:

-rw-r--r-- 1 graham staff 778 28 Nov 09:43 HelloWorld$.class
-rw-r--r-- 1 graham staff 607 28 Nov 09:43 HelloWorld.class

Two classes? Yep, two classes. We compile one "object" and we end up with two classes. Let's have a look at what's inside these classes.

If you want to see what's going on inside a Java class (or a Scala class or object that's been compiled to a Java class) you can inspect the class file with the JDK tool 'javap'. Depending on the options you provide to javap, it can print you out just a summary of the class' method signatures or you can see a pseudo-English translation of the all compiled bytecodes. Let's start by having a look at just the signatures:

[scala-tests] graham$ javap -classpath . HelloWorld HelloWorld$
Compiled from "HelloWorld.scala"
public final class HelloWorld extends java.lang.Object{
public static final void main(java.lang.String[]);
public static final int $tag() throws java.rmi.RemoteException;
}

Compiled from "HelloWorld.scala"
public final class HelloWorld$ extends java.lang.Object implements scala.ScalaObject{
public static final HelloWorld$ MODULE$;
public static {};
public HelloWorld$();
public void main(java.lang.String[]);
public int $tag() throws java.rmi.RemoteException;
}

Wow! So, we wrote one method - HelloWorld.main() - and we've ended up with 6 methods and one static field across two classes. Obviously not all of this code is relevant to the running of our HelloWorld program, so let's discuss some of the surrounding fluff and then put it out of mind.

What Is This $tag() Thing?
Probably the first obvious thing is that both classes have a method called $tag(). If we have a look at the Scaladocs for the ScalaObject trait, the base class of all classes and objects compiled by Scala, we'll see no mention of the $tag() method. However, if you have a look at the source of ScalaObject.scala, you'll see this definition, which is been in the Scaladoc:

/** This method is needed for optimizing pattern matching expressions
* which match on constructors of case classes.
*/
@remote
def $tag(): Int = 0

Basically, the $tag() method is a simple categorisation method akin to java.lang.Object's hashCode() that is used by Scala to make it's much-lauded pattern matching perform better. Interestingly, in the 2.8.0 branch of Scala, $tag() has been removed, so now that we understand it, we know that we don't really have to worry about understanding it any more!

What Makes It Run?
Having learnt enough to ignore the $tag() method, let's have a look at how our program runs. Your keen eye may have noticed that we have two main() methods - one on the HelloWorld class and one on the HelloWorld$ class. If you're lucky enough to have two keen eyes, you would have noticed that the main() method on HelloWorld is static, but the main() method on HelloWorld$ is not. The significance of this is that, though there are two main() methods, only one of the classes - HelloWorld - can be used to start the application. If I tried to start the application by telling the java command to start with the HelloWorld$ class, the JVM will happily tell me that I'm an idiot:

[scala-tests] graham$ java -cp .:$HOME/Library/Scala/Current/lib/scala-library.jar HelloWorld$
Exception in thread "main" java.lang.NoSuchMethodError: main

Instead of acting like an idiot, let's have a look at what this HelloWorld.main() method does. The javap command allows us to see the actual bytecode instructions that are contained within the class if we pass the -c option:

[scala-tests] graham$ javap -c -classpath . HelloWorld
Compiled from "HelloWorld.scala"
public final class HelloWorld extends java.lang.Object{
public static final void main(java.lang.String[]);
Code:
0: getstatic #11; //Field HelloWorld$.MODULE$:LHelloWorld$;
3: aload_0
4: invokevirtual #13; //Method HelloWorld$.main:([Ljava/lang/String;)V
7: return
...

If you've learnt a little bit about Java bytecode, reading what this method does is pretty simple…
0: This instruction retrieves the value of the static field HelloWorld$.MODULE$ and pushes it onto the stack. We can see both from this line (after the colon) and from the signatures we looked at above that the type of the MODULE$ field is HelloWorld$.
3: This instruction takes the first argument to the method - the String[] that represents the command-line arguments - and pushes it onto the stack.
4: This instruction invokes the main() instance method on the HelloWorld$ object that was pushed onto the stack at 0, passing it the String[] pushed onto the stack at 3.
At the heart of it, this is a pretty simple operation. If we were to write this method ourselves in Java, it would look like this:

public static void main(String[] args) {
HelloWorld$.MODULE$.main(args);
}

What Is This MODULE$ Thing?
Moving on, I think the next thing we want to find out is, what is MODULE$ and how is it initialised? Chances are you're pretty smart and you've probably figured this out already, so let's just cut straight to the bytes:

[scala-tests] graham$ javap -c -classpath . HelloWorld$
Compiled from "HelloWorld.scala"
public final class HelloWorld$ extends java.lang.Object implements scala.ScalaObject{
public static final HelloWorld$ MODULE$;

public static {};
Code:
0: new #10; //class HelloWorld$
3: invokespecial #13; //Method "":()V
6: return

public HelloWorld$();
Code:
0: aload_0
1: invokespecial #17; //Method java/lang/Object."":()V
4: aload_0
5: putstatic #19; //Field MODULE$:LHelloWorld$;
8: return
...

Again, reading this is pretty simple. Basically it's creating a singleton instance of HelloWorld$ which is stored in a public static field. There's a static block that creates a new HelloWorld$ object and there's a HelloWorld$() constructor, which does something which I find a little bit odd. If we translated it into Java, we'd have something like this:

public final class HelloWorld$ {
public static final HelloWorld$ MODULE$;

static {
new HelloWorld$();
}

public HelloWorld$() {
super();
MODULE$ = this;
}
}

Does that assignment in the constructor look a little weird to you? The constructor is setting the value of the static MODULE$ field. This is especially strange seeing as MODULE$ is a final static field. If you tried to use this Java code you'd find that it wouldn't even compile. At first I thought that this was so odd that I must have interpreted the bytecode incorrectly, so I wrote this little Java class to test out what happens when you call the HelloWorld$() constructor directly:

public class HelloWorldTest {
public static void main(String[] args) {
System.out.println(System.identityHashCode(HelloWorld$.MODULE$));
new HelloWorld$();
System.out.println(System.identityHashCode(HelloWorld$.MODULE$));
}
}

Sure enough, the output of running this code shows that every invocation of the HelloWorld$() constructor does indeed change the value of MODULE$, even though it's final:

2114843907
1179703452

That's a bit of an oddity, but there's a lesson there - never call the constructor of a Scala object from Java code - there is no telling what kind of havoc you may wreak if you instantiate a second instance of an object that is assumed to be a singleton within your Scala code.

Dude, Where's My Code?
Okay, so nothing we've examined up until now has had ANYTHING to do with the one line of imperative code that we wrote in Scala. But we're almost there, as there's only one piece of the double-main() puzzle left to examine - HelloWorld$.main():

[scala-tests] graham$ javap -c -classpath . HelloWorld$
Compiled from "HelloWorld.scala"
public final class HelloWorld$ extends java.lang.Object implements scala.ScalaObject{
...
public void main(java.lang.String[]);
Code:
0: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #28; //String Hello World!
5: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return

And here we finally see the code that we actually wanted to run. This method is extremely similar to the main() method we saw in HelloWorld: It pushes the singleton instance of Scala's Predef object onto the stack, pushes the "Hello World!" constant onto the stack and then invokes the Predef.println() method.

Can You Repeat That In English?
Let's summarise what we found in the bytecode of this HelloWorld program. When you define a main() method on a Scala object, the Scala compiler splits the responsibility of running your application into two classes. One class has the same name as your object and contains a static method that is invoked by the JVM to start the application. The other class, which has the same name as your object except with a dollar sign ($) at the end, contains the actual code of your object's main() method in an instance method called main(), as well as a constructor and a public static field for creating and accessing a singleton instance of this special class.

If you want to read some more about why the code from you object ends up in a class that has a dollar sign at the end of its name, you might like to do some reading on companion objects in Scala.

Bonus Marks for Pointing Out Something Nerdy
There is one other little surprise in here that I skipped over and which I only noticed while looking at a decompilation of a Java HelloWorld program. The HelloWorld class generated by the Scala compiler has no constructor at all. Not one. It is im-possi-ble to create an object of type HelloWorld. This is a minor departure from the convention of Java where every class has at least one constructor, by virtue of the Java compiler generating one for you if you decide not to define one. This little difference has absolutely no effect on anything at all, but I always find it interesting when the Scala guys decide to contradict ideas that have been Java "laws" since what seems like the beginning of time. It almost feels like they're slaying Jack Harkness.

Friday, November 6, 2009

XML Generation with Scala

When I first heard the about a proposal to add native XML (a.k.a. XML literals) into Java, my first thought was: who writes XML in their code? I've created plenty of services that generate XML in my time, but they've all either used a template engine like JSPs or Velocity or been generated by an object tree, vis-a-vis JAXB. So my question became: who would even WANT to write XML in their code? It stank of a poor separation of concerns.

Today, however, I am eating my words. I've just written a small utility that uses Scala to generate the HTML of a simple web page, so I used Scala's native XML and it is Good. It's remarkably simple and intuitive, so I thought I'd share the love.

XML Literal Coercion

So, Scala essentially has XML literals, which means that you can just start typing XML in the middle of your code and the Scala compiler will automatically coerce it into an object that can be used for performing xml-ish operations. If you try this using the 'scala' interpreter, you can see some of what happens under the hood:

scala> val myXml = <test><tag/></test>
myXml: scala.xml.Elem = <test><tag></tag></test>

Note that there's no quotes or special charters around the XML - it's just XML. Scala automatically turns it into an Elem object.

But this isn't where the fun ends! The power of native XML comes from the fact that it's very easy to escape out of XML and into Scala code, right in the middle of your XML. You can escape into Scala simply to include some computed output in the XML, or you can do more crazy things like looping through a list and yielding a list of more Elem objects to be included.

Escaping to Scala: Text

From what I've seen so far, there are two slightly different ways to escape into Scala from an XML literal. The first is used when you want to escape into Scala to include text or another XML element and it looks like this:

val name = "Graham"
val xmlOne = <test>{name}</test>
println(xmlOne)

Output:

<test>Graham</test>

Escaping to Scala: Attributes

If, however, you want to escape at the XML attribute level, you would be WRONG if you tried to do this (like I did):

val xmlTwo = <test name="{name}"/>
println(xmlTwo)

You don't get a compilation error, but the "escaping" is not interpreted, so you get this:

<test name="{name}"></test>

The syntax for escaping an attribute properly looks like this:

val xmlThree = <test name={name}/>
println(xmlThree)

All we've done is drop the quotes, and now we get the output we want:

<test name="Graham"></test>

Escaping to Scala: Elements and Looping

Finally - this is where the power becomes really evident - you can escape into Scala and evaluate an expression that yields a list of Elems in order to include an iteration of values in your XML. Observe:

val hobbies = List("Scala", "Photography", "Cycling")
val xmlFour =
<test name={name}>
{for (hobby <- hobbies) yield <hobby>{hobby}</hobby>}
</test>
println(xmlFour)

Output:

<test name="Graham">
<hobby>Scala</hobby><hobby>Photography</hobby><hobby>Cycling</hobby>
</test>

Did you notice the really cool part of that? After we escaped out of the XML literal into Scala so that we could loop through the list, we then started another XML literal and then escaped out of that one to print the value 'hobby'! At that point we are nested 4-deep: Our outer XML literal contains nested Scala, which contains a nested XML literal, which contains more nested Scala. And yes, this could go on forever, down and down and down (just like the turtles). The great thing is that the syntax is so intuitive that you probably hardly noticed that we had gone that deep in this example - the code is simple and clear.

A Little Warning

Note that, when you're looping and yielding, there's nothing to stop you returning something that's not an Elem - Scala will simply call toString on whatever you return and insert it into your XML as text. For example, the following compiles and runs, but doesn't produce what we want:

object Test {
case class Scala;
case class Photography;
case class Cycling;

def main(args: Array[String]) {
val name = "Graham"
val xmlFive =
<test name={name}>
{for (hobby <- List(Scala, Photography, Cycling)) yield hobby}
</test>
println(xmlFive)
}
}

The output from this?

<test name="Graham">
&lt;function&gt;&lt;function&gt;&lt;function&gt;
</test>

Ewwww… (and, yes, the entities do appear in the output)

In conclusion: I used to think that native XML in Java was a stupid idea. Now I don't really care because Scala has it and it looks good and it works fine so whenever I need to produce XML from within code I'll just use Scala.

A Side-Note

If you're slightly genius, you're probably wondering why, in the last example, I showed my whole 'Test' object, whereas in all the other examples I just showed the contents of the main() method. The simple explanation is that I had originally defined the case classes in the main method, but I got this compile error:

Test.scala:19: error: forward reference extends over definition of value xmlFive
{for (hobby <- List(Scala, Photography, Cycling)) yield hobby}
^

To be honest, I wasn't (and I'm still not) exactly sure why this was a problem, but it seemed obvious that scalac was not happy for me to define a case class inside a method and then use that class in the same method (well, actually, I'm using its companion object). I wonder if the compiler injects the instantiation of the companion object at the end of the method, rendering it unusable throughout? That would seem a bit silly. Anyway, the obvious fix was to move the declaration of the case classes out of the definition of main(), and hence why I posted the whole class as the example.