25 July 2006
Java on Rails? Trails: What it is (and isn’t)
Much to-do has been made recently about Rails, and the productivity gains that are to be had from the infrastructure it provides. Listed among these gains comes a productivity boost that can be had from the embracing of a Domain Driven Development approach, whereby the developer concentrates on the Domain model and the framework (in this case Rails) provides some automagic plumbing an duct work on behalf of the programmer.
The Trails project is a rough analog to this approach (although the author seems to regret somewhat the ‘Trails’ moniker as it people naturally jump to the conclusion that it is a java version of Rails; which it is not.) This post describes my recent experimentation with the Trails framework, and my subsequent opinions on when/where/etc it might be appropriate.
Let me first start out with a disclaimer of sorts, around RoR. I have very little practical experience to date with Rails, let alone Ruby; and as such, I am not attempting to compare Trails to Rails. Also, this is not a tutorial on Trails…Several links off the Trails project homepage provide an excellent and easy to follow tutorials which will guide you thru the basics.
Trails in a Nutshell
Trails can be neatly summed up with a (slightly modified) quote directly from the project home page:
The trails project aims to make [web based] java enterprise application development radically simpler by allowing developers to focus on the domain model and having other portions dynamically generated.
Basically, you, the developer, provide:
- A POJO domain model (i.e., Plain Old Java Object representations of the data to be persisted to a database)
- Annotations within the Domain Objects that indicate which fields are to be persisted and their relationships with other Domain Objects.
The Trails framework in turn automagically provides just about everything else. Including :
- Project directory structure and build environment (Using Ant)
- Simple Web based CRUD (Create-Read-Update-Delete) screens; one-per Domain Object (Using Tapestry)
- Object relational mappings to a persistence store and the underlying Data Access Objects (DAOs) (Using Hibernate)
- A basic workflow lifecycle and wiring between the View and the Model (Using Spring)
- A packaged Web Application (.war) file ready for deployment into a standard Servlet container
So lets say you had an application that dealt with an inventory of Automobiles. You would first set up a trails project (using a provided ant task), and then define a basic POJO Domain Object:
@Entity public class Car { private Integer id; private String make; private String year; private String model; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getId(){ return id; } public void setId(Integer id) { this.id = id;} public String getMake(){ return make;} public void setMake(String make){ this.make = make;} public String getModel(){ return model;} public void setModel(String model){this.model = model;} public String getYear(){ return year;} public void setYear(String year){this.year = year;} }
The only interesting thing in this class are the handful of annotations that indicate that we want this object to be persisted (@Entity) and we want an unique Object Id auto assigned. Basically we are using the JPA to indicate to Trails (and in this case Hibernate) what gets mapped to our database.
That’s all the code we write.
When compiled into a war and deployed into a servlet container (using the ant build script that Trails provides for you), we get this when we point a browser at http://localhost:8080/blog

Clicking around allows us to enter some new car data:

… which we can then list out here:

WOW. Pretty nifty. And not bad for about 5 minutes work. Less even.
OK. This is obviously a very simple/dumb application. Its straightforward and (generally) easy to add additional Domain relationships (OneToMany, ManyToMany,etc), automatic data validation, and UI customization with a bit more work (all of which is detailed in the links available from the Trails project home page)
The Pros & Practical Applications
- You can quite literally have a complete working and very usable application running in minutes.
- Its a terrific way of providing the tedious, yet mandatory, backend admin interfaces to your existing application.
- There are lots of cool built in graphical widgets that come along for the ride, like calendars, list selectors, etc. that are generated as a result of your Domain Objects underlying data types and relationships.
The Cons
- Trails makes numerous fundamental assumptions for you– this is both its core strength and weakness. If these assumptions don’t fit within your applications overall paradigm you are going to have to do a fair amount of research/work to retool.
- Establishing relationships between Domain Objects requires JPA knowledge; and as soon as you start getting into anything remote complicated you will likely get stuck for a bit. This is not a Trails flaw per se, but its a bit of a wall nonetheless.
- Trails uses Tapestry for its view. I don’t really know squat about Tapestry, so from my standpoint that’s a con.
- Its not clear (to me anyway) how to provide ‘controller’ type logic or how one would integrate the Trails constructs cleanly with existing structures. Once again, this may be due to my general ignorance of Tapestry.
- Don’t be fooled into thinking that the resulting app is close to lightweight. It requires a servlet engine, and the generated war itself is over 20mb(!)
The Conclusion
Trails is cool. Very cool. And for certain types of applications it gets 2 thumbs up. Don’t let the listed cons keep you from exploring its value to you. That being said, it seems most valuable for quickly generating Administrative interfaces to existing applications, where the look and feel can be CRUDe (crude, get it?). Working the basic CRUD paradigm into an application with significant business logic seems daunting; and probably more work then solving the problem in a more ‘conventional’ J2EE approach.
Technorati Tags: trails, domain driven development, java, RoR
Comments are locked.
ryan says:
don says:
I can try ;) The EJB3/JPA syntax uses Java5 annotations to establish the relationships between domain objects. So if want the above defined Car object to have a collection of Part objects (yeah I know its dumb), you might declare an attribute within the Car Object like so:
private Set
..and then establish the One-Car-Has-Many-Parts relationship with an annotation on the accessor for the Parts:
@OneToMany
public Set
And if you want the Part objects in turn to know about the Car that collects them, you would have establish the ManyToOne relationship within the Part Class; as well as establish the mapping column to be used:
@OneToMany (mappedBy=”owningCar”)
…there are then a host of other adornments that can be layered on controlling cascading, lazy loading, etc. Basically, all the stuff that you have to know in order to use Hibernate directly, you need to know with the JPA. Once again, not really Trails problem, but still necessary.
ryan says:
Gotcha, so Trails doesn’t auto-wire relationships based on conventional column names (as Rails does) – it’s up to you to define them using JPA demarcations?
I wonder how difficult it would be to take it that step further and build in auto-sensing relationships…
Graeme Rocher says:
This is exactly what Grails does with GORM (http://grails.org/GORM). We built an ORM mapping strategy built on Hibernate that uses the convention in the classes instead of annotations/XML.
don says:
Ryan/Graeme,
Well with my disclaimer around my general lack of Rails experience in tact; you have it correct. Trails does not autowire relationships based on names. It does however create tables/columns/etc for you and there is a standard naming convention at play there… but it is more one associated with the JPA standards, less Trails.
I have been meaning to more fully investigate Groovy in general, and Grails in particular; so perhaps now is my excuse. Thanks for the tip.
-don
ryan says:
Don, I think I mis-spoke – Rails doesn’t auto-wire relationships per-se. You have to say something like:
has_many :parts
…similar to the annotation you would use in your examples. However, you don’t have to tell it what columns to use if you follow the convention (i.e. car_id column in the parts table) thereby avoiding the mappedBy=XXX annotation attribute in Java.


Can you expand upon what is meant by this, “Establishing relationships between Domain Objects requires JPA knowledge”?