Matt RaibleMatt Raible is a Web Developer and Java Champion. 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.

How do you get around Struts' single inheritence model?

Adrian Lanning sent me an interesting e-mail yesterday. He's looking for a better way to extend Struts. I thought I'd post his message here and see if anyone has ideas.

I am a big struts fan and use it for my projects but I think there is something fundamentally wrong with the design. The real crux of the matter may be that Java is a single-inheritance model and Struts is designed more for multiple-inheritance.

Example 1.
Complexity when trying to use "extensions" to struts that have their own RequestProcessors. Such as my extension for roles (mentioned below) used together with Asqdotcom's ActionPlugin which is a plugin but still uses its own RequestProcessor, plus another hypothetical extension which has it's own RequestProcessor. Basically the only way to use them all is to modify the source of one or two to extend the others which doesn't seem like a good design.

Example 2.
Extending LookupDispatchAction to include per-method validation (set in struts-config.xml). Basically same problem. Need to combine functionality of ValidatorAction and LookupDispatchAction but can't extend from both. Have to modify source. Actually Brandon Goodin wrote this already (I find it very useful). It's called ValidatorLookupDispatchAction.

I know this is a common issue with single-inheritence models/languages. It would be really easy to extend Struts in a multiple-inheritance model.

* THE POINT *
I was just wondering if you knew of a better way to design when dealing with single-inheritance models to avoid problems such as these.

Personally, I don't find the need to extend Struts that much, so this is not much of an issue for me. I think Struts 2.0 will solve many of Struts single-inheritance design by declaring interfaces for all core components. I wonder when 2.0 is roadmapped to ship - sometime in 2006? ;-)

Later: The article, Security in Struts: User Delegation Made Possible, by Werner Ramaeker provides a good example of a Struts extension strategy.

Posted in Java at Feb 25 2004, 04:00:05 AM MST 23 Comments
Comments:

I've extended the Action classes for extra processing myself. While it might not solve your problem for plugins which are written by others, it will solve the problem for your own extentions. Basically I always have a BaseAction class which extends Action. All my actions extend BaseAction. The same goes for RequestProcessor, BaseRequestProcessor extends RequestProcessor, then you write your impls from there and override the methods as needed. This would allow you to have multiple extentions with different behavior based on which plugin you use. As you said, it's a single-inheritance model, hence you need to have a model which allows 'faking' the multiple inheritace. HTH. R

Posted by Robert S. Sfeir on February 25, 2004 at 01:16 PM MST #

Extending Struts gives you huge productivity. I extend Action and FormBean clases every time in Struts and elsewhere. So.... standard Java, a baseFormBean has a DAO. So you have dual inehritance, is a/has a. thanks for a post on conference. .V

Posted by Vic on February 25, 2004 at 02:20 PM MST #

Example 1 _could_ be solved by writing a decorator that is derived from RequestProcessor and expects another RequestProcessor instance in the constructor, e.g: public MyRequestProcessor(RequestProcessor otherProcessor). Unfortunately important messages of the RequestProcessor are declared as protected. Therefore your RequestProcessor must be in the same package as the original processor. Furthermore it would be a good design if RequestProcessor was an interface. In SAIF I faced exactly this problem: a special RequestProcessor that should honor other veriants of RequestProcessor.

Posted by Lars Hoss on February 25, 2004 at 03:56 PM MST #

With <code>ActionMapping</code>, mostly it's up to the extension to play nice with others. Often the point of offering an <code>ActionMapping</code> extension is to add custom properties to the XML file for each <code>Action</code>. If the extension specifies an interface, and treats the <code>ActionMapping</code> <em>only</em> as a place where it can retrieve the custom properties—then it can put the handling code in a helper class of some kind. This lets each Struts end user create a basic extension of the Struts <code>ActionMapping</code>, and then implement many interfaces that are (typically) simple getters and setters. So it's likely that the use of intefaces in Struts 2.0 will really help this dillema. Until then it's entirely possible for extension writer to "play nice," but it's up to them to do so. An interesting example is Struts-Workflow. It did well on making the <code>RequestProcessor</code> easily combine with others, but could be better at letting its <code>ActionMapping</code> do so as well.

Posted by Tim on February 25, 2004 at 04:46 PM MST #

Haha... this is too easy... use WebWork... :-)

Posted by Jason Carreira on February 25, 2004 at 05:16 PM MST #

The main problem (IMO) with WebWork and Tapestry is industry adoption. I do plan on learning them, but I doubt I'll get many contracts where I can actually use them. As an independent consultant, I'd be foolish not to following the money. Today's tally on Dice.com:

  • Struts jobs: 495
  • WebWork jobs: 1
  • Tapestry jobs: 0

You guys need some serious marketing. ;-)

Posted by Matt Raible on February 25, 2004 at 05:27 PM MST #

Well, that's ones specifying the technology... how about ones where they just want it to work and be as simple and maintainable as possible? Many jobs aren't going to specify details like this...

Posted by Jason Carreira on February 25, 2004 at 05:48 PM MST #

Jason, you are still living in your dream world. Struts is proven well documentated and do not have trolls like you but have serious engineers working on it. JSF is an excellent component based framework, a company would be foolish not to use them and risk using webwork where developers go on hiatus for months.

Posted by Unknown on February 25, 2004 at 07:59 PM MST #

If you're going to bash WebWork (or any other project), please be kind enough to leave your name. Words from <em>nobody</em> mean nothing. What are your credentials?

I think it's time I started a new policy. From this point forward, anonymous bashers must leave their name or their comments will be deleted.

Posted by Matt Raible on February 25, 2004 at 08:09 PM MST #

We go on hiatus for months? How long did it take Struts 1.1 to come out? And with what features? If you believe serious engineers built Struts go read this question again... Did serious engineers put serious design into this framework, or are there serious limitations because of the design decisions which were made? Are you thinking for yourself, or following the herd?

Posted by Jason Carreira on February 25, 2004 at 08:15 PM MST #

Jason, If you're saying that Struts bites, then you must also say that JSF bites, since it doesn't offer much more than Struts does, and JSF's blue print was designed by excellent engineers. I am not seeing where you point is in bashing Struts 1.1. It has drawbacks, it took a while to come out, but so what? Does that make it a bad Framework? No. Does it mean that serious engineers don't use it? hell no, I do, and last I checked no one told me I wasn't serious :-) I just think each product has its advantages, each product will cater to a different audience, and no 2 engineers think alike, hence the great wide world of choice. I think your response was probably out of anger towards this anonymous coward who won't come out to say what's on his/her mind. (Hey it could be a chick :-) ) Matt, I agree about the anonymous posts. If you don't have the cojones to come out and say it in public, and be ready to take it in the face, then don't come out at all. R

Posted by Robert S. Sfeir on February 25, 2004 at 08:31 PM MST #

I get tired of hearing how great Struts is when I see issues like the one in this post come up time and again. Yes, I'll say it, Struts bites. Many people have been able to get it to work, which makes it the most dangerous type of crappy software, the kind that kind-of-works-and-you-can-get-it-to-do-most-of-what-you-want-so-why-bother-changing? On the WebWork lists, we get thank yous all the time from people who've switched from Struts and found out how much easier it can be with WebWork. If Struts works for you, then great, but don't start crap with me about how great it is, because it's seriously flawed. JSF is a different beast. I think it's going to be the EJB of the web tier. It's a solution in search of a problem, IMHO, and, after lots of people adopt it and then figure out the problems with it, we'll see a similar backlash. I think it will eventually settle down into being used to quickly mock things up and for very simple web applications, perhaps on intranets. I don't think it will be capable of building serious enterprise web applications.

Posted by Jason Carreira on February 25, 2004 at 08:46 PM MST #

Thank you for all the advice.

It seems most people think that using Interfaces solves this issue.

I may be showing my ignorance here but can someone point out how using Interfaces solves my 2 example issues? Jason?

Is the "pipeline" concept of chain-able processing blocks (servlet filters, superscalar microprocessor cores, graphics pipelines, MS Windows event hooks) a better way to design for extension?

Thoughts?

Thanks,
Adrian

Posted by Adrian Lanning on February 26, 2004 at 05:05 AM MST #

Chain of Responsibility / Interceptor / Filter does fit really well when you know you're going to want to be able to plug in other functionality easily at some point... We use it in Xwork / WebWork as Interceptors which can run before and after the Action and Result are executed, and it works great. Interceptors help because they allow you to have any implementation, rather than having to extend a certain class. Remember, Java DOES have multiple inheritance, it's just that you only have Interface inheritance, not implementation inheritance. So you can have impl1, impl2, and impl3, which just delegates to impl1 and impl2 in order...

Posted by Jason Carreira on February 26, 2004 at 05:27 AM MST #

oops... should have been "Interfaces help because they allow you to have any implementation.."

Posted by Jason Carreira on February 26, 2004 at 05:29 AM MST #

I have to agree struts bites. Give experience in both struts and WW, I don't think it would be a hard sell to managment. If you can be more productive in WW it doesn't make sense not to use it over struts. Given an in house resource, any "competent" developer should be able to pick up WW and be productive with a day or two. As for JSF. A company would be foolish to adopt this now. JSF is really cool if you have ide support. If not, its more tedious to wire together than simple post/get requests. Since their is no .NET ide for the java world (via JSF), it would not make sense to use JSF(yet).

Posted by Matthew Payne on February 26, 2004 at 04:53 PM MST #

meant to say any competent "struts" developer. i.e. an existing mvs web knowledge

Posted by Matthew Payne on February 26, 2004 at 05:04 PM MST #

Interceptors = Design for Extensibility?

So Interfaces aren't the solution, Interceptors (filters, chain of responsibility, what have you) are. Any number of "extensions" can be used because they are all implemented as "interceptors" (filters, hooks, etc...). Is this correct?

Assuming this is correct, then the design of Struts itself is only flawed in this regard in that there is no method for Interception. For example, many times extension authors must add extra functionality to the RequestProcessor which causes problems such as I illustrated in my original email. Each extension basically nullifies all others because there is no way for multiple RequestProcessors to work together.

Solving the Struts Extension Problem

A permanent solution would be for extension authors to be able to implement RequestProcessor-esque "interceptors" which would each be put into the processing pipeline for each request... Have I reached the heart of the matter?

To solve the extension problem in Struts temporarily we just need to create a new RequestProcessor, ActionMapping, and Action. As Lars posted early on, if we changed the RequestProcessor constructor sig to also accept other RequestProcessors, this would allow developers to declare multiple RequestProcessors in the struts-config.xml file (thereby solving the extension problem). We would also have to make the base RequestProcessor's "important messages" public rather than private as Lars points out above.

Does this solve the problem? Has anyone done this already?

WebWorks

Jason, it seems that you are saying WebWork uses Interception and therefore solves these issues. It is "extensible" because you can plug any number of interceptors into the request pipeline. Please provide an example of a time when you used multiple "extensions" in WebWork together. It will no doubt shed some light on this.

(PLEASE NOTE: If the any of the functionality I suggest below as examples of "extensions" is "built-in" to WebWork please use a different example. The point here is to study how frameworks can be designed for extension, not to solve any specific problem of mine.)

I'm not familiar with WebWork terminology or structure but say, for example, I want to process a request three times before any Action gets called. Once to validate data on a per-method basis (vs the per request basis that I think is built into WebWork), again to validate user roles, and a final hypothetical time for some other "extension".

Posted by Adrian Lanning on February 26, 2004 at 06:57 PM MST #

Upon further thought on the issue of temporarily modifying Struts to allow for multiple RequestProcessors, what changes are really necessary?

Not knowing the struts internals, could it be as simple as modifying the digester code to take a comma seperated list of RequestProcessors and then changing the code that uses the RequestProcessor to use each in turn?

This strategy might be directly applicable to other projects as well. Such as Matt's excellent Struts-Menu.

For arguments sake assume someone wants to use more than one "PermissionAdapter" when using Struts-Menu. I want to do 'permissions="pa1,pa2'. (I know, I know, PermissionAdapter is so simple that it would be really, really easy to use composition to solve this.) Thoughts?

Posted by Adrian Lanning on February 26, 2004 at 07:51 PM MST #

BOTH Interceptors AND programming to Interfaces are powerful and allow for extensibility of a system. Adding a chain of responsibility would help Struts, but it's not the only issue.

In WebWork, we use Interceptors for much of the core functionality. I'm not sure what you're talking about, when you say "I want to process a request three times before any Action gets called". If you mean you want to apply 3 Interceptors, then that's very easy, you just configure your Action with those 3 Interceptors applied.

For Interceptors, we have everything from the very easy Logging and Timing, to core functionality like setting the parameters from the request onto your Action (yes, this can be omitted and/or replaced with your own). We also have complex Interceptors like the validation Interceptor (the Interceptor is simple, but the framework behind it does a lot of work). The validation framework is very flexible and provides for different validation sets for different action configurations, even if they're mapped to the same Action class, and provides for inheriting common validations, and even allows you to pass the validation down into your properties to be validated using their own validation rules. We also do things like form token validation, to prevent duplicate posting. There's actually 2 Interceptors to prevent the Action from executing twice... One returns a code which can be mapped to another page, etc. The other actually keeps the previously executed Action in the Session and re-renders it the same as the first time the request was posted...

These are just examples, though. In the Hibernate example app, which is built with WebWork2, they implemented an Interceptor to handle managing the Hibernate Session, creating it when the request enters and closing it when it's done (after the page has been rendered).

Other Interceptor ideas are unlimited... Whatever you need to do. We implemented a lot of the core functionality in Interceptors so they can be plugged in (or not) and only provide the exact functionality required for this Action.

Posted by Jason Carreira on February 26, 2004 at 08:05 PM MST #

Adrian few people has extended struts to allow webwork type of interceptors and IOC

Posted by Unknown on February 26, 2004 at 10:56 PM MST #

Jason, thanks for the breakdown. I'm looking forward to trying out WW2.

Any plans to make a Struts 1.1 -> WW2 migration guide? Or flesh out the Struts 1.0 ->WW2 one?

Since Struts is apparently the most used framework, an example app written in Struts and then ported to WW2 (to show the difference/benifit of WW2) might be very successful in encouraging developers to migrate to WW.

Posted by Adrian Lanning on February 28, 2004 at 03:45 AM MST #

work in

Posted by Ashok Agrawal on July 30, 2005 at 07:23 AM MDT #

Post a Comment:
  • HTML Syntax: Allowed