Ruby, meet Spring - No Fluff Just Stuff

Ruby, meet Spring

Posted by: Craig Walls on August 25, 2005

Throughout history, man has repeatedly attempted to join two or more simple elements to create a new and more astonishing item from the combination. For example, consider metal alloys, mules and hinnies, Reeses peanut butter cups, and the act of putting the lime in the coconut.

Today I practice my own brand of amalgamation by introducing Spring to Ruby. What follows are the results of a 10-minute experiment that I performed during lunch today...

Let's say that you have a simple POJO named Lime. Lime is defined as follows:

package com.habuma.jruby;

public class Lime {
    public Lime() {}
    
    public void drink() {
        System.out.println("Call the doctor, wake him up!");
    }
 }

And let's also say that you've configured Lime in a Spring context like so:

<beans>
    <bean id="lime" class="com.habuma.jruby.Lime"/>
</beans>

So far, so good. Now, let's suppose that for some reason (be it practical or sick and twisted) you need to use Lime in your Ruby code. Using JRuby I could simply import Lime into my Ruby script and run with it:

require 'java'
include_class 'com.habuma.jruby.Lime'

class Coconut
  def initialize(l)
    puts "You put the lime in the coconut"
    @lime = l
  end

  def drinkThemBothUp
    puts "Drink them both up"
    @lime.drink
  end
end


lime = Lime.new

coconut = Coconut.new lime

coconut.drinkThemBothUp

The first two lines are key as they indicate that I'll be using Java objects and specifically that I'll be using the Lime class. With Lime imported, I can now use it as if it were a Ruby class. This will work and the only real gotcha is that I must run it through JRuby instead of the standard Ruby interpreter.

That's really nice, but I'm still instantiating Lime directly. It's not too much of a mental stretch to realize that if Lime were much more complex that I may want to configure it in a Spring context and use dependency injection to wire it up with other objects. So how can I (for reasons either practical or perverse) retrieve my Lime object from Spring?

It stands to reason that if I can use Lime in my Ruby script that I can also use Spring's FileSystemXmlApplicationContext (or any of Spring's other container implementations) in much the same way. And if I can access a Spring application context in Ruby, then I can also access beans configured in that application context and use them as if they were Ruby objects:

require 'java'
include_class(
'org.springframework.context.support.FileSystemXmlApplicationContext'
)

appContext = FileSystemXmlApplicationContext.new "lime.xml"

class Coconut
  def initialize(l)
    puts "You put the lime in the coconut"
    @lime = l
  end

  def drinkThemBothUp
    puts "Drink them both up"
    @lime.drink
  end
end

lime = appContext.getBean "lime"

coconut = Coconut.new lime

coconut.drinkThemBothUp

Now the lime object in my Ruby script is retrieved from a Spring application context instead of being instantiated directly. And Ruby's duck-typing kept me from having to cast the bean to a Lime before I can use it.

I'm certain that I'm going to get comments from both the Ruby camp and the Spring camp saying that this is an abomination and questioning the real worth of this technique. Honestly, this was just a quick lunch-time experiment where I was only asking a question of "Can it be done?" I think I've answered that question with a resounding "Yes". But I really haven't explored the question of "What practical purpose does this have?"

However, before you completely dismiss this article, consider this: I often hear arguments against Ruby and Rails that say that Ruby applications can't make use of resources and APIs that are readily available to Java applications. For instance, what if a Rails application needs access to a legacy EJB?

I'm not yet sure if it's even possible to run Rails within JRuby...that's an experiment for another lunch hour. But if it can be done, then a Rails application can use Spring's mechanism for wiring EJBs to easily gain access to an EJB.

Furthermore, any Ruby can take advantage of the wealth of Java libraries that are available to do their bidding. And when configured as <bean>s in a Spring context, Spring's dependency injection and AOP support can be applied as needed.

What do you think? Can you think of a practical use of this technique? If so, leave me a comment...I'd love to hear about it.

Craig Walls

About Craig Walls

Craig Walls is a Principal Engineer, Java Champion, Alexa Champion, and the author of Spring AI in Action, Spring in Action, and Build Talking Apps. He's a zealous promoter of the Spring Framework, speaking frequently at local user groups and conferences and writing about Spring. When he's not slinging code, Craig is planning his next trip to Disney World or Disneyland and spending as much time as he can with his wife, two daughters, 1 bird and 2 dogs.

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »