Freitag, 8. Juli 2011

Marrying JSF with Scala - Part1

 This is the first part of a mulitpart blogpost on how to marry JSF with Scala.

Why Scala? Java is fine


My personal opinion is, having done programs in many languages, that Scala is a huge step up from Java complexity-wise and many things are corner case fillers which probably could have been left out with a more lenient approach.
Nevertheless Scala has lots of merits as well.

The code reduction compared to Java on the average is 30-50% less thanks to better property handling and other things like closures.
The speed if touched right is about the same as Java (one of the complaints about groovy).
However, if you want to apply Scala you seriously have to touch it the way you would touch C++, make up your mind on what part of the language you really use and only touch others in rare cases.

But lets stop the criticism here. Scala has lots of merits especially for JSF:

  • Absence of setters and getters
  • Tight integration with Java
  • Isolation of common constraints via Mixins instead of base classes
  • Same or almost the same performance as java
  • Closures for things like iteration
  • etc...
So lets dig into JSF and Scala

Part 1, Managed Beans

The possible easiest entry into combining Scala and JSF is to create a managed bean. Every managed bean in JSF is a pojo with a handful of setters and getters. (and more depending on your functionality)
It probably is the easiest artifact within the JSF stack you can get.

Let us have a look at a simple Java managed bean:


The same now would be coded in Scala


Note for the people who are familiar with Scala, we took two assumptions here, first we are using for familiarity
reasons the Java mutable LinkedList and secondly we use BeanProperties
(we could resolve that with our own el resolver as well)


This is tightlier written, but what about data encapsulation what about setters and getters?
Scala follows a different route for data encapsulation. You can set properties but usually the data is public until you have overrides which cause the data encapsulation without any further code interference.

Also one thing noticeable is, that the implements Serializable has been replaced by a @serializable annotation. The rest of the annotations is applied as is.

So what about this @BeanProperty?

This is a special Scala annotation which tells the compiler to encapsulate the property and generate setters and getters for it.

I want to use CDI instead of ManagedBeans

CDI has been the new kid on the block and given that bigger projects nowadays either use Spring or CDI it makes sense to cover the CDI integration here as well.
To sum the CDI and Scala situation regarding managed beans, it is as seamless as it is with pure managed beans.

Here is an example:


Of course you still can use @Inject and other CDI constructs as well.

@BeanProperties is this really needed?

As you have seen @BeanProperties produces the connection between our properties and the EL by encapsulating the property and providing Java like setters and getters.
This is very inelegant, first of all, because to access those properties, you have to use the setters and getters on the Scala side as well, and the code is convoluted with annotations.

Wouldn't it be nice to simply have something like:


This works as expected, even the EL will pick up all properties, thanks to Scalas public per default convention. However we now face a problem, once we want to encapsulate for instance val1. If we now would make it private or protected the code definitely would be broken and the EL would not pick it up anymore. As long as you stay in Scala, you can use Scala properties, however the EL is implemented in Java and expects Java setters and getters.

So to make the EL scala aware we have to roll out a binding solution, but first, lets talk about Scala properties.

Scala properties are a different convention. From outside they are invisible by default but they still implement full isolation.

So, code like myobj.myprop = 1 still would be myobj.myprop = 1 after the isolation has been added.

So how do we do it?

  • the def val1: Int = _val1 is basically our new getter replacing our old val1 for read access
  • def val1_$eq (val1: Int) is basically a convention to open val1 for write access via the = operator.
This works within Scala seamlessly and for orm frameworks as well as long as they know the Scala convention (most do by now via plugins). But on the Java side you have to call those methods directly via <methodName> and <methodName>_eq.
The last remaining open problem is the Expression Language. The EL relies on setters and getters for accessing the properties.

Thankfully there is a way to override the ELs handling via a custom resolver tailored for Scala. Now this code would override the scope of this blog, but you can download the sources for this EL resolver as Maven project from https://github.com/werpu/scalaelresolver
(NOTE: You have to follow the included readme.txt for your own project integration)

End of Part1

We now have reached the end of part1. The next part will be about the ViewController patterns. Page navigation Codi style in Scala, and what we can do with Scala traits in a JSF context. So stay tuned.

6 Kommentare:

  1. Of course, if you just want to get rid of the getters and setters, you can also use Lombok.

    AntwortenLöschen
  2. Jepp but Scala has more to the table than just getting rid of the pesky property accessors. The following articles will show it.

    AntwortenLöschen
  3. Hi
    when I use


    jsfutil.ScalaELResolver


    I am getting
    Cause: Unable to create a new instance of 'jsfutil.ScalaELResolver': javax.faces.FacesException: jsfutil.ScalaELResolver.
    could you provide the jar file which have this class.
    Regards
    Philip

    AntwortenLöschen
  4. Hello sorry for answering so late, but I was busy with other projects. I now have created a github project for the Scala EL Resolver together with an example. You can find it in:

    https://github.com/werpu/scalaelresolver

    AntwortenLöschen
  5. I have updated the blog accordingly, so that the el resolver link now points to the project with a hint to follow the readme for proper installation instructions.

    AntwortenLöschen