Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Sunday, March 26, 2006

New version of tapestry-spring

I've built out a new and improved version of tapestry-spring yesterday and today. This is a tiny module that properly initializes Tapestry to allow Spring beans to be injected into Tapestry pages.

This one works first off! I now run an integration test to prove this; it starts up a Jetty instance and injects a Spring bean into a Tapestry page.

More importantly, this version addresses the prototype issue. Using the standard @InjectObject annotation messes up when the bean being injected is not a singleton. Non-singleton Spring beans, aka prototypes, must be re-acquired from the BeanFactory in order to get the correct, new version.

There's now an @InjectSpring annotation that does that; reading the property will, beneath the covers, always go back to the BeanFactory to obtain a fresh copy. No caching at any layer, no problems.

I just realized that I forgot to update the documentation; that will come shortly.

I also bumped the version number up to 0.1.2 to celebrate the fact that this code works. But it is still alpha quality!

I did some trickery (I believe) so that the non-annotation classes are compiled for JDK 1.3, and the annotation classes are compiled for JDK 1.5. Took a bit of a struggle with Maven, but it works. If you aren't using annotations, you need to use a bit of XML:

<inject property="myProperty" type="spring" object="mySpringBean"/>


Matt Raible said...

Why isn't it possible to keep using object="spring:userManager"? It seems like it should just be a matter of parsing the string instead of needing a new attribute.

Howard said...

Well, @InsertObject is geared towards objects obtained from HiveMind. HiveMind objects (that is, services and configurations) do their lifecycle on the inside, so it makes sense to only obtain them once. Spring beans have a different lifecycle, so a different kind of property injection is a good solution, and one that doesn't keep you waiting for release 4.0.1.

Anonymous said...

Thanks Howard!

liigo said...

hi, howard:

at the last line, you use:

<inject property="myProperty" type="spring" object="mySpringBean"/>

why not:

<inject property="myProperty" object="spring:mySpringBean"/>

Howard said...

liigo -- please re-read the posting. There's a whole lifecycle issue with Spring that makes it not (always) work well with @InjectObject. Thus the need for @InjectSpring.

des09 said...

It is working well for me, very easy to integrate... set up the spring context via the listener in web.xml, add tapestry-spring .jar to WEB_INF/lib and start using the new annotation. Its not that I don't like hivemind, but when I am trying to add a web interface to a springified app, it just seems like a whole lot of extra work and duplicated configuration to inject service objects via hivemind

Howard said...

If you have an investment in Spring, or are using the many great Spring libraries, then use Spring! This is a keen demonstration of the power of open source and POJOs ... it all just works together no muss, no fuss.

vasanth said...

is there a way to inject spring service directly into a transient reference in ASO

Howard said...

No! What you do is define a HiveMind service that is the factory for the ASO, and you inject dependencies into that factory, which can then pass the dependencies to the ASO. HiveMind proxies are serializable (even if the underlying service implementation is not).

Travis said...

Do you know of a way to access HiveMind services from Spring? For exmple, I often want access to tapestry.services.External to generate external URLs.

Mahesh said...

Guys, what version of spring-tapestry do I specify in my pom dependency to get the @injectSpring annotation? I am using 5.0.18 and it does not seem to contain this annotation. TIA.

Howard said...

Mahesh -- this is an old posting for Tapestry 4. Tapestry 5 has Spring compatibility built right in, via the tapestry-spring module.

Mahesh said...

Hi Howard - does that mean, in T5, I can use @Inject for non-singleton spring beans?

Because I read the documentation:

And it says (I quote):
For the moment, you should consider the non-singleton beans to be not-injectable. Instead, inject the WebApplicationContext service and obtain the non-singleton beans as needed.

Mahesh said...

I ran some tests, with a prototype and a session bean - and it looks like the documentation is correct. @Inject appears to cache and WebApplicationContext works correctly.