Source Allies Logo

Sharing Our Passion for Technology

& Continuous Learning

<   Back to Blog

Java EE 6 and Scala

Last weekend while pondering the question "Is Scala ready for the enterprise?" I decided to write a simple Java EE 6 app entirely in Scala, without using any Java. I had three main reasons for doing this: one was just to see how easy/difficult it would be to write everything in Scala (it was easy).  Another was to document the process for others journeying down the same road (the entire project is on github).  Finally, I wanted to identify advantages of using Scala instead of Java that are specific to Java EE apps (I found several).

Background

The specific app I created was an adaptation of the Books example from Chapter 10 of Beginning Java™ EE 6 Platform with GlassFish™ 3. It's a simple web app that displays a list of books in a database and lets you add new books. Although it's a pretty trivial app, it does touch on several important Java EE 6 technologies: JPA 2.0, EJB 3.1 and JSF 2.0.

Results

As a baseline, I first created the example from the Book using Java (and put it on github). The three Java classes are mostly identical to the book: Book.java, BookEjb.java and BookController.java. Aside from those, I refactored common elements of the two JSF views into a template, included the Blueprint CSS framework and created a better Maven pom.xml.

Next I rewrote the Java parts in Scala (and put it on github). Initially I did a one-to-one mapping of the Java classes to their Scala counterparts. Once that was complete I did a bit of refactoring to Book.scala and BookEjb.scala, so the versions you'll see on github now look a bit different.  During this process I did use some hints from a few other related blog posts.

JPA

First up, here's Book.java:
package com.sourceallies.model;

import javax.persistence.*;

@Entity
@NamedQuery(name = Book.FindAllBooks, query = "SELECT b FROM Book b")
public class Book {
	public static final String FindAllBooks = "findAllBooks";

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(nullable = false)
	private String title;

	private Float price;

	@Column(length = 2000)
	private String description;

	private String isbn;
	private Integer nbOfPage;
	private Boolean illustrations;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public Float getPrice() {
		return price;
	}

	public void setPrice(Float price) {
		this.price = price;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getIsbn() {
		return isbn;
	}

	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}

	public Integer getNbOfPage() {
		return nbOfPage;
	}

	public void setNbOfPage(Integer nbOfPage) {
		this.nbOfPage = nbOfPage;
	}

	public Boolean getIllustrations() {
		return illustrations;
	}

	public void setIllustrations(Boolean illustrations) {
		this.illustrations = illustrations;
	}

	public static String getFindallbooks() {
		return FindAllBooks;
	}
}

The Java version has 58 lines of completely useless getters & setters.  You need at least 9 lines per field and more for additional annotations. IDEs like Eclipse can generate these getters/setters for you, but they still take up space and must be maintained over time.

Now let's look at the Book entity in Scala:

package com.sourceallies.model

import javax.persistence._
import scala.reflect._

@Entity
@NamedQuery{val name = "findAllBook", val query = "SELECT b FROM Book b"}
class Book extends Id with Description {
  @Column{val nullable = false}
  @BeanProperty
  var title: String = _

  @BeanProperty
  var price: Float = _

  @BeanProperty
  var isbn: String = _

  @BeanProperty
  var nbOfPage: Int = _

  @BeanProperty
  var illustrations: Boolean = _
}

/** Defines an id field for entities to use as a primary key. */
trait Id {
  @javax.persistence.Id
  @GeneratedValue{val strategy = GenerationType.IDENTITY}
  @BeanProperty
  var id: Long = _
}

/** Defines a description field for entities. */
trait Description {
  @Column{val length = 2000}
  @BeanProperty
  var description: String = _
}

In the code base these are actually three separate files: Book.scala, Id.scala and Description.scala, I just included them all in one place here for convenience.

The Scala version needs only two lines per field: one for the @BeanProperty annotation to generate getters/setters in the compiled class and one to declare the field itself.  This is seven lines less than the Java version per field.

Fields are declared as vars so they are public by default, mutable and every var that is a non-private member of some object implicitly defines a getter and a setter method with it.  So "var x" defines a getter just named "x" and a setter named "x_=".  This lets you get the field using object.x and set it using object.x = y.

If JPA supported Scala-style accessors & mutators, we'd be done, but it requires the use of get/set methods.  This is why we use @BeanProperty on each field.  This instructs the Scala compiler to generate Java-style get/set methods in the compiled class file so it looks just like a Java entity to JPA.

You may also be wondering why each field is assigned a value of _ in its declaration.  This is just the default value in Scala, just like omitting an initializer in Java: 0 for numeric types, false for booleans, and null for reference types.

The annotations also look a bit different; in Java they're @Column(nullable = false) but in Scala are @Column{val nullable = false}.  This is just how you do it in Scala.

I also pulled the id and description fields out into their own traits. This makes the entity class shorter and makes common fields reusable and more consistent across entities.  I could have pulled all fields out into their own traits, but in practice there's probably a limit to how much you'd want to do this, some fields will be specific to a single entity class and not reusable.

EJB

Now let's look at BookEjb.java:
package com.sourceallies.ejb;

import java.util.*;

import javax.ejb.*;
import javax.persistence.*;

import com.sourceallies.model.*;

@Stateless
public class BookEjb {
	@PersistenceContext(unitName = "book")
	private EntityManager manager;

	@SuppressWarnings("unchecked")
	public List&lt;Book&gt; findBooks() {
		return manager.createNamedQuery(Book.FindAllBooks).getResultList();
	}

	public Book createBook(Book book) {
		manager.persist(book);
		return book;
	}
}

The Java version is very simple: it basically just provides two Book-specific CRUD methods using a JPA EntityManager.

And here is the Scala version:

package com.sourceallies.ejb

import javax.ejb._
import javax.persistence._
import com.sourceallies.model._

@Stateless
@LocalBean
class BookEjb extends CrudEjb[Book]

/** Provides basic CRUD support using an injected JPA entity manager. */
trait CrudEjb[E] {
  @PersistenceContext
  protected var manager: EntityManager = _

  def create(entity: E): E = {
    manager persist entity
    entity
  }

  def readAll()(implicit m: Manifest[E]) = manager createNamedQuery ("findAll" + m.erasure.getSimpleName) getResultList

  def read(id: Long)(implicit manifest: Manifest[E]): E = manager.find(manifest.erasure, id).asInstanceOf[E]

  def update(entity: E): E = manager merge entity

  def delete(entity: E) { manager remove entity }
}

Again, these are two separate files in the actual code base: BookEjb.scala and CrudEjb.scala.

In the Scala version I created the CrudEjb trait that provides full CRUD support for any JPA entity, so the concrete EJB can be defined simply as BookEjb extends CrudEjb[Book].  In several places we need the Class object of the entity, which is difficult to obtain due to Java's erasure of generic types at runtime.  Scala's Manifests are a great solution to this problem.

The Scala version requires the @LocalBean annotation while the Java version does not (not sure why).  Also the EntityManager is defined as a var without the Java-style getters and setters.  The container is able to inject the EntityManager using the Scala-style mutator (bean.manager = x) but it does log an error about it not having a set method.

JSF

And now the BookController.java:
package com.sourceallies.controller;

import java.util.*;

import javax.ejb.*;
import javax.faces.bean.*;

import com.sourceallies.ejb.*;
import com.sourceallies.model.*;

@ManagedBean
@RequestScoped
public class BookController {
	@EJB
	private BookEjb ejb;
	private Book book;
	private List&lt;Book&gt; bookList;

	public Book getBook() {
		if (book == null)
			book = new Book();
		return book;
	}

	public void setBook(Book book) {
		this.book = book;
	}

	public List&lt;Book&gt; getBookList() {
		if (bookList == null)
			bookList = ejb.findBooks();
		return bookList;
	}

	public void setBookList(List&lt;Book&gt; bookList) {
		this.bookList = bookList;
	}

	public String doNew() {
		return "newBook.xhtml";
	}

	public String doCreateBook() {
		book = ejb.createBook(book);
		bookList = ejb.findBooks();
		return "listBooks.xhtml";
	}
}

This Java version is simply a Book-specific CRUD wrapper around BookEjb, and provides Book and List<Book> objects to the JSF views.

And finally, BookController.scala:

package com.sourceallies.controller

import javax.ejb._
import javax.faces.bean._

import com.sourceallies.model._
import com.sourceallies.ejb._

@ManagedBean
@RequestScoped
class BookController {
  @EJB
  private var ejb: BookEjb = _

  private val book = new Book

  def getBook = book

  def getBookList = ejb.readAll

  def doNew() = "newBook.xhtml"

  def doCreateBook() = {
    ejb create book
    "listBooks.xhtml"
  }
}

The Scala version is basically just the Java version converted to Scala, no major changes, just looks a bit cleaner due to Scala's concise syntax. As with the EJB, we get an error logged about not having a set method for injecting BookEjb, but the container does actually inject an instance properly.

Conclusion

Even though this was a simple example, I think it shows a few advantages of using Scala instead of Java in Java EE apps. You can forget about useless getters/setters in JPA entity classes, use traits to reuse common JPA entity field definitions and mixin common behavior in EJBs (example: BookEjb could also mixin Logging trait and other traits). And advanced Scala features like Manifests help you write better code faster.

This example only scratched the surface of what Scala can do, and didn't even use things like closures, case classes, pattern matching or Scala's functional programming capabilities (using Scala collections of JPA entities would help a lot).