Matt RaibleMatt Raible is a writer with a passion for software. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.
You searched this site for "java web frameworks comparison". 2,229 entries found.

You can also try this same search on Google.

Comparing the Big 5 Web Frameworks

My session at ApacheCon is titled Comparing Web Frameworks: Struts, Spring MVC, WebWork, Tapestry & JSF. I have to turn in my presentation by Friday. The purpose of this post is to get your feedback and see what you'd like to see in such a talk. Here's the abstract:

This session is designed to explore the popular Java web frameworks. It will briefly explain how each one works and the strengths and weaknesses of each. Tips, tricks and gotcha's will be plentiful. A simple web application will be dissected and the different options will be compared. Lastly, it will provide attendees with a sample app they can download that has options to use any of the frameworks described.

The simple webapp is MyUsers from Spring Live. As part of my gig with Open Logic this summer, I wrote a number of sample apps using Equinox. Among these where 1) a Mavenized version, 2) a Tapestry version, 3) a JSF version, and 4) WebWork version. The Struts and Spring MVC versions were already done as part of the book. They agreed to let me use the code and knowledge from that experience. This is all to say it shouldn't be too hard to create the sample app for this talk.

The hard part is going to be talking about things that developers care about. In my post on JSF a while back, I noted the things I typically want in my webapps. The following topics might make good points of discussion.

  • A sortable/pageable list of data. It's possible, but you have to add special sorting logic for each class. JSP already has this with the display tag - I'd simply like to be able to use it in JSF.
  • Bookmarkability. Container managed authentication gives us a great way to offer users the ability to bookmark pages. If everything is a POST with JSF, we lose this ability. Sure there's the HTMLOutputLink, but if we can't invoke actions, what good is it?
  • Clean and easy to read validation messages. The validation messages in both MyFaces and Sun's RI are not something you'd deliver to customers. What's wrong with making clean messages out-of-the-box? Tapestry seems to have no problems doing this. All the other MVC frameworks make you specify your own - which is fine with me.
  • Easy cancelling and multi-button form handling. JSF does this well - better than the rest I'd say.
  • Easy testability. Because of the plethora of JavaScript, JSF apps are difficult to test with tools like jWebUnit and Canoo's WebTest. Don't get me wrong, I love JavaScript - but an application should be able to be tested w/o it.
  • Success Messages. JSF does success messages OK - it's a pity it's not easier to get a resource bundle and it's a shame that you can't escape HTML in the <h:messages> tag. This seems like an oversight to me.

I could do a number of slides and show how each framework handles the above situations. Other topics that would be worthwhile would be:

  • Model in View - can you use your model objects to back forms or do you have to use something like ActionForms?
  • Spring Integration - all of them have this. This would merely be a discussion on how its handled.
  • Validation - how robust and/or extensible is it? How hard is it to do chained validation? What about client-side validation? Is the client-side stuff immature like WebWork's?
  • Internationalization - how is it done and how hard is it to get messages in your classes? JSF sucks at this.
  • The Duplicate Post Problem - how does it handle duplicate posts. Not the "push the submit button twice" but the "hit refresh after saving" kind. Tapestry fails this test.
  • Page Decoration - SiteMesh can be used for all frameworks, Tiles for some. Discuss how much easier it is to use SiteMesh.
  • Tools - since some frameworks have tools to help ease there development and others don't.
  • Business/Marketing - how well known is the framework and will your skills be marketable if you learn it? JSF and Struts are in high demand. Tapestry is virtually unheard of. WebWork is for the evil few (heh!) and Spring MVC is the new kid on the block.

Whaddya think - what is so special about your framework that'll make it look better in my talk? What are the things that suck that I can bash on? If you're a committer on one of these frameworks - are you going to be at ApacheCon? I'd love to have some folks defend their projects after I'm done ripping on them. ;-) If I don't rip on yours, then you can bask in all its glory.

If you live in Denver, I'll be delivering this presentation at DJUG's Architecture SIG on November 3rd.

Posted in Java at Oct 12 2004, 11:59:16 PM MDT 28 Comments

Estimating Projects

Martin Fowler has a good post on the Fixed Scope Mirage.

Many companies like the idea of writing a contract that fixes scope and price because they think it lowers their risk. The mirage says that their financial obligation is fixed at the price of the deal. If they don't get satisfactory software, then it won't cost them.

I see this often when looking for new projects. The potential client has a project they want done, and they want it done in X weeks/months. Why? Because they're willing to pay X dollars for the software and their next door neighbor (whose in IT) did an estimate for them while they were drinking beers the other day. I've learned my leason with these clients - run! Any client that estimates how long it'll take you to do something is going to be a nightmare to work for. Furthermore, if you get the gig - you've likely told them that you could do it in their timeframe.

Even worse are clients that want you to do a 1-2 week project. These are a nightmare because they tend to want lots of functionality, but don't want to pay for it - hence the 2 week project. From my experience, I've learned to only take clients that allow you to do the estimating and have projects that are a month or longer.

Posted in Java at Oct 11 2004, 02:30:08 PM MDT 7 Comments

[ANN] AppFuse 1.6 Released

After many late nights and lots of Red Bull - AppFuse 1.6 is finished. Phew! The major additions to this release are SiteMesh and WebWork. I also did a lot to simplify DAOs and the tutorials. This release is definitely the largest AppFuse one I've ever done - or at least I spent the most time on it. Not only was WebWork added and Spring MVC improved, but I improved the Struts version significantly too. Now it'll handle nested objects, which can translated into nested forms - and validation even works. All classes in the "web" module can now be tested sans-container, which eliminates the need for Cactus and reduces test execution time by over 50%. The relationship between users and roles was also re-worked to take advantage of Hibernate's slick parent-child relationship features.

See the QuickStart Guide and Tutorials to get started right away. Enjoy!

Posted in Java at Oct 09 2004, 01:34:16 PM MDT 9 Comments

fValidate - a Kick-Ass JavaScript Validation Library

I found this gem from Ben Alex on the Spring Forums tonight. fValidate looks to be an awesome client-side validation library. If you do a view-source on the aforementioned page, you'll see that all the validation rules are specified in the "alt" attribute of input elements. Apparently this is XHTML valid. Since the current implementation of WebWork in AppFuse doesn't have client-side validation, I may have to hack something together tonight. From the looks of it, this will simply involve adding an "alt" attribute to the existing WebWork tags.

Later: I think I'll pass on the AppFuse/WebWork integration - it looks like a fair amount of work and I'd rather just get 1.6 finished and released.

Posted in Java at Oct 08 2004, 10:46:14 PM MDT 14 Comments

Resin slower than Tomcat, fails the AppFuse Test

As part of AppFuse 1.6, I was hoping to supply the option to use Resin instead of Tomcat. In reality, hardly anyone has asked for this on the mailing list - but since so many folks say that "Resin is better" - I figured I'd give it a whirl. I hate to be the guy that spoils all the Resin users mantra, but it seems like Tomcat is the better server. Why? Speed, compliance and shit works. Here are some things I found:

  • Server startup time when AppFuse is only app installed (deleted work directories before starting):
    • Resin: 25 seconds
    • Tomcat: 14 seconds
    I also found that Resin loads my StartupListener twice b/c it's defined in web.xml and XDoclet puts it in the generated TLD. I think the best solution is to add a flag to XDoclet to allow you to exclude listeners from the TLD when it's generated. I commented out the entry in web.xml for this test.
  • Running "ant test-canoo" which runs through all the JSPs using Canoo's WebTest (server already started):
    • Resin: 1st run (no compiled JSPs) - 53 seconds, 2nd run (compiled JSPs) - 24 seconds.
    • Tomcat: 1st run (no compiled JSPs) - 49 seconds, 2nd run (compiled JSPs) - 14 seconds.

I did have to hack a number of things to even run the tests (which verifies titles, success messages, etc.) on Resin. First of all, SiteMesh seems to puke with if you try to use <dispatcher>FORWARD</dispatcher> on the filter-mapping. I had to comment this out, resulting in a lots of HTML Tidy errors during the tests ( Error: <content> is not recognized!). I also had to turn off Resin's fast-jstl to bypass this bug. Finally, I had to revert the displaytag to using the non-EL version (which required changing titleKey -> title and name="${listName}" -> name="listName"). It seems that Resin enables EL even if you're using a 2.3 DTD. With Tomcat, and I believe the spec says this, EL is only enabled if you use a 2.4 XSD.

So there you have it folks, not only is Resin 3.0.9 slower than Tomcat 5.0.28 (JDK 1.4.2, Windows XP), but it's not standards compliant. Of course, the speed could be due to my using the open source version (with performance enhancements turned off) - but I'd think the other (albeit minor) stuff should be easy to fix. Everytime I try to use Resin, I end up finding bugs and going back to Tomcat. I guess this is another one of those days. I don't think I'll include a Resin installer as part of 1.6, but I might distribute one later if I can get these issues solved. I wonder if I should give Orion a run for its money?

P.S. Since I know people are going to ask: Tomcat 5.5.3 with JDK 5.0 took 9 seconds to startup. Running "test-canoo"? First run: 37 seconds, second: 14 seconds. Looks like the new compiler is quite a bit faster.

Posted in Java at Oct 07 2004, 07:13:09 PM MDT 24 Comments

The New Gig

I started a new gig on Monday. For the next 6 weeks or so I'll be helping Oak Grove Systems enhance their Reactor products. I'm excited about the opportunity. I was going to use Equinox to build the prototype (due Monday), but since the final product requires security and user management - AppFuse is a more logical choice. I'd like to use WebWork or Spring, but since Oak Grove's reference implementation of their portal framework uses Struts, it's probably wise that I do the same so they can maintain it easier.

I almost went to work full-time and in an office - but now that I've chosen to take a gig with 100% work-from-home, I'm pretty glad I did. It would be tough to give up the musing-blaring, 23" monitor environment I've grown to know and love. The new office later this month will make it even nicer. BTW, the house is coming along and we should move in in a couple of weeks. Here's some pics: view from front, view from back and inside view.

Posted in Java at Oct 07 2004, 10:02:11 AM MDT 4 Comments

Aren't out-of-container tests supposed to be faster?

Earlier this week, I converted my StrutsTestCase tests from using CactusStrutsTestCase to MockStrutsTestCase. At first, this seemed like a great thing - on my Windows XP box. To run all the tests in AppFuse, it takes around 2:20. I know, this is quite a bit of time for unit tests - but it was 3:15 in version 1.5. At least it's faster than it was. 1:20 of this is for starting Tomcat and running Canoo WebTests.

This all seemed great until I ran "ant test-all" on my PowerBook tonight. It averages around 7:00 minutes. WFT?! I know PowerBooks are slow - but they're not that slow. I'm guessing the reason is because Spring's ApplicationContext is loaded by each test - whereas the Cactus versions would always grab it out of the ServletContext. Sounds like I need a TestSuite.

What if I isolate and compare times for just the "test-web" target? This target runs all the Action, Filter and Listener tests. Time to execute on Windows: 33 seconds, PowerBook: 2 minutes 21 seconds. What about just testing the JSPs (with Cargo)? Windows: 1:24, PowerBook: 3:32. My Windows desktop has 1.5 GB RAM and a 2.6 GHz processor. My PowerBook has 1 GB RAM and 1.5 GHz. I agree that it seems like an unfair comparison - but AppFuse tests ran in around 4 minutes on the PowerBook in the last release. I guess it's back to the drawing board.

Update: Nevermind. I just downloaded and checked out AppFuse 1.5 - almost 8 minutes for running all the tests. If I were going to work on my PowerBook for my next project, I'd refactor AppFuse Managers and Actions to use jMock. Luckily I'm using my Windows machine. ;-)

Update 2: I found a solution! Using Ant 1.6.2's forkmode="once", I was able to reduce the time of the test-web target from 2:21 to 24 seconds on my PowerBook!! Windows: :33 -> :18. Running "ant test-all" on the Mac is now 2:15 - while the Windows version is 2:20.

WTF!? My PowerBook is actually faster than my Windows box? I never thought I'd see the day - Yeeee haaawwww!!

Now I just have to figure out how to detect 1.6.2 and warn users if they aren't using it.

Posted in Java at Oct 05 2004, 09:26:56 PM MDT 8 Comments

Resin now Open Source?

I noticed on the release notes for Resin 3.0.9 (released last Saturday) that they now have an open source (GPL) version.

Resin Open Source (GPL) - Contains all functional components of Resin, including EJB, but excludes performance and clustering capabilities.

Excludes performance capabilities? What does that mean - is it slow on purpose? ;-)

I was planning on looking at AppFuse on Resin again tonight and hopefully figure out a way to make it easy to setup/test/deploy on Resin instead of Tomcat. Since AppFuse currently works fine on Resin, this shouldn't be too hard. The hard part is going to be finding a non-obtrusive way to setup Resin.

With Tomcat, I can copy a couple JARs to $CATALINA_HOME/common/lib and an appfuse.xml file to $CATALINA_HOME/conf/Catalina/localhost and the app is setup and ready to go. Better yet, I can use Tomcat's Ant tasks to deploy a WAR with an embedded context.xml file and it'll get copied to the appropriate location.

Is there a similar system that Resin allows? I know I can do the copy-JAR thing. However, the last time I checked, you had to manually edit the resin.conf file to import a <web-app> definition.

Posted in Java at Oct 05 2004, 04:03:36 PM MDT 7 Comments

Laszlo Goes Open Source

It's awesome to see that Laszlo has gone open source. The main reason I haven't dug into Macromedia's Flex is because it's $12K per CPU. I agree that this it's probably worth it if you're after a nice user experience - but most of my clients want open source, and only open source. It's tough to find folks that'll pay for JIRA even - if you can believe that.

With Lazlo going open source, it opens a whole new world for me. Now there's an opportunity to use this technology with clients. Of course, now I have learn the stuff so I can be productive enough to convince them to use it. I may even add a Lazlo front-end to AppFuse, but probably not until next year, after Tapestry and JSF. Hmmm, if JSF is really all that - can it render a Laszlo UI? That'd be wicked.

Posted in Java at Oct 05 2004, 09:32:06 AM MDT 14 Comments

Integrating WebWork into AppFuse

Last week was a busy one as I was trying to finish up AppFuse 1.6 before starting my new gig (more on that later). Most of this involved 1) integrating WebWork and 2) writing the Ant-based installer for replacing Struts with WebWork. I've worked with WebWork before, so this post is mostly an extension of that - as well as documentation on what I did so others can understand AppFuse+WebWork better. Below is a list of things I found.

  • WebWork's concept of "results" are very similar to Struts "action-forwards". However, they also allow you to chain to other actions and use expressions.
  • Implementing the ModelDriven interface in your Actions is a good idea, but it's not that great. I found that by simply using get/setUser(), I got the same functionality - except that I had to add "user." to all my form elements in my JSP. The advantage to doing things this way (over ModelDriven) is you can have an Action that services many objects. The main reason I'm not using ModelDriven is because the following tag doesn't render the label (it's just blank). Strangely enough, it renders just fine after validation fails.
    <ww:textfield label="getText('user.firstName')" name="'user.firstName'"
        value="user.firstName" required="true"/>
  • WebWork is similar to Tapestry in that they encourage you to specify i18n messages (properties files) on a per-action basis (Tapestry is per page). Some might think this is a good idea, but after using Struts and Spring, I'm used to using one ResourceBundle for everything. To migrate AppFuse from using 1 bundle to many bundles just for WebWork would've been a pain. Luckily, in WebWork 2.1, they added the ability to specify a custom bundle using "webwork.custom.i18n.resources=ApplicationResources" in webwork.properties. I believe my issue with ModelDriven and labels is caused by this new feature.
  • The Spring-integration provided by SpringObjectFactory is quite nice. Unfortunately, client-side visitor validation doesn't work with it.
  • Unit-testing WebWork actions is easy, though it's kinda wierd to not send request parameters and such to set values (instead, you just set values directly on the Action).
  • I experimented with putting stuff on the stack and pulling it off in JSPs, but never got it to work quite right. After failing the 10 minute test, I decided to just put stuff in the request and get it working. Looking through the code now, there's only 3 places where I'm stuffing attributes into the request: 2 in FileUploadAction and 1 in ExceptionHandlerInterceptor.
  • With most frameworks I've used in the past, I rarely jumped into the source to try and see how things worked. Because of this, I rarely extended framework classes for my own use. However, with WebWork/XWork, I found it quite easy to dig in and extend the framework. Especially with Interceptors - which I dig.
  • Following up on Interceptors, I was able to easily create my own ValidationInterceptor that cancels validation on GET requests, and when cancel or delete is clicked.
  • Other interceptors that came in handy are a UserRoleAuthorizationInterceptor (which I borrowed from Spring) and an ExceptionHandlerInterceptor (which is modeled after Spring's SimpleMappingExceptionResolver). The 1st interceptor made it easy to mimic Struts' ability to declare a "roles" attribute on an action-mapping. The 2nd one allows you to map exceptions to results. This is something I was looking for when I first started using WebWork.
  • The "required" attribute in WebWork's JSP tags have nothing to do with validation, except that they add an asterisk to the field label. I'd rather this be integrated with validation - where an asterisk shows up when a field is "required" in its Action/POJO-validation.xml file.
  • I had a few other issues with validation: client-side validation shows one error at a time, client-side validation doesn't allow cancelling and field errors are displayed in a random order. If I were to start a project tomorrow that wanted WebWork with client-side validation, I'd probably try to integrate Commons Validator.
  • Testing Actions is easy, as it should be. Using Spring's Servlet API mocks made it easy to test Actions that used ServletActionContext to set cookies and other such request-related stuff.
  • I dig the rich set of form tags and it's great that these can be easily customized. I customized a few for AppFuse to make the syntax a bit more XHTML-compliant.
  • I'm a stickler for formatting and good-looking XHTML in JSPs. I try to keep lines less than 80 characters. Here's a comparison of the LOC required by the different frameworks for userForm.jsp:
    • Struts: 298
    • Spring: 319
    • WebWork: 186

All in all, I enjoyed working with WebWork and if given a choice of an AppFuse combination to use on my next project - it would probably be WebWork+Hibernate. If the client wanted client-side validation, I'd either integrate Commons Validator (which shouldn't be too hard) or use Spring+Hibernate. After using Spring and WebWork, which allow you to use your model objects directly in the view, it would be tough to go back to Struts. However, I still do know Struts better than the other two - so if I had a really tight deadline, that might be the smart way to go.

Posted in Java at Oct 04 2004, 08:17:37 AM MDT 2 Comments