Java EE 6 and Scala

February 22nd, 2010 by Zach Cox Leave a reply »

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<Book> 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<Book> bookList;
 
	public Book getBook() {
		if (book == null)
			book = new Book();
		return book;
	}
 
	public void setBook(Book book) {
		this.book = book;
	}
 
	public List<Book> getBookList() {
		if (bookList == null)
			bookList = ejb.findBooks();
		return bookList;
	}
 
	public void setBookList(List<Book> 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).

Advertisement

12 comments

  1. Pooria says:

    Many thanks for the article,

    A few days ago I wondered if I could use JEE with scala, googled it, but didn’t find anything useful. But there you’ve made it clear.

    By the way, is there a (preferably official) place where it is described how to use scala with JEE? I mean, for ex, how did you figure out that you had to use @LocalBean etc?

  2. Werner eil says:

    I don’t think it’s quite there yet. And in the Scala Bazar many things exist in a rough, little maintained state like a draft for Unit support (Java is currently getting this on a core level with JSR-275)

    In a few years I guess it’ll be ready, until then only considered research or POC quality, not production yet.

  3. Zach Cox says:

    @Pooria – there currently is no official documentation for using Scala with Java EE, I dug through some other blog posts for hints and performed a lot of trial & error.

    The use of @LocalBean specifically came from this post:

    http://vikasrao.wordpress.com/2009/06/

  4. Zach Cox says:

    @Werner – while I agree not every enterprise should immediately switch from Java to Scala, there are some compelling reasons to start using it now. Scala compiles to Java bytecode so it can run on the same JVM as your existing Java classes and interact with them pretty seamlessly. And as I’ve shown here, Scala can be used end-to-end in a Java EE app.

    Scala is already being used in production, from startups like Twitter and Foursquare to large organizations like Novell and Sony (http://www.scala-lang.org/node/1658 ).

  5. mcahornsirup says:

    Now, we need some better tooling and it will lift off! I did something similar and was impressed, too… there were some problems when mixing java classes and scala classes at the same time, referencing each other (chicken-egg). But I think, this is not a problem, but avoids bad code ; )

  6. Nice to see an example of the use Scala in JEE. To be fair, your Java and Scala code do not also do the same thing. For exampe, in the JSF managed bean you use a lazy evaluation in getBookList and in Scala you do not (I think the lazy keyword should be helpful here).

    Still, I like the cleanliness of the Scala code.

  7. coubeatczech says:

    hi, I’v tried to play a little bit with this and I found, that I can’t use EJB as I want, because I get NullPointerException. Do you know why?
    http://pastebin.com/uTACayqx
    I always get the error at line 17 when I use the bean. (There’s also a need to tweak web.xml for services)
    Thanks for answering!

  8. Hendy Irawan says:

    For Named Beans in EJB 3.1 to work, they need implement the Serializable interface in Java, so while writing the same in Scala programming language, we “extend” it. The @LocalBean annotation is unique to the Scala implementation. Without this annotation, the session bean exposes a local business interface (ScalaObject in this case) as its client instead of UserController.

    See: http://scala-enterprise.blogspot.com/2010/10/named-beans-in-ejb-31-using-scala.html

  9. @mcahornsirup

    If you have Java and Scala referencing each other, you compile like this:

    scalac *.java *.scala
    javac *.java

    The scala compiler knows enough Java to be able to understand what will be exported by Java code and use it to compile Scala code. Java can then use the generated class files.

    @Werner eil

    Scala Bazar is a failed experiment. There’s plenty stuff for Scala, but you won’t find it through that tool. Presently, the site implicit.ly and the scala tools maven repository are the best way to find stuff for Scala.

  10. Eric P says:

    Actually, you don’t need the @BeanProperty annotation. JPA will use the field definition generated by the var.

    Also, you can use annotations like @Index(name=”role_name”). Perhaps you are using an old version of Scala?

  11. Jean says:

    Hi Zach, Thanks for the good article! Very few articles on this topic on the Web even right now.
    I tried running this example (am using lift basic archetype in eclipse; build through maven). I changed the code to use Derby DB (which comes default wtth basic archetype).

    The index.jsp page redirects to “/listBooks.xhtml”. But when I run the app, I get an empty page. I then included Faces servlet mapping in web.xml as:

    Faces Servlet
    javax.faces.webapp.FacesServlet
    1

    Faces Servlet
    *.faces

    But, after doing this change, am getting runtime errors like “faces servlet not found” etc. Can you please help with this? How do Faces & Scala co-work? What happens when index.jsop redirects to /listBooks.xhtml. Does Lift have anything to do here?
    Is there any update to your code after you posted in this page?

Leave a Reply

*