Spring-Loaded
got <beans>?
nerdbooks.com
All | General | Java | XDoclet | Programming | Spring | Development

20060207 Tuesday February 07, 2006

Spring in Academia

I very recently found out that Colin County Community College (a community college based in Plano, TX) is offering a continuing education course in Spring (the framework, not the season).

This is pretty cool for 2 reasons: (1) It's neat to see that Spring has gained enough attention that there's a demand for classes for it in colleges (even if it is a CE course). (2) I'll be teaching the course.

The class will be four 3-hour sessions on four Saturdays, starting with this Saturday (2/11). There's still a little room in the course, so if you're in the Plano area and are interested, hurry up and register for the course.

(2006-02-07 07:34:35.0) Permalink

20060124 Tuesday January 24, 2006

Moving on...

You may have noticed that I've not posted much on my blog lately (until tonight). And the astute reader may notice that my list of employers (on the right side) has changed to reflect a new employer...which, in part, explains why I've been too busy to update my blog.

For quite awhile, I've been growing increasingly frustrated and disheartened with my job at Michaels Stores. In short, despite my team's successes there was a move afoot to stifle our agile ways in favor of more rigid software development. I fought it for a long time, but I finally became jaded and decided it wasn't worth the frustration. I began looking for new work.

In my search, I talked to several great companies, including (no names mentioned)...

  • A well-known technology company who is best known for their application server.
  • A well-known consulting company who is best known for their very popular open-source framework.
  • A small educational software company that is only 10 minutes from my house.

I also considered going into independent consulting and at The Spring Experience, several people handed me their business cards asking if I'd be interested in joining their company. All of these appealed to me but...

In the end, it was my No-Fluff/Just-Stuff colleague and friend Glenn Vanderburg who got me in the door at Countrywide Financial. The drive to work is a bit long, but the team I'm on is great. The ironic thing is that I'm on a team at Countrywide that is revolutionizing software development within the company--I'm on a team that has management backing to do what I failed to pull off at Michaels.

I'm excited to be there. I am met with new challenges in this job, but they're the good kind of challenges...the kind I can learn and grow from.

(2006-01-24 23:21:39.0) Permalink

"Books" will appreciate it...

Last week I had the opportunity to visit Nerdbooks in Richardson, TX. I was there to present at the Spring Dallas User Group, but I got there early enough to browse their selection and had the pleasure of meeting Dave (the owner) and "Books" (the store dog).

Actually, Books took me by surprise. I'm no stranger to dogs (I have 4 of them myself), but it was a bit peculiar to see a dog in a bookstore. Nonetheless, Books is a very friendly dog and it was pretty cool that he gets to hang out at Nerdbooks.

You may have noticed that I've swapped out my "The Spring Experience" banner in the header of this blog with a banner for Nerdbooks. I don't often promote specific businesses or products, but I make an exception for a business that I really like. Since TSE was over awhile back, I decided to offer the space to Nerdbooks...just because they have such a cool bookstore. They have an AWESOME selection and fantastic prices on virtually every computer-related book in print.

I invite you to check out Nerdbooks.com. Or if you're in the Dallas area, make a visit to the store in Richardson.

(2006-01-24 23:04:48.0) Permalink Comments [1]

Example Code From Spring Dallas User Group

Last week I presented some basic Spring DI and AOP stuff at the Spring Dallas User Group. It was a ton of fun and I was pleasantly surprised to see more than 50 people show up. I'm hoping that this group does really well. It's great to see the Spring community expand in Dallas and I'm glad that Erik and Andy invited me to kick things off.

For those of you who were there (or just for the curious), I've just zipped up the code that I wrote during the presentation and have placed it here. I zipped up the code in the last state that it was in when the presentation ended, so any of the stuff that happened along the way is no longer available.

To make it work, you'll need the Spring 2.0 spring.jar file in your classpath along with commons-logging.jar. And because I'm using AspectJ pointcut expressions, you'll also need aspectjrt.jar and aspectjweaver.jar. All of these JARs are available in the Spring 2.0-M1 distribution (with dependencies).

(2006-01-24 22:52:52.0) Permalink

20051211 Sunday December 11, 2005

TSE: Wrap-up

I arrived in Dallas late last night sleepy and hungry, so I took care of both needs before waking up this morning to write my last thoughts on TSE.

On the final day of TSE, I attended Colin Sampaleanu's "Spring and EJB" talk. It was a very very good talk. The bulk of the talk compared the capabilities of Spring with EJB 3. The verdict: Well Colin said what I've been saying for awhile now--that is, EJB 3 is certainly a step in the right direction, but it still doesn't match up with the capabilities of Spring.

On the plus side, Colin showed how Spring 2.0 will provide support for the Java Persistence API (JPA...or what some call EJB 3 persistence). Specifically, there will be a LocalEntityManagerFactoryBean and a JpaDaoSupport class, which provides JPA support similar to that of LocalSessionFactoryBean and HibernateDaoSupport for Hibernate (and other similar support for other persistence mechanisms).

The last part of Colin's talk focused on the support Spring has for integrating with EJB 2.x

I was planning on going to either Ben Alex's "Advanced Acegi" talk or possibly Justin Gehtland's "Spring and AJAX" talk, but I ended up talking with Rick Hightower in the hallway and decided to not attend either. Instead I went up to help Raymie pack and get ready to meet SuperShuttle for our ride to the airport.

While waiting for SuperShuttle to show up, a large portion of the Spring team (Rod, Juergen, Colin, Thomas, and Rob) walked by. I stopped Rob to ask him about something I noticed missing in the Spring 2.0 JAR he had given me. Rob and Rod ended up hanging out with us and chatting for awhile. Maisy (my 1-year old daughter) was particular taken by Rod and was talking with him (her 1 year-old vocabulary is limited, but I assume that it was about the shortcomings of anemic domain models and how this will be addressed in Spring 2.0).

In the final analysis: I have found that it is really hard to fully enjoy a conference when you're a speaker, because you are too busy worrying about presenting your own sessions. That said, TSE 2005 was an awesome opportunity. The big news that Rod mentioned during his Friday night keynote was that we'd be doing this again next year. I can't wait for TSE 2006.

(2005-12-11 09:42:15.0) Permalink Comments [1]

20051209 Friday December 09, 2005

TSE Day 3

Day 3 of The Spring Experience is now over and I'm officially done being a speaker for the week.

I started the day in Rod Johnson's "Testing with Spring" talk. It was a really good talk. And Rod emphasized what I've been saying all along: Spring shouldn't be part of unit-testing. By writing your code as dependency-injected POJOs, you enable them to be tested more easily, but Spring itself shouldn't be involved in unit-testing. But there are several Spring-provided mock implementations that make unit-testing a bit easier. he also talked about the role of other types of testing. But, to be honest, I was only paying half-attention, because I was double-checking my "Service-Oriented Spring" examples to be sure that they'd be ready.

In the 2nd session of the day, I gave my "Service-Oriented Spring" presentation. I think it went rather well. As some of you may recall, it was a disaster when I gave the same presentation in Austin earlier this year, but this time went a lot more smoothly. Of course, the session evals that I pick up from Jay tomorrow will tell me if I'm right about it going well.

After lunch I sat on the expert panel. I enjoy the opportunity to sit on these panels, but more often than not the crowd asks questions that I have no insight into. Many of the questions centered around future plans for Spring, about which I (not being a member of the Spring team) have nothing to offer. So I sat mostly silent on the panel. I've been asked plenty of great questions in the hallway...where were those questions when I'm on the panel?

After the expert panel, I was exhausted, so I came back to my room to rest before the last session of the day.

During the last session, I presented my "A Few of my Favorite Frameworks" talk. This is the first time I've done this presentation, so I wasn't sure how it'd go. I think it went rather well. Again, the evals will tell the final story.

After dinner Rod Johnson presented another keynote and was joined by Adrian Colyer. Together they stressed the importance of AOP in a POJO-based platform. In short, Adrian has brought a lot of AOP value to the Spring project and there's going to be some really good AOP stuff in Spring 2.0.

Adrian also talked a bit about getting away from anemic domain objects (that is, domain objects that are nothing but data holders). The idea is that if domain objects were responsible for their own functions, the service layer could be made skinnier and the domain objects could be more OO. But the problem is that domain objects are typically instantiated and managed external to Spring (eg, Hibernate). So, how can Spring inject things like DAOs into domain objects if Spring isn't instantiating them? Well, in Spring 2.0, using AOP, you'll be able to declare that certain objects will injected with dependencies post-instantiation, regardless of how they are instantiated. This, when you really think about it, is some really cool stuff. I'm looking forward to trying this out.

Tomorrow I attend two of three sessions before heading back to the airport. Which sessions I actually attend will be a gametime decision. But I'm done with my own sessions, so I'm finally going to be able to take it easy and enjoy the rest of the conference.

(2005-12-09 21:58:46.0) Permalink Comments [0]

20051208 Thursday December 08, 2005

TSE Day 2 wrap-up

Day two of TSE is over...but I don't have much to report. I bowed out of most of the sessions today to take care of some personal stuff. The only session I attended after lunch was the one I had to go to--my portlet presentation.

I thought the presentation went okay. But I was a bit off and it was made worse by the fact that the wireless mic I was using was low on batteries and kept cutting out. Aside from that, I think it went okay.

For those of you attending that talk (or just interested), here's where you can get the example Rolodex portlet. Enjoy.

I'll be around for more of the conference tomorrow...and with that, more blogging.

(2005-12-08 23:02:32.0) Permalink Comments [0]

Spring saves a life (news from TSE)

I'm taking another break from the conference to test my example for my "Thinking inside the box" presentation later today. On the way back up to my room, I ran into Rick Hightower in the lobby. Rick informed me there's news being made on the beach just outside of our hotel.

Apparently, someone got into a bit of trouble out in the ocean and was drowning when a TSE attendee came to the rescue swimming out to pull the troubled swimmer to safety. From what I understand everybody's okay, but there were tons of police, paramedics, and news helicopters around the scene (although I've found nothing on the news about it yet).

My hat's off to the Spring'er who came out a hero today--Literally. As I mentioned in an earlier blog, I have a couple of extra "got <beans>?" hats. It's only a small token, but if I find out who the hero is, I'll give them a hat. I'll be asking around to find out who it is...of course, I'll be watching the news and talking to Jay to see if he knows anything.

(Let's keep this honest folks...I don't want everyone claiming to be a hero just to get a free hat. If that happens, then I'll need evidence.)

(2005-12-08 15:43:42.0) Permalink Comments [0]

TSE Day 2: Spring, Mule and ESB

It's day 2 here at The Spring Experience. I started the day by chatting with Chris Richardson, the author of the upcoming POJOs in Action. I was hoping to be able to read his book early and provide a quote for the back cover, but I've not received my e-copy yet and Chris says that it's going to the printers in the next day or two. So, while I can't say that POJOs in Action is a good book, I can say that Chris is a really nice guy and based on our discussion he seems to know what he's talking about. (There ya go, Chris...I told you I'd give you a "nice guy" quote!)

I also chatted briefly with some old friends: Rick Hightower, Stuart Halloway, and Justin Gehtland. It was good to meet up with them.

In the first session of the day, Justin gave his "Spring, Mule, and the ESB" talk. I must say, it was a very very very good presentation. Justin knows Mule very well. I learned a lot from that session. If anyone is planning on attending my "Service Oriented Spring" talk tomorrow, I hope you won't be disappointed after hearing Justin's talk. Justin went into a great deal more detail than I will with Mule. But hopefully there will be something of value for you in my talk.

I'm skipping out of the 2nd session to write this and to help my wife pack so that we can move to a more comfy room. (The room they gave us initially has a great ocean view, but sucks otherwise.)

More later...

(2005-12-08 11:32:16.0) Permalink Comments [0]

20051207 Wednesday December 07, 2005

Blogging from The Spring Experience (Day 1)

It's Wednesday night and the first day of The Spring Experience has concluded. Actually, it wasn't a full day...just a dinner and a keynote. But it was a keynote from Rod Johnson, so I guess that it wasn't just a keynote.

Rod's keynote is summarized as "where we've been and where we're going next". The big news is that Spring 1.3 has now been renamed to Spring 2.0. They (the Spring team) decided that Spring 1.3 was too much to simply be a point release. So, later this week Spring 2.0M1 will be released and they're targeting Spring 2.0 final for March 2006.

There are a lot of new features and conveniences appearing in Spring 2.0, most notable:

  • Simpler and custom XML configuration (similar to what XBean offers).
  • A lot of AOP enhancements thanks to Adrian Colyer's efforts. One thing that stuck out to me is the ability to use AspectJ-style aspects in Spring without going through the "ajc" compile step. Also the ability to define pointcuts using AspectJ pointcut syntax is really nice.
  • Spring WebFlow. We've all known that it was coming in Spring 1.3...but now it's going to be part of Spring 2.0. (I spoke with Keith Donald afterwards and he informs me that Spring 2.0M1 also marks the release of Spring WebFlow 1.0M1).

Rod turned the podium over several times during his keynote to other Spring team members to demo their stuff. One of the demos was from Alef Arendsen where it was demonstrated that Spring 2.0 will be fully backward compatible with Spring 1.2.x. In other words, you won't have to change anything to start using Spring 2.0. But, Spring 2.0 offers some coolness that may tempt you to change some stuff anyway to take advantage of the new features.

Afterwards I stayed around for a bit and chatted with Rod, Colin Sampaleanu, Keith Donald, Rob Harrop, Adrian Colyer, and others. I also ran into Thomas Risberg in the hallway before the keynote and I saw Rick Hightower from across the room and intended to say "hi", but he disappeared before I got a chance.

I also chatted briefly with Matt Raible before Rod's keynote. As soon as Rod started talking Matt told us that he was going to have to blog about this, so he sat down to start blogging about Rod's keynote. Matt always scoops me on the good stories, but as of this moment, he hasn't added anything to his blog about TSE, so it looks like I've beat him to this one. Sorry Matt. I'm sure your blog about Rod's keynote will be more detailed...but mine was first! :-)

Tomorrow I'll try to blog again about the sessions I attend...stay tuned.

BTW, Jay tells me that some people are already asking where they can get one of those "got <beans>?" hats that I was sporting tonight. If you want one, there are two ways to get them. First, I gave 3 of them to Jay and he'll be giving them away as door prizes this week. But if you don't win or if you're not here at TSE, then you can e-mail me (beanhat _at_ habuma.com) to find out how to get your own "got <beans>?" hat.

(2005-12-07 22:55:39.0) Permalink Comments [7]

20051206 Tuesday December 06, 2005

Spring and annotation-driven injection

It's been awhile since I've blogged, I know. The last couple of months have kept me quite busy...

  • Preparing for the LoneStar Software Symposium in Dallas
  • My wife having surgery (which prevented me from attending LSSS in Dallas)
  • Preparing for Christmas
  • Preparing for The Spring Experience
  • Preparing for my daughter's first birthday
  • Looking for a new job

It's been quite hectic, to say the least.

But before I board a plane for Fort Lauderdale to speak at The Spring Experience, I wanted to throw a little something out here to make up for my silence.

Norman and I spend a lot of time on e-mail and chat discussing the ins and outs of Spring vs. EJB 3. Norm, being a JBoss'er, comes at this from an EJB 3/JBoss perspective, while I bring an Spring view to the table.

Recently, the topic turned to why Spring must be configured via XML and why dependency injection can't be done using annotations. Actually, Spring doesn't have to be configured with XML. XML just happens to be the weapon of choice for Spring'ers. In fact, I've been thinking of writing a YAML if for no other reason than to prove that it can be done.

But since the topic came up, why not try a Java 5 annotation approach?

Regardless of your philosophical views on whether injection should or should not be done using annotations, I thought it would at least be an interesting exercise to add annotation-injection to Spring. (Truthfully, I'm not sure that I'm in favor of using annotation-injection, but with enough people talking about it, I thought it couldn't hurt to try it out and see what comes of it.)

What follows is a work in progress annotation-injection Spring container. Let me stress the phrase "work in progress", as there's plenty of room for improvement.

Defining the annotations

In my simple annotation-driven Spring container, I'm going to use three annotations:

  • @Bean : Marks a class as being a Spring-managed bean. Roughly equivalent to the <bean> XML tag.
  • @Ref : Tags a property to be injected with another bean. Roughly equivalent to the <ref> XML tag.
  • @Value : Tags a property to be injected with a specific value. Roughly equivalent to the <value> XML tag.

The code for the annotations are as follows:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Bean {
  String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Ref {
  String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Ref {
  String name();
}

The annotations themselves are fairly straight-forward. Where they get interesting is in how they're interpreted by a Spring container.

Defining an annotation container

Processing the Spring annotations should follow a simple pattern:

  • For each class that has a @Bean annotation do:
    • Create a BeanDefinition
    • For each property that has a @Ref annotation do:
      • Add a RuntimeBeanReference to the BeanDefinition's MutablePropertyValues.
    • For each property that has a @Ref annotation do:
      • Set the specific value to the BeanDefinition's MutablePropertyValues.
    • Register the BeanDefinition to the container.
  • Refresh the container (to resolve any unresolved references).

My own implementation of AnnotationApplicationContext is listed here:

import ../../page/java.lang.reflect.Field.css;
import ../../page/java.util.HashMap.css;
import ../../page/java.util.Map.css;
import ../../page/org.springframework.beans.MutablePropertyValues.css;
import ../../page/org.springframework.beans.factory.BeanDefinitionStoreException.css;
import ../../page/org.springframework.beans.factory.config.BeanDefinition.css;
import ../../page/org.springframework.beans.factory.config.RuntimeBeanReference.css;
import ../../page/org.springframework.beans.factory.support.RootBeanDefinition.css;
import org.springframework.context.support.GenericApplicationContext;
public class AnnotationApplicationContext extends GenericApplicationContext {  
  public AnnotationApplicationContext(String[] beanNames) {
    registerBeansByName(beanNames);
    refresh();
  }
  private void registerBeansByName(String[] beanNames) {
    for(int i=0; i < beanNames.length; i++) {
      registerBeanByName(beanNames[i]);
    }
  }
  private void registerBeanByName(String beanName) {
    try {
      registerBean(Class.forName(beanName));
    } catch (ClassNotFoundException e) {
      throw new BeanDefinitionStoreException("Error registering bean with class '"+beanName+"'");
    }
  }
  private void registerBean(Class clazz) {
      if(clazz.isAnnotationPresent(Bean.class)) {
        Field[] fields = clazz.getDeclaredFields();
        Map refMap = new HashMap();
        for(int i=0; i < fields.length; i++) {
          Field field = fields[i];
          if(field.isAnnotationPresent(Ref.class)) {
            Ref ref = (Ref) field.getAnnotation(Ref.class);
            RuntimeBeanReference beanRef = new RuntimeBeanReference(ref.name());
            refMap.put(field.getName(), beanRef);
          } else if (field.isAnnotationPresent(Value.class)) {
            Value value = (Value) field.getAnnotation(Value.class);
            refMap.put(field.getName(), value.value());                      
          }
        }
        Bean annotation = (Bean) clazz.getAnnotation(Bean.class);
        MutablePropertyValues mpvs = new MutablePropertyValues(refMap);
        BeanDefinition beanDef = new RootBeanDefinition(clazz, mpvs, true);
        registerBeanDefinition(annotation.name(), beanDef);
      }
  }
}

The most interesting part of AnnotationApplicationContext is in the registerBean() method. Here, I inspect a given class for the @Bean annotation and, if found, process any @Ref or @Value annotations on its properties. In the end, I call the registerBeanDefinition() method to register the bean with the container.

The unfortunate part of AnnotationApplicationContext is that I must specify all annotated beans with their FQCN at constructor time. I'd rather provide a list of packages to inspect for @Bean-annotated classes, but from what I can tell, it's really hard to get a list of classes given a specific package name. (If someone knows a trick for this, let me know.) So I must explicitly tell the container which classes might have Spring annotations in them.

Spring annotations in action

Now let's look at a few Spring-annotated beans. First, here's a DvdPlayerImpl class:

@Bean(name="player")
public class DvdPlayerImpl implements DvdPlayer {
  public DvdPlayerImpl() {}
  public void play() {
      if(dvd != null) {
        System.out.println("NOW PLAYING:  " + dvd.getTitle());
        dvd.play();
      } else {
        System.err.println("No DVD loaded");
      }
  }
  @Ref(name="movie")
  private Dvd dvd;
  public void setDvd(Dvd dvd) { this.dvd = dvd; }
}

Here the bean has been named "player" and thus will be registered into the Spring application context with that name. It also has a "dvd" property that I use the @Ref annotation to inject it with a bean named "movie".

As for the "movie" bean, here's the code for SuddenImpact:

@Bean(name="movie")
public class SuddenImpact implements Dvd {
  public SuddenImpact() {}
  public void play() {
      System.out.println("Go ahead...make my day.");
  }
  @Value("Sudden Impact")
  private String title;
  public void setTitle(String title) { this.title = title; }
  public String getTitle() { return title; }
}

As before, the @Bean annotation is used to declare this as a Spring-managed bean. But instead of using @Ref to inject a bean reference, I'm using @Value to inject a hard-coded value into the "title" property.

To try these out, you simply instantiate AnnotationApplicationContext, giving it the names of the annotated classes, then use the beans contained therein:

  public static void main(String[] args) throws Exception {
    String[] annotatedClasses = new String[] {
            "com.habuma.movies.DvdPlayerImpl",
            "com.habuma.movies.SuddenImpact"
    };
    ApplicationContext ctx = new AnnotationApplicationContext(annotatedClasses);
    DvdPlayer player = (DvdPlayer) ctx.getBean("player");
    player.play();
  }

When this main() method is executed, the output is:

NOW PLAYING: Sudden Impact
Go ahead...make my day.

As I said, AnnotationApplicationContext is a work in progress. If you have any suggestions or would like to build more functionality into it, then please feel free. Keep me informed of your progress.

Why I think this is a bad idea

As I stated before, this was a fun exercise, but I'm not so sure if it's a good idea to use annotations for dependency injection.

I think annotations should be used to provide metadata that describes objects at the class-level, not at the instance-level. Consider EJB 3/Hibernate-persistence annotations. These annotations describe persistence at a class-level. An Employee class may be annotated with instructions on how all employees should be persisted, but the annotations don't describe how any particular instance of Employee should be persisted. This, in my opinion, is a proper use of annotations.

Dependency injection, on the other hand, is an instance-level activity. Using annotations to describe how a bean and its properties should be registered in a dependency-injection container (such as Spring) makes it hard to have more than one instance of that class (each configured differently) in the same container. The annotations effectively say that all instances of DvdPlayerImpl should be registered in the container with the name "player" and their "dvd" property should always be injected with a bean whose name is "movie". (Of course, with all instances being registered with the same name, only one instance will be registered.) This, again in my opinion, is a misuse of annotations.

So, even though I've shown you how to add annotation-driven dependency-injection to Spring, I'm convinced that you should probably never use it. But I wanted to throw this out here anyway to spark some discussion.

It's your turn: Tell me why annotation-driven injection is a good idea. Or tell me why it's a bad idea. I'm eager to hear your thoughts. Or maybe you have some ideas on how to improve AnnotationApplicationContext. Regardless, leave a comment here and let's talk about it.

For those of you going to The Spring Experience, look for me and say "hi". I look forward to meeting you.

(2005-12-06 16:49:26.0) Permalink Comments [3]

20051103 Thursday November 03, 2005

No NFJS for me...

I was supposed to be speaking at NFJS this weekend in Dallas, but...

Unfortunately, my wife has been in the hospital for a few days. It's nothing too serious and she's doing a lot better, but she'll be off of her feet for a few days and she's going to need some help wrangling our 10.5 month old daughter. So, I had to tell Jay that I had to bow out.

Jay tells me that he's arranged for Keith Donald to fly in and fill in for me. I've never heard Keith speak, but I know that he knows his stuff. I'm actually a bit bummed that I can't be there because I'd love to hear Keith's presentations. (But if I was there then there'd be no reason for Keith to be there.)

I guess that I'll just have to wait until next month when both Keith and I are speaking at The Spring Experience.

(2005-11-03 20:21:35.0) Permalink Comments [7]

20051013 Thursday October 13, 2005

Spring Simplified with XBean

A complaint that I frequently hear about Spring is that the Spring XML configuration files can be somewhat verbose and unwieldy. It's true...while working with Spring XML files, you can easily get lost in a endless sea of <bean> and <property> tags.

As I see it, there are two problems with Spring's configuration XML:

  1. It's too verbose
  2. It's not expressive enough

The verbosity issue is self-explanatory. But Spring configuration files are also not very expressive in that the XML tags are non-descript <bean> and <property> tags. These tags, by themselves, do not tell you anything about the context of the objects that they define. To illustrate, consider the following standard Spring configuration XML:

<beans>
  <bean id="quest"
      class="com.springinaction.chapter01.knight.HolyGrailQuest"/>
  <bean id="knight"
      class="com.springinaction.chapter01.knight.KnightOfTheRoundTable">
    <property name="moniker">
      <value>Bedivere</value>
    </property>
    <property name="quest">
      <ref bean="quest"/>
    </property>
  </bean>
</beans>

Spring has no problem parsing this file. Everything Spring needs to know to configure a knight and a quest can be found among the XML. But for the human who reads and writes this XML, you'll need to do a bit of deciphering. The <bean> tag only tells you that you are dealing with a bean. If you want to know what kind of bean you're dealing with, you must look at the class attribute. To see how it's configured, you have to examine the <property> tag's name attribute and <value> and <ref> sub-elements.

Spring is still quite useful despite these problems. But wouldn't it be nice if something could be done to make the Spring configuration files simpler and more expressive?

Spring itself offers a couple of ways to shorten your configuration XML. Auto-wiring cuts down on the number of <property> tags in your configuration by allowing Spring to guess which beans should be wired into properties using hints based on the property's name or type. And, as of Spring 1.2, short-hand XML makes it possible to roll property values and references from XML sub-elements into attributes. For example, the XML above can be shortened a bit by applying both auto-wiring and short-hand XML:

<beans>
  <bean id="quest"
      class="com.springinaction.chapter01.knight.HolyGrailQuest"/>
  <bean id="knight"
      class="com.springinaction.chapter01.knight.KnightOfTheRoundTable"
      autowire="byName">
    <property name="moniker" value="Bedivere" />
  </bean>
</beans>

The XML is a bit shorter, but it's still not very expressive. If anything, auto-wiring has eliminated some of the clarity of what is being wired. There's nothing in this XML to explicitly tell us that the quest property of the "knight" bean is being wired.

Enter XBean

XBean is an extension of Spring that makes it possible to customize Spring's configuration XML to hit the sweet-spot where it is both terse and expressive. Simply put, XBean automagically maps XML elements and attributes to JavaBean classes and properties using reflection and simple conventions. When using XBean, you are able to extend Spring's XML configuration files with custom XML tags and attributes that describe the beans that you are configuring.

The first step in using XBean is to download it. XBean is in the process of evolving from the GBean project, so it's tricky to find the JAR file. I found it sitting in Codehaus's Maven repository at xbean-spring-1.0-SNAPSHOT.jar.

In this article, I'm going to show you how to apply XBean to the Knight example from chapter 1 of Spring in Action. For these examples, the minimum set of JAR files you'll need are:

  • spring.jar
  • commons-logging.jar
  • jaxrpc.jar
  • xbean-spring-1.0-SNAPSHOT.jar

With the exception of the XBean JAR, I found all of these JAR files in the distribution of Spring 1.2.5.

It should be noted that the use of XBean is still cutting edge stuff. The fact that I had to dig around in Codehaus' Maven repository to find a JAR should indicate that although it seems to work fine in these examples, mileage may vary from project to project. Use with caution.

UPDATE: James Strachan informs me that the official XBean website is up. No need to dig around in Codehaus' Maven repository! However, it is still a pre-1.0 snapshot release, so continue to exercise caution in using it.

Setting the stage

To get started, consider the KnightOfTheRoundTable class that we'll be working with:

package com.springinaction.chapter01.knight;
public class KnightOfTheRoundTable implements Knight {
  private String moniker;
  private Quest quest;
  public KnightOfTheRoundTable() {}
  public Object embarkOnQuest() throws QuestException {
    return quest.embark();
  }
  public void setQuest(Quest quest) {
    this.quest = quest;
  }
  public String getQuest() {
    return quest;
  }
  public void setMoniker(String moniker) {
    this.moniker = moniker;
  }
  public String getMoniker() {
    return moniker;
  }
}

If you're comparing this class with the same class from Spring in Action, you'll notice that I tweaked things a bit. First, I changed the class to be able to set both properties via a setter method (instead of by constructor). That's because when you're using XBean, setter-injection is the way to go.

But even more noticeable than that, the name property has been renamed to moniker. Aside from looking for a valid excuse to use the word "moniker", there is a more practical reason why I made this change. But, I'll save that explanation until a bit later.

Now take a look at the HolyGrailQuest class:

package com.springinaction.chapter01.knight;
public class HolyGrailQuest implements Quest {
  public HolyGrailQuest() {}
  public Object embark() throws GrailNotFoundException {
    // do whatever it means to embark on a quest
    System.out.println("Embarking on HolyGrailQuest");
    return new HolyGrail();
  }
}

There's nothing too remarkable about this class. In fact, it's virtually identical to the same class in Spring in Action. I have added a System.out.println() to prove that the embark() method is getting called, but other than that it's the same class.

Customizing Spring XML

To configure these two classes as beans in Spring, you could use either of the XML configurations listed earlier in this article. But using XBean, things get simplified a little:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans xmlns:k="java://com.springinaction.chapter01.knight">
  <k:HolyGrailQuest id="quest" />
  <k:KnightOfTheRoundTable id="knight" moniker="Bedivere">
    <property name="quest" ref="quest" />
  </k:KnightOfTheRoundTable>
</beans>

Notice that instead of using <bean> tags, I'm able to use <k:HolyGrailQuest> and <KnightOfTheRoundTable> tags. These tags map directly to the HolyGrailQuest and KnightOfTheRoundTable classes. These classes are found by way of the XML namespace which is associated with the Java package that the bean classes are in.

Also notice that instead of setting the "moniker" property via a <property> tag, we're setting it as an XML attribute of the <KnightOfTheRoundTable> tag. This is why I had to change the property name to "moniker" instead of "name". In Spring, the "name" attribute already has a meaning (similar to that of the "id" attribute) and XBean won't let me set a property called "name".

At this point, the XML elements have a bit more meaning. It's clear from the tags themselves that we're configuring a HolyGrailQuest and a KnightOfTheRoundTable. To be able to use this XML, you'll need to use an XBean-specific application context. XBean comes with four application contexts:

  • org.xbean.spring.context.ClassPathXmlApplicationContext
  • org.xbean.spring.context.FileSystemXmlApplicationContext
  • org.xbean.spring.context.ResourceXmlApplicationContext
  • org.xbean.spring.context.XmlWebApplicationContext

Each of these application contexts mimic the corresponding application context of the same name in the Spring JAR (that is, except for ResourceXmlApplicationContext which has no twin in Spring). You use an XBean application context just as you would its corresponding Spring application context. For example:

  ApplicationContext ctx = new
      FileSystemXmlApplicationContext("knight.xml");
  KnightOfTheRoundTable knight = 
      (KnightOfTheRoundTable) ctx.getBean("knight");
  System.out.println("Knight's name:  " + knight.getMoniker());
  knight.embarkOnQuest();

The XBean version of the Spring configuration above is more expressive than the plain-vanilla Spring configuration, but there's even more that can be done. First, KnightOfTheRoundTable and HolyGrailQuest are lengthy names for XML tags. Let's see how to shorten them.

In the example above, the XML namespace was a "java://" URI and XBean assumed some simple conventions for the XML tags and attributes. But if the namespace is an "http://" URI, it can be used to lookup a properties file that guides XBean to alias class names and property names into custom XML tags and attributes.

For example, if the XML namespace is changed to "http://springinaction.com/schemas/knight", XBean will look in the classpath for a property file named "knight" in META-INF/services/org/xbean/spring/http/springinaction.com/schemas. I used the following "knight" property file to change the <KnightOfTheRoundTable> and <HolyGrailQuest> tags to <knight> and <quest> tags:

# The default package
package = com.springinaction.chapter01.knight
knight = com.springinaction.chapter01.knight.KnightOfTheRoundTable
quest = com.springinaction.chapter01.knight.HolyGrailQuest

After saving the "knight" properties file in META-INF/services/org/xbean/spring/http/springinaction.com/schemas, I am able to change my Spring configuration XML to look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans xmlns:k="http://springinaction.com/schemas/knight">
  <k:quest id="quest" />
  <k:knight id="knight" moniker="Bedivere">
    <property name="quest" ref="quest" />
  </k:knight>
</beans>

That's a little bit cleaner. The only argument against aliasing class and property names is that the Spring XML file no longer is clear about exactly which classes and properties are being manipulated. In order to get a clear picture of the real classes and properties involved, you must read the configuration file alongside the properties file. If that's a problem for you, then I recommend that you not create alias tags.

We're making a lot of progress, but there's still that Spring-esque <property> tag used to wire the "quest" bean into the "quest" property of the "knight" bean. How can we make that line more expressive?

It just so happens that you can use XML sub-elements to wire in objects just as you might use XML attributes to configure String or other native properties. So, instead of <property name="quest"> we can use a <quest> tag:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans xmlns:k="http://springinaction.com/schemas/knight">
  <k:knight id="knight" moniker="Bedivere">
    <quest><k:quest/></quest>
  </k:knight>
</beans>

Now the XML is very terse and a lot more expressive. There's one more thing we can do, though. Let's move the XML namespace declaration to the <knight> tag, so that we can eliminate the XML namespace prefix:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <knight id="knight" moniker="Bedivere"
      xmlns="http://springinaction.com/schemas/knight">
    <quest><quest/></quest>
  </knight>
</beans>

This Spring configuration XML is much better. Using XBeans, we've dramatically reduced the verbosity and made each tag name mean something.

The only questionable aspect of this last version of the XML is that the <quest> tag has a double-meaning. The outer <quest> tag is setting the "property" of the "knight" bean, while the inner <quest> is instantiating a HolyGrailQuestion object. I personally don't consider this a huge issue, but if it bugs you, then there are a couple of options.

The first and most obvious option is to keep the XML namespace at the root level and continue using the namespace prefixes. That's not too bad, but I find that the prefixes hinder the readability of the XML. Another option is to edit the "knight" properties file and choose a different alias for the HolyGrailQuest class other than "quest". That's easy enough to do, but let me suggest a third option.

Just as we were able to apply aliases to our bean classes using the "knight" properties file, we can also apply aliases to the bean properties. For example, to alias the knight's quest property as "myQuest", simply add the following line to the "knight" properties file:

knight.myQuest=quest

Here we're effectively creating a new XML tag called <myQuest> that will be used to inject values into the knight's quest property. Thus, the XML can be changed (one more time) to the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <knight id="knight" moniker="Bedivere"
      xmlns="http://springinaction.com/schemas/knight">
    <myQuest><quest/></myQuest>
  </knight>
</beans>

Note that although we're aliasing the quest property here to create a new XML tag, the same technique can also be used to alias an XML attribute.

Where we've come from

In weight-loss advertisements, it's customary to see a before and after picture so that you can appreciate how much progress has been made. The transformation we've taken Spring's XML through is not unlike some form of weight-loss--we've taken a bulky and boring XML document and made it lean and mean. So, I thought it'd be good to see a before and after picture of the knight configuration file side-by-side:

Before (Standard Spring)After (Using XBean)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <bean id="quest" class=
      "com.springinaction.chapter01.knight.HolyGrailQuest"/>
  <bean id="knight" class=
      "com.springinaction.chapter01.knight.KnightOfTheRoundTable">
    <property name="moniker">
      <value>Bedivere</value>
    </property>
    <property name="quest">
      <ref bean="quest"/>
    </property>
  </bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <knight id="knight" moniker="Bedivere"
      xmlns="http://springinaction.com/schemas/knight">
    <myQuest><quest/></myQuest>
  </knight>
</beans>

(Sorry about the small font size...it was necessary in order to squeeze the examples in side by side.)

Be aware that these two XML files are effectively identical in purpose. They both instantiate HolyGrailQuest and KnightOfTheRoundTable objects and then wire the "quest" bean into the knight's quest property. But the difference is obvious: The XBean version is much cleaner, shorter, and easier to read. The knight example was brief to begin with, but using XBean, it became much simpler and clearer. As an exercise to the reader, imagine how XBean could be used to simplify the configuration of a much larger Spring application.

As an example of how XBean is being used, consider ServiceMix. The current release of ServiceMix (v1.0.1) comes with a modified version of Spring to simplify configuration of the ESB from a complex <bean>/<property> approach to a more terse and expressive <container>/<components>/<component> approach. Unfortunately, however, because ServiceMix is using a modified (i.e., "unofficial") release of Spring, you are unable to use a newer release of Spring with ServiceMix. This will change in a future release of ServiceMix, however, as they replace their custom Spring code with XBean for configuration. Once ServiceMix uses XBean, you'll be free to choose any official Spring release for your project.

For your convenience, I've placed the source code from this article, along with all necessary JAR files for download here. The included Ant build file will compile and run the example using the final version of the Spring/XBean XML file. To swap out different versions, edit the com.springinaction.chapter01.knight.KnightApp class to load its context from one of the other XML files.

(2005-10-13 11:44:06.0) Permalink Comments [28]

20051007 Friday October 07, 2005

Why should I use XDoclet 2?

Somehow, when I wasn't looking, XDoclet 2 was released. Apparently it was released some time ago, but it didn't cross my eyes until today.

But, I'm not so sure that I care.

I have been a big fan of XDoclet...so much so that I wrote a book about it. But I find myself using XDoclet less and less lately and am wondering why I should bother with XDoclet 2.

First off, I am no longer troubling myself with EJB 2.x, the primary motivator for XDoclet. If and when I choose to use EJB 3, I'll be using annotations, so XDoclet doesn't apply.

I've also been known to use XDoclet to generate TLD files, web.xml files, and struts-action.xml files. I rarely write my own JSP tags or standalone servlets, and I've not done anything in Struts in well over a year.

At the moment, the only thing I'm still using XDoclet for is to generate Hibernate mapping files. I'm starting to look into using Hibernate 3 annotations, but it'll be awhile before I'm able to migrate all of my production apps to Java 5. So, I still have a "legacy" use of XDoclet and probably will for quite some time.

I suppose that I could switch to XDoclet 2 to generate those mapping files. But what would it buy me? XDoclet 1 still does a great job of generating Hibernate mapping files. What will XDoclet 2 give me that XDoclet 1 doesn't already do? Sure, XDoclet 2 is much better designed than XDoclet 1. But that's "under the covers" stuff. As a user of XDoclet, what's my motivation to switch to XDoclet 2?

I'm not dismissing XDoclet as being useless. Just as I have a legacy need for XDoclet for generating Hibernate mapping files, you may have your own reasons to continue using XDoclet. My question centers around XDoclet 2.

I'm sincerely asking: Can anyone tell me why I should go to the trouble of switching to XDoclet 2?

(2005-10-07 13:56:08.0) Permalink Comments [7]

20050825 Thursday August 25, 2005

Ruby, meet Spring

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.

(2005-08-25 16:29:18.0) Permalink Comments [5]


my books
other stuff i've written
places i've spoken
where i've worked
archives
links
referers