Matt RaibleMatt Raible is a Web Architecture Consultant specializing in open source frameworks.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: AngularJS, 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.


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.

Does Struts 2 suck?

As far as I can tell, Struts 2 sucks. To be fair, so does Stripes. Why? Because there's no developer feedback for invalid properties or OGNL Expressions. What does this mean? It means if you fat-finger a property name, nothing happens. The OGNL exception is swallowed and you never know you did anything wrong. Furthermore, no one seems to care. The XWork folks will help you build, but not solve the problem. This seems like a major deal-breaker to me, However, I also believe it can be fixed - so maybe there's hope.

To demonstrate the problem, I did an experiment. I used the "user details" page in AppFuse Light to fat-finger a property name for the following frameworks: Struts 1, WebWork, Struts 2, JSF, Spring MVC, Stripes, Tapestry and Wicket. First, I tried changing the "lastName" property to "LastName" to see if the framework's property evaluation was case-sensitive. I found that with WebWork/Struts 2, Stripes and Tapestry, the property is not case-sensitive. I prefer case-sensitivity, but maybe that's because I prefer Unix over Windows.

The 2nd thing I tried was changing "lastName" to "pastName" to see if I'd get an error. An error occurred for all the frameworks mentioned, except for WebWork/Struts 2 and Stripes. This makes me believe these frameworks suck. The both use OGNL, so they could blame it on that, but Tapestry uses OGNL and it presents an error message. After this small experiment, my conclusion is the following frameworks have the best developer feedback:

  • Struts 1
  • JSF
  • Spring MVC
  • Tapestry
  • Wicket*

* Wicket seems like it needs some work as all it presents is "Internal Error" and makes you dig through your log files to find the problem.

Without good developer feedback, how can you have good productivity?

Dear Struts 2 and Stripes Developers,

What do you think about improving your error messages for invalid properties and expressions? Is this a feature you think you could add? We'd love it if you did.


Your Users

Click here for some screenshots of how a fat-fingered property looks in various frameworks:

Update: Stripes doesn't suck and Wicket has excellent error reporting. See my comment below for more details.

Update 2: I've created a patch to (hopefully) solve this issue in XWork. If you have any feedback on ways to improve this patch, I'd love to hear about it.

Posted in Java at Sep 05 2007, 11:21:57 AM MDT 39 Comments

Actually, Stripes does warn you, just not on the page. It would be in the debug. Also note that Stripes doesn't use OGNL anymore. Not that that is a big deal with regards to your post but you might want to be accurate at least.



Posted by Gregg Bolinger on September 05, 2007 at 11:35 AM MDT #

Deal breaker indeed, right up there with Struts 1 failing silently when it cannot convert a String to another type (hence the whole "Forms should only have String properties"). Can you file a JIRA bug on this? This would surely grab the developers' attention.

Posted by GB on September 05, 2007 at 11:41 AM MDT #

I agree, that sucks. But I think the overall Struts2 has a bright future. The documentation for Struts2 sucks, the developer feedback sucks but these are things that can come in time. I'd be much more concerned if there were fundamental problems with the heaviness of the framework. Glad to see you shining a light on it and I look forward to the developers doing what they can.

Posted by Demian Neidetcher on September 05, 2007 at 11:48 AM MDT #

Here's the debug for Stripes:

DEBUG Could not bind property with name [lkastName] to bean of type: FormTestActionBean : Bean class does not contain a property called 'lkastName'. As a result the following expression could not be evaluated: lkastName

It's not an immediate result when the page is displayed but it does inform you to exactly what the problem is.

Posted by Gregg Bolinger on September 05, 2007 at 11:57 AM MDT #

About Wicket requiring to dig through the logs, is your app configured in development or deployment mode? In development mode, you should get the stack trace right into your page, while in deployment mode, you only get an internal error page (which is customizable).

IMO it's a very nice way to deal with errors, end users should not have to see stack traces or detailed error messages.

Posted by Xavier Hanin on September 05, 2007 at 12:07 PM MDT #

Thanks for the tip Greg - I didn't realize I needed to turn logging on in Stripes to see this. It looks like all you need is the following in your log4j.xml:

    <logger name="net.sourceforge.stripes">
        <level value="DEBUG"/>

Then you get:

INFO - | Could not locate property of name [user.PastName] on Bean class org.appfuse.model.User does not contain a property called 'PastName'. As a result the following expression could not be evaluated: user.PastName

Of course, you could use INFO and get the same error. I'd expect this to be WARN though since it seems like a pretty big issue to me. With my level set to DEBUG for Stripes - I am impressed with the nice and readable logging:

DEBUG - Log.trace(188) | Intercepting request to URL: /userform.html
DEBUG - Log.debug(177) | LocalePicker selected locale: en_US
DEBUG - Log.debug(177) | LocalePicker did not pick a character encoding, using default: UTF-8
DEBUG - Log.trace(188) | Dispatching request to URL: /userform.html
DEBUG - Log.debug(177) | Transitioning to lifecycle stage ActionBeanResolution
DEBUG - Log.debug(177) | Running Spring dependency injection for instance of UserFormBean
DEBUG - Log.debug(177) | Found spring bean with name [userManager] and type [$Proxy1]
DEBUG - Log.debug(177) | Transitioning to lifecycle stage HandlerResolution
DEBUG - Log.debug(177) | Resolved event: view; will invoke: UserFormBean.view()
DEBUG - Log.debug(177) | Transitioning to lifecycle stage BindingAndValidation
DEBUG - Log.trace(188) | Running binding for property with name: id
DEBUG - Log.debug(177) | Converting 1 value(s) using converter net.sourceforge.stripes.validation.StringTypeConverter@173fce
DEBUG - Log.debug(177) | Transitioning to lifecycle stage EventHandling
DEBUG - Log.debug(177) | Transitioning to lifecycle stage ResolutionExecution
DEBUG - Log.trace(188) | Forwarding to URL: /userForm.jsp

GB - I filed XW-557 last week.

Xavier - good point, I forgot I was using Application.DEPLOYMENT. Changing it to Application.DEVELOPMENT results in an excellent error message. I agree that having different error messages for different deployments is a great feature. Here's a screenshot in development mode.

Posted by Matt Raible on September 05, 2007 at 12:44 PM MDT #

T5 has even better exception reporting. It doesn't use OGNL. It is NOT case sensitive, by design. The exception reporting is even better.

I can't remember if I've implemented this yet, but I believe that when you "fat finger" a property name, Tapestry will now (in the exception report) list the known properties. I know we have all the right information to accomplish this, but I need to double check if it exists yet. That's a common feature in T5: if you are selecting a name from some preset list, is case insensitive, and on a no-match failure, lists the possible matches.

Posted by Howard Lewis Ship on September 05, 2007 at 01:18 PM MDT #

Oh c'on you can do better than that :). Just logging or throwing an exception in CompoundRootAccessor:getProperty when the property is not found will do.

Posted by musachy on September 05, 2007 at 02:44 PM MDT #

[Trackback] prompted from this posting : it's possible for ognl to report that a property does not exist, just that no logging was coded up. null

Posted by JIRA: XWork on September 05, 2007 at 03:18 PM MDT #

I'm not so sure that this is a bad thing... sure logging in the background would be nice but in the presentation layer having a silent fail is often nicer than a splat but this does all really come down to the context. I have been using XSLT/Saxon recently in a project and it errors out when processing the XML + stylesheet when say an expected XML value is empty it dumps into the logs but does not render anything at all. Overall I really like the Struts2 framework, it seems really easy and flexibile with the help of Appfuse :)

Posted by James McIntosh on September 06, 2007 at 04:56 AM MDT #

When you are using freemarker as your result technology in struts2 you get great feedback on problems like this. This is not indicative of the whole framework -- just the result-type that you are using (probably jsp?)

Posted by Keith Weinberg on September 06, 2007 at 07:12 AM MDT #

Someone should have responded to your question -- not a good sign. Similar to Xavier's point on Wicket, WebWork also has a development mode. Too verbose for my taste, but a helpful feedback during development. Do you think it would be more helpful if this was on by default?

Posted by Jay on September 06, 2007 at 07:57 AM MDT #

Oh, and here's the link for Strut's devMode --

Posted by Jay on September 06, 2007 at 08:00 AM MDT #

I have been using struts2 in one of my project. Struts2 has a good pluggable architecture. But I have to say that it does not perform well in the enterprise app. Upgrade even within different struts2 versions is painful especially if you are using Tiles and Ajax in your app. I have used WebWork and SpringMVC in the past. Stripes on the other hand I think the best request based MVC framework available.

Posted by dave on September 06, 2007 at 09:02 AM MDT #

Have you tried working with devMode turned on?


For example, if I add to the form on MailReader Login.jsp
    <s:textfield name="doesntexist" />

and submit the form with devmode=true, the following is logged

Sep 6, 2007 11:14:52 AM
INFO: Detected AnnotationActionValidatorManager, initializing it...
Sep 6, 2007 11:15:01 AM
SEVERE: ParametersInterceptor - [setParameters]: Unexpected Exception
caught setting '' on 'class mailreader2.Login: Error
setting expression '' with value
Sep 6, 2007 11:15:01 AM
SEVERE: ParametersInterceptor - [setParameters]: Unexpected Exception
caught setting 'doesntexist' on 'class mailreader2.Login: Error
setting expression 'doesntexist' with value

Note that devmode also reports things like there not being a property to catch the 
values submitted by the buttons. At one time, our examples had it turned on by 
default, but people were neglecting to disable devmode in production, which was 
leading to performance issues.  

In some cases, the debugging interceptor might also be of use: 


If a post like this is not answered on user@, please feel free to repost to dev@, in case 
there is a need for new functionality. After that, also feel free to open a JIRA ticket to 
track any work on the issue, including any patches of your own that might address the 

HTH, Ted.

Posted by Ted Husted on September 06, 2007 at 09:34 AM MDT #

Matt, we hear you. It's these kinds of issues that make Java frameworks frustrating to work with. There are so many choices and options that result in this type of problem. It can be agonizing to work through these things. However, as Keith said, this specific problem should disappear completely when using Freemarker templates rather than JSP. If I were you, I'd just switch to Freemarker for Struts 2 projects.

Posted by giesen on September 06, 2007 at 10:56 AM MDT #

That is definitely not a problem with Wicket. This is expected behavior in deployment mode. If you want to see a stack trace and even more useful information about what went wrong, you need to be in development mode.

Posted by Jonathan Locke on September 06, 2007 at 11:22 AM MDT #

Ted: Using struts.devMode=true will catch setting invalid properties, but not reading from them. I want to be warned when a property/method doesn't exist. Or in the instance of calling stating methods with FQCN, I want to be made aware when I fat finger the package name. If I could use JSP's import and then read from the package, that'd be even nicer. It's somewhat verbose to call FQ static methods. I suppose I could move the methods into my action, so it's not too bad.

Giesen: FreeMarker is an easy sell to me, but often not to my clients. While it may be easy enough to use and learn, it's difficult to hire for. JSP is easy. You and I realize a good developer can learn any templating language, but companies often like the buzzword-compliant technologies they think they can hire for. Another problem with FreeMarker is I haven't used it enough to get be productive, so I still tend to do a lot of searching through documentation and macro libraries.

Has anyone used the FreeMarker Eclipse Plugin? It's nice having code-completion with JSPs. Unfortunately, it looks like IntelliJ users are SOL when it comes to FreeMarker.

I've done a lot of work with JSP Tag Files recently and I think I prefer Ctrl+Shift+R -> search for tag filename over opening a macro file and searching for the macro you're trying to use.

Posted by Matt Raible on September 06, 2007 at 11:23 AM MDT #

Matt: If that's your itch, then please scratch it. (IOW: Thanks for volunteering!)

Both the Struts and the XWork teams are always on the lookout for good patches from great developers, like you! Products like Struts aren't created behind closed doors. Struts is now (and always has been!) created by volunteer developers, who work another job all day and then tinker at night. If Struts doesn't work the way you think it should, then, please, show us the patch.

Though, be careful, we have a bad habit of offering karma to people who submit patches! :)


Posted by Ted Husted on September 06, 2007 at 07:03 PM MDT #

I've used Struts2 on various projects and I have to say that the learning curve from Struts1 is high - the framework is totally different and takes some getting used to. Aditionally, Struts 2.0.6 and below suffered from a particularly bad OGNL performance problem with freemarker templates. Which pretty much made it unusable for us a large clustered and high transaction environment. Having said that on smaller projects I've been using Struts 2.0.9 and it works a charm.

Posted by Derik on September 07, 2007 at 01:55 AM MDT #

@Regarding OGNL converting different value types: There was a previous bug in OGNL that made it swallow errors when it tried to do set operations with values of differing types that couldn't be converted with the basic java type facilities available. This has been fixed since the 2.7 series started, but just wanted to be sure that people didn't think this was the fault of any particular framework using ognl. It annoyed the crap out of me too for a long time until I accidentally saw and fixed it.

Posted by Jesse Kuhnert on September 07, 2007 at 05:51 AM MDT #

[Trackback] Attached is a sample app to reproduce this behavior. From its README.txt: This application was created to show how Struts2/XWork doesn't throw exceptions or log errors when a property doesn't exist. Furthermore, it doesn't notify the user when a ...

Posted by JIRA: XWork on September 07, 2007 at 12:24 PM MDT #

hi Matt, I have posted some additional thoughts on the same subject. I think it may also offer an answer to why you think that the stripes community continues to be small. Thanks anand raman

Posted by anand raman on September 07, 2007 at 09:01 PM MDT #

I was inspired, so I added the "show me the possible properties" feature to Tapestry 5:

[Link to Screenshot]

Posted by Howard Lewis Ship on September 08, 2007 at 09:45 AM MDT #

Matt, What is your favorite Java Web framework these days? Also, if you were to develop a Digg-like Web application what framework would have you chosen? The same framework? Finally, what framework do you recommend to use when the App is going to be deployed on a host with a modest amount of RAM (say 256MB or 512MB at best)? Let's suppose the App is going to have around 5 requests/second at peak times.

Posted by Chris on September 10, 2007 at 12:54 AM MDT #

Matt, The second screenshot you gave actually points to another problem (as you can read from the error message): you added a component with an id that can't be matched. If you use a PropertyModel with an expression that can't be found, you'll get a message like: org.apache.wicket.WicketRuntimeException: No get method defined for class: class org.apache.wicket.examples.forminput.FormInput$InputForm expression: stringPropertie at org.apache.wicket.util.lang.PropertyResolver.getGetAndSetter( Of course, you don't have to use property models; with a little bit more code, you'll be completely statically typed. :)

Posted by Eelco Hillenius on September 10, 2007 at 08:03 PM MDT #

This whole discussion brings me back to the root of the problem Why must we use strings as property expressions, Why can't we have real statically typed and compiled expressions in java that would be sooo much better, complete refactor support out of the box new PropertyModel(new Bean(), person#address$street) please sun give us that!

Posted by Johan Compagner on September 11, 2007 at 01:51 PM MDT #

> Matt, What is your favorite Java Web framework these days? Also, if you were to develop a Digg-like Web application what framework would have you chosen?

I think it all depends on the application you're writing, as well as a number of other factors, including: application type, ease of development, project community, prooject future and roadmap, maintenance and technical features. I'll be talking about this a lot at this year's Colorado Software Summit. I've changed the title of my talk from Choosing a Web Framework to Choosing a JVM Web Framework.

I hope to make the talk an interactive discussion that leads to some conclusions I can use to write some sort of article or whitepaper on.

Posted by Matt Raible on September 20, 2007 at 06:53 AM MDT #

Matt, can you please update the Wicket portion of this article? It's highly misleading since Wicket's developer feedback is better than most of the frameworks you show here. The error page you're showing is *intentionally* terse because it's intended for production rather than development use. I know it's already been mentioned, but it looks like you've switched to deployment mode when you should be in development mode.

Here's a FAQ entry describing various ways to change the configuration mode.

Posted by Ryan Holmes on September 24, 2007 at 01:52 PM MDT #

Sorry Matt, just now saw your comment that you switched to development mode and got the correct feedback. But, again, can you please update your article with this info? Not everyone is going to read through all the comments to discover that Wicket actually has great developer feedback, rather than such poor feedback that it gets an asterisk and a "needs work" note in the article.

Posted by Ryan Holmes on September 24, 2007 at 02:10 PM MDT #

I've added an update note - thanks for keeping me honest Ryan. ;-)

Posted by Matt Raible on September 24, 2007 at 02:12 PM MDT #

[Trackback] I'm not convinced my implementation is a good one. However, I do believe the functionality is necessary. Of all the frameworks I examined, Struts 2 was the most deficient in this area. ;-)

Posted by JIRA: XWork on November 02, 2007 at 10:14 PM MDT #

Just did a cursory evaluation of struts2 and stripes in WebSphere. The overhead of both of these (especially stripes) was not worth the benifits and I stayed with struts. RAD/WebSphere is a heavy development environment as it is and either of these put it over the edge as unusable. Stripes especially, inventoring every jar in the project on load was completely unacceptable.

I guess having worked with struts from the beginning and finding solutions to all the perceived problems with struts also makes these shortcomings seem larger than they might be otherwise.


Posted by Edgar Dollin on January 25, 2008 at 11:00 AM MST #

Yes. Its a framework solving no outstanding problems and very, very poorly integrating with existing frameworks and handling errors. But we are stuck with it on many large Java projects due to market fads.

Rather than solve hard problems, the framework guys keep solving easy ones. E.g. why not have support for 200 common business data types and an integrated way to validate these. Now that would save everyone some time. Yet another way to handle web requests is just plain redundant. Worst of all, the Struts 1 framework binds the display to the backend. Struts architects will tell you it doesn't but every implementation which uses it does. Perhaps Struts 2 with REST approach will be better.

I'm just starting to look at Struts 2. Incredibly poorly documented on even the helloworld example. For instance, it cannot just be dropped into IBM's RAD7 and run. It doesn't work. Perhaps some special mappings need to be added to support the "action" extension; but the point is these special steps to make their framework work should be clearly documented.

Not being backward compatible is a trademark of Apache projects. It is against the software industry standard of being compatible with the last two releases. It is not professional.

Posted by MadHacker on October 17, 2008 at 04:21 AM MDT #

the best think on wich struts2 sucks is that there is no servlet as there was with Webworks. Instead, there is a filter.

the problem is that you *can't* use request dispatcher to forward to another action. You can't because the lack of a servlet make the application server answer with a "404 not found".

I know you can use "action chaining" but it breaks servlet apis and it's not always possible.

For example, I recently had the problem because I had to use a client api that make use of request dispatcher ...

Also, request dispatcher allow to make dispatch to someting like "/". Actually, it's impossible. For action chaining, I have to had parameters names that matchs. I can't give an arbitrary action.

Also, with action chaining, insterceptors stack is not called again.

And last, wth action chaining, you can't call code that use "request.getParameter()". You could with a standard request forward.

well there is hundreds of reason to use request dispatcher but struts2 broke it. I asked why, but I never had an explanation. If anybody had an Idea, I would love to read it ...

Posted by Mike on December 21, 2008 at 05:23 AM MST #

Well I won't say it "sucks", but I will say I don't see the point of having created a new framework. It would have been a whole lot better for everyone if they just appended to Struts1. After all there's a zillion lines of code for Struts1 and we wouldn't have to re-learn everything all over again. Sure Struts2 purports to "fix" all of Struts1's problems but again, what's the point when all those "problems" were already handled.

So now we've got Struts2 and are at square 1. Samething happened when we coded against the straight servlet model, everything worked! Then all these damn frameworks, more and more code, more and more development time, more and more bugs.

You tell me, so far I would say on the whole frameworks suck. Next will be Struts3, etc, ad naseum.

With everyone coding AJAX, the "view" of MVC is out the window, so now we've got Struts with no real need for all the view portion which then begs the question, well if no view then why have all the code which handles the UI side of things in the framework.

Again more and more code, more and more bugs, more and more development time.

So no Struts2 doesn't "suck" but the paradigm of never ending frameworks just might.

Posted by raka on October 01, 2009 at 12:07 PM MDT #

Struts 2 ? - common, there is no "Struts 2" its 100% re-branded version of "not so popular" webworks,and I had really bad experience with webworks and its performance bottlenecks, that is why I "unfortunately" moved away from struts after that and landed on Stripes Framework . so I agree Struts 2 - sucks, Struts 1.3.x - I love it.

Posted by levan on February 03, 2010 at 09:50 AM MST #

I agree : it's the biggest problem. I asked for this to Patrick Lightbody 3 years ago.

and his reply :

There are some args here :

But I'm not convinced.

At webwork's time, we were able to choose between servlet and filter. When it become strut2, the servlet part has been removed.

Posted by mike on February 26, 2010 at 09:21 AM MST #

I've looked at Struts 2 as an upgrade from Struts 1.4 and so far I am not convinced. My big surprise was that the whole thing is implemented as a servlet filter and not a servlet, which seems to severely limit my ability to use other filters, e.g. when I need to forward from a custom filter directly to the struts code. But you cant forward to a filter! A very peculiar architectural decision.

Posted by Igor on February 26, 2010 at 09:21 AM MST #

Post a Comment:
  • HTML Syntax: Allowed