Summary: Demonstrating the steps that are necessary to use Spring with Scala by translating Spring.io’s guides from Java to Scala.
This is the content of my talk I gave at the Spring I/O conference in Barcelona (19.&20.05.2016). Slides can be found here.
- But why?
- Examples
- Summary
- Scala SDK is getting better at dealing with Java
- Conclusion
- Thanks for reading
Scala is becoming a popular choice when developing for the JVM. However, developers with a Spring/Java background might be reluctant to give up all of their familiar tools and frameworks.
In this post I’d like to demonstrate how to introduce Scala into an existing Spring/Java environment.
But why?
Using Spring with Scala feels a bit like this:
It seems I’m trying to sneak in Scala into the harmonic marriage of Spring with Java. A valid question therefore is: why should someone want to do this?
I think there are good reasons.
Why Scala?
I could also ask: why learn a new programming language? There are probably two reasons:
- For fun: learning a new programming language makes me a better developer
- For profit: your boss might want to use it, the job market has an increasing number of Scala projects etc.
Scala was built for functional programming from ground up, where for Java it’s been added on top of it. And that shows up in code, many times solutions can be expressed more concisely in Scala.
Why Spring + Scala?
Possible reasons why this might be a good idea:
- You come from a Java/Spring background and think it sufficient in the beginning to learn a new language. Why drop also all the tools that you know and are efficient in (I for example absolutely love Spring Boot, I don’t want to give it up).
- New languages come always with new frameworks and tools. Those are that: new and unproven. There is some risk involved using them. Spring has been around for a very long time and is proven and comes with support.
- Probably the most common reason: you and your team want to gradually introduce Scala into your existing Java/Spring project. This is without problems possible.
Examples
In order to demonstrate how we can use Scala with Spring I went to the guide section of Spring.io1, selected a few of the guides and translated them into Scala.
The source code of the examples can be found as usual on Github2.
The Spring.io guides have the advantage of being short, yet showcasing distinct features of Spring.
First example: serving websites using Spring MVC
The Spring MVC example consists basically of four files:
.
├── build.gradle
└── src
└── main
├── java
│ └── hello
│ ├── Application.java
│ └── GreetingController.java
└── resources
└── templates
└── greeting.html
We have our build file (Gradle), the template, the Spring main application and a controller (we don’t have a model in this simple example).
Making Gradle work with Scala
In order to make Gradle work with Scala, we just need to add the Scala plugin and add the dependency to Scala.
I’ve also added the application
plugin so that I can execute the examples using gradle run
but that is optional.
That’s all that is necessary to build & run the examples.
Application class
The Java application class is a typical Spring Boot application (Application.java
):
This becomes following in Scala (Application.scala
):
We don’t have static methods in Scala, so we add an object
to our main class. We can use Java/Spring annotations like @SpringBootApplication
in Scala the same way as in Java (one exception see below).
We only need to pass our arguments as args:_*
(basically a compiler hint).
That’s all there is to do. This is true for the rest of the examples.
Template
Of course, no changes need here, just to demonstrate how this example works, the template (template.html
) looks like this:
We pass a name
parameter to the template.
Controller
The Java side is a typical MVC controller (GreetingController.java
):
In Scala, we only need to handle the @RequestMapping
annotation differently. Instead of passing just a String, we need to wrap it into an Array("/greeting")
(file GreetingController.scala
):
That’s it. We can now run the project and ping the endpoint:
$ gradle run
...
2016-05-06 16:05:52.644 INFO 1297 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-05-06 16:05:52.650 INFO 1297 --- [ restartedMain] scala.App$class : Started App.class in 5.117 seconds (JVM running for 5.753)
$ curl http://localhost:8080/greeting?name=SpringIO
<!DOCTYPE HTML>
<html>
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Hello, SpringIO!</p>
</body>
</html>
Example consuming a REST service
In this example, we access a sample rest service to retrieve a random quote.
complete-java$ tree .
.
├── build.gradle
├── src
│ └── main
│ └── java
│ └── hello
│ ├── Application.java
│ ├── Quote.java
│ └── Value.java
Beans in Scala
Simple POJOs are shorter with less boilerplate in Scala, however, they don’t follow the bean standard with getter/setter. In order to make this work, we need to annotate fields of a bean with Scala’s @BeanProperty
annotation (Value.scala
):
Asynchronous consumption
The original guide uses a synchronous RestTemplate
to access the webservice. That translates almost 1:1 in Scala. To make things a bit more interesting, let’s use an asynchronous example.
The Java application class (Application.java
):
The example uses the AsynchRestTemplate
. Calling the endpoint returns a future that we can attach two callbacks to, one for the success case and one for a failure. addCallback
is Java 8 ready, meaning we can use Java 8 Lambdas.
Java 8 Lambdas look strikingly similar to Scala function literals
Java: (Integer a, Integer b) -> a + b
Scala: (a:Int, b:Int) => a + b
However, putting Scala functions into the Spring callback method does not work. We have to fall back to ugly anonymous classes:
This is going to change with Scala 2.12. See below.
Example: providing a REST API
├── build.gradle
├── complete-java.iml
├── complete-java.ipr
├── complete-java.iws
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
└── main
└── java
└── hello
├── Application.java
├── Person.java
└── PersonRepository.java
In Spring Data Rest most work resolves around implementing repositories.
The Java side is straight forward (PersonRepository.java
):
That translates almost 1:1 in Scala (PersonRepository.scala
):
However, running this creates an error:
PersonRepository.scala:8: type arguments [hello.Person,Long] do not conform to trait PagingAndSortingRepository's type parameter bounds [T,ID <: java.io.Serializable] trait PersonRepository extends PagingAndSortingRepository[Person, Long] {
which translates is due to: Scala Long != Java Long. We need to make sure to pass the Java base type to the Java interface import java.lang.Long
(or use the full package name).
Final example: JDBC
In this example, we access a relational database using JdbcTemplates
. We create a table, insert some data and execute a query to check the results.
Java side
The steps in Scala:
Create a collection of names in Scala
Dealing with Java, we can’t use Scala’s default immutable collections. Instead, we need to fall back to mutable package in Scala.
import scala.collection.mutable.ListBuffer
val splitUpNames = ListBuffer("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long“).map(_.split(" "))
splitUpNames.foreach(name => log.info("Inserting customer record for %s %s".format(name(0), name(1))))
passing a collection to Java
The signature of batchUpdate
method is this: public int[] batchUpdate(String sql, List<Object[]> batchArgs)
We need to pass a List<Object[]>
collection. This requires type casting:
- Java
Object
<=> ScalaAnyRef
- Java Array
[]
<=> ScalaArray
- Java (mutable) List <=> Scala
mutable.Buffer
We do the casting here:
Now, splitUpNames.instanceOf[...]
is still a Scala collection that we can’t pass to Java. For this, Scala provides JavaTransformations.asJava
. The complete code becomes:
Querying the db: receiving a collection from Java
In the final step, we want to accomplish this in Scala:
Here, we have to other direction and need to call asScala
on the collection that is returned from Java.
The complete implementation:
Summary
Those are the steps I had to do in order to make my selection of guides work in Scala:
What | Step | Effort required |
---|---|---|
Make Gradle work with Scala | add scala plugin & dependency |
easy |
Application class | split into class & object, pass args with args:_* |
easy |
Use Spring annotations | need to add Array(STRING) |
easy |
Create beans in Scala | Use @BeanProperty annotation |
easy |
Implement Java/Spring interface | Import java base types | slightly annoying |
Using Java collections in Scala and vice versa | Transform collections using JavaTransformations asJava and asScala |
slightly annoying |
Pass collections from Java to Scala and vice versa | Casting required, eg Object to AnyRef | annoying |
Pass collections from Java to Scala and vice versa | We have to use mutable collections in Scala | annoying |
Using Scala functions as Java Lambdas | Not possible for Scala < 2.12 | annoying / not a problem anymore |
Scala SDK is getting better at dealing with Java
One important point to remember: the Scala SDK is getting better at working with Java 8. Scala 2.12 has Lambda support and that makes working with Spring a lot better in Scala.
That brings me to another point: what about using additional frameworks that ease working with Spring? For example, there has been a now defunct Spring-Scala project3. I think there is no need for a framework like that. I prefer to deal in a consistent way with my Java dependencies and rather bet on the Scala SDK to further improve.
Conclusion
If you are wondering why I have only talked about how to use Java from Scala and not more about using Spring from Scala, you are right. And that’s the good news because it means:
It works. Spring is just another Java framework that I can use from Scala.
Drawbacks of using Spring instead of a pure Scala framework:
- I may not always be able to write most idiomatic Scala code
- Transforming & casting can get tiresome
Advantages:
- I can keep my productivity (Spring Boot, yay!)
- I can use a well-proven and supported framework
Thanks for reading
I hope this post was helpful for you. If you have comments, questions or found a bug please let me know, either in the comments below or contact me directly.