Spring Framework and the Cake pattern

Even though the Spring Framework is (amongst many other things) a dependency injection container, there is still some scope to use the Scala Cake pattern in your Spring code. I am going to talk about the details and the background tomorrow in my Spring in Scala talk tomorrow at Skills Matter; but here are the most important details and motivation.


In a Spring application, we let the framework manage components that expose some API. The components are usually interface-implementation pair; the API is, of course, the methods defined in the interface. Spring Framework then uses metadata we provide (either in XML or in annotations) to instantiate the components and wire up the component together. In other words, we very rarely write code that instantiates or looks up the components, we leave that to the Spring Framework.

If you are using Scala to implement your Spring components, you may be wanting to use the mixin composition that Scala provides in your Spring beans. Let’s build an application that can register a user; we want to configure the way in which we hash (and salt!) the passwords and the way in which we notify the users of a successful registration. In Java/Spring, we will usually write:

public interface PasswordCodec {
  String encode(String plain);
}
public class Sha1PasswordCodec implements PasswordCodec {
  public String encode(String plain) {...}
}
public class PlainPasswordCodec implements PasswordCodec {
  public String encode(String plain) {...}
}

public interface Notifier {
  void registered(User user);
}
public class EmailNotifier implements Notifier {
  public void registered(User user) {...}
}
public class SmsNotifier implements Notifier {
  public void registered(User user) {...}
}

The UserService would then have the instances (configured at runtime) injected into it by the Spring Framework (see Figure 1).

Figure 1. Java-like composition

This is a good start, but the Sha1PasswordCodec, PlainPasswordCodec, EmailNotifier and SmsNotifier are “closed”–that is, we cannot mixin their functions into another component in our system. We can only use the object-oriented delegation pattern. Scala offers the Cake pattern, which takes advantage of the self type annotation to enforce mixing in of other components. Think of this as compile-time dependency injection, where the dependency is not an instance, but a piece of functionality. So, turning this into Scala, we would change the components from classes into traits; viz Figure 2.

Figure 2. Scala composition

Turning this into Scala code, we’ll make the substitution and use the self type annotation on the UserService:

trait PasswordCodec {
  def encode(plainText: String): String
}
trait Sha1PasswordCodec
  extends PasswordCodec {
  def encode(plainText: String) = ...
}
trait PlainPasswordCodec
  extends PasswordCodec {
  def encode(plainText: String) = ...
}

trait Notifier {
  def registered(user: User)
}
trait EmailNotifier
  extends Notifier {
  def registered(user: User) { /* ... */ }
}
trait SmsNotifier extends Notifier {
  def registered(user: User) { /* ... */ }
}

class UserService (private val sessionFactory: SessionFactory) {
  this: PasswordCodec with Notifier =>

  @Transactional
  def register(user: User) {
    user.password = encode(user.password)
    registered(user)
    sessionFactory.getCurrentSession.saveOrUpdate(user)
  }
}

The line this: PasswordCodec with Notifier => says that the instance of the UserService must mix-in the PasswordCodec and Notifier traits. Furthermore, the various password codecs and notifiers remain traits, which means that we can compose the functions contained within them (the registered(User): () and encode(String): String) into any other component in our system using Scala’s inheritance.
So, given the self type annotation means that we cannot just write new UserService:

new UserService(sessionFactory)              // doesn't compile
new UserService(sessionFactory) extends
  PlainPasswordCodec                         // doesn't compile
new UserService(sessionFactory) extends
  SmsNotifier                                // doesn't compile

new UserService(sessionFactory) extends
  PlainPasswordCodec with SmsNotifier        // OK
new UserService(sessionFactory) extends
  Sha1PasswordCodec with EmailNotifier       // OK

So, it’s looking good. I have more reusable components (because they are traits, so they can be mixed-in further) and I have expressed the composition dependency of the UserService. But we’re in the Spring application, remember? Now can I construct the UserService bean? Spring Scala to the rescue!

<?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:scala="http://www.springframework.org/schema/scala"
  xsi:schemaLocation="...">

  <context:load-time-weaver aspectj-weaving="on" />
  <context:component-scan base-package="org.cakesolutions.scala.services"/>

  <scala:bean id="userService" class="UserService">
    <scala:constructor-arg ref="sessionFactory"/>
    <scala:with trait="Sha1PasswordCodec"
                   if="#{environment['profile'] == 'live'}"/>
    <scala:with trait="PlainPassowordCodec"
                   if="#{environment['profile'] != 'live'}"/>
    <scala:with trait="EmailNotifier" />
  </scala:bean>

</beans>

Excellent! Not only can I mixin the required components, the Spring Scala namespace also gives me the control over when the dependencies are mixed-in. In the example above, the ShaPasswordCodec is mixed in only when the SPEL expression environment['profile'] == 'live' is true (presumably, this will be on the live environment). So, with the Spring Scala namespace, you can keep using Scala’s mixin inheritance, consider isolating the functionality you need in traits, thus giving you the opportunity to compose them into new components.

This entry was posted in Jan's Blog and tagged , , , . Bookmark the permalink.

10 Responses to Spring Framework and the Cake pattern

  1. Great stuff! Is there any way to get the code for the library and the example?

  2. Jan Machacek says:

    It is all on Github (https://github.com/janm399) and I’ll upload the PDF version of the slides here tomorrow, too. (I just need to tidy up the Github repository a bit before the talk.) Watch this space.

  3. Hi Jan,

    great – which project is the one I should be looking at?

    Thanks,
    Eberhard

  4. Jan Machacek says:

    D’oh!–it’s the scala-kickstart project. As I said, there’ll be a more thorough write-up about it tomorrow.

    Jan

  5. I didn’t quite get the thrust of this until I looked at the code, perhaps being slightly distracted by the AspectJ weaving being present. I initially thought: “Why not just use AspectJ mixins if you’re going to be running the AJ weaver?”

    Clearly I’m still in “Java-mode” too much, but now I see.

    The challenge with Spring XML config is that it has the drawbacks of many a dynamic language, in that it will compile, but then fail at runtime. I like Guice and Spring JavaConfig for this reason.

    Why not stick with the Cake Pattern for the example you’ve given (for the scala side) and then use @Bean annotated methods to expose the scala services to the spring container?

  6. Pingback: 2012? 2? 9? it ???? |

  7. Jan Machacek says:

    You’re absolutely right with the @Bean annotation; I didn’t want to give everything away before my talk. Check out the latest post, the slides and source code.

    Jan

  8. Pingback: Spring and Scala (Scala User Group London talk) | Cake Solutions Team Blog

  9. Tim Stearn says:

    I’m very interested to learn where I can find an implementation of the scala specific Spring config tags shown above.

  10. Jan Machacek says:

    Ah, we’re cooking up something in the Spring Framework–that’s all I can tell you for now, but I think we’ll be ready after the summer. In the meantime, you can use Spring’s JavaConfig to get bake your Spring cake beans (that is beans with functional dependencies expressed through the self-type annotations in Scala).

    I hope this helps,
    Jan

Leave a Reply