I have a custom interceptor. I would like this interceptor to run on all action invocations except a few. I would like to program this (for extendibility/clarity) rather than using if/else statements checking the action's name inside the interceptor's intercept() method itself.
I think it might be done with the "exclude method" capacities of Struts2, but I'm stuck with the exact details. I think my interceptor needs to extend the MethodFilterInterceptor, but it has 2 intercept methods and the API is not very helpful in saying what each should do:
protected abstract String doIntercept(ActionInvocation invocation)
Subclasses must override to implement the interceptor logic.
String intercept(ActionInvocation invocation)
Override to handle interception
You are thinking it the other way around:
instead of checking the Action name (or better, the instanceOf to check for a specific Action Interface) to see if it should do some business, simply tell that Action to use a different Interceptor Stack.
For example, you can say that your Custom Stack (the Stack containing your Interceptor) is the default (then applied to all actions), but that ActionA, ActionB and ActionX run with the DefaultStack...
Interceptors shouldn't extend ActionSupport, yuck. They're not actions.
Mark the actions it should (or should not) run for with an interface or annotation and check for that in the interceptor.
Related
I have prepare interceptor in use. In one action class, I have an action method named testSomething(), and I also have an action method named prepareTestSomething().
The problem I'm facing here is that the prepare interceptor would invoke the prepareTestSomething() action method as if it was a preparing method for testSomething(), in which case it is not.
Is there a way to make the prepare interceptor to skip the invocation for certain action methods? Like for validation interceptor, we can use "excludeMethods" parameter.
Prepending the prepare word to an Xxx method is the Struts2 convention to tell the framework that it is the prepare() method for the Xxx action method. From the docs:
if the action class have prepare{MethodName}(), it will be invoked
Instead of doing other voodoos (like excluding methods) in order to make this voodoo work, simply change the method name, it is the only right way to go.
Call it initTestSomething(), initializeTestSomething(), preparzTestSomething()... whatever; but please, don't use a convention trying to make it work for something else. It is just... wrong.
In Spring MVC, Inside a Controller class, the method annotated with #RequestMapping annotation are allowed to have Flexible Method Signature.
If I want to do something like this with my own custom annotation, Can somebody give me some pointers for the same.
Thanks in Advance.
Spring MVC has a lot of features in that regard so it might be easier to look elsewhere as a starting point. The new messaging abstraction that was introduced in Spring 4 has similar features.
Look at #MessageMapping which allows you to build a flexible signature against a Message instance. You could for instance inject a header of the message
public void foo(#Header("myHeader") int myHeader)
Or you could validate that the payload against a Validator
public void bar(#Payload #Validated Order order)
The core of the infrastructure is located in InvocableHandlerMethod which is going to invoke a java.lang.reflect.Method you have provided on a given bean instance based on an incoming Message and additional parameters you may provide (see public final Object invoke(Message<?> message, Object... providedArgs)
To create that instance, you need to provide a set of HandlerMethodArgumentResolver. Each HandlerMethodArgumentResolver is responsible to handle a method parameter. In short, that's basically going to provide you a MethodParameter instance (i.e. a reference to a parameter of the method you want to handle, such as the annotated order in the last example) and you're going to tell if you support it or not and when you do, handle that parameter so that the right value is injected. For the header example, the implementation looks for a header with the name on the annotation. Simple!
A set of default resolvers are created for example in SimpAnnotationMethodMessageHandler (look at initArgumentResolvers). That's going to show you the kind of parameters you can inject there by default. By extending that list (or providing custom instances) you can augment what the user can use in the method signature.
In Spring 4.1, we rely on this infrastructure to provide JMS listener annotated endpoints and those endpoints may have a flexible signature as well. It's actually already implemented so you may want to have a look to that for yet another example.
I have a -validation.xml file to check if the fields of the form are empty and that kind of simple validation. I also have a validate() method (extended from ActionSupport) to check more complicated things. But when I send the form it checks the method before the XML file, so if the fields are empty a NullPointerException appears. At least that's what I think is happening.
So my question is, is there a way to change the order of the validation, so the XML is checked before the method?
EDIT: I had the idea of checking if the String is not null in the validate() method so I can avoid the problem, but I don't think that's the wisest thing to do.
The interceptor does check XML first, but IIRC doesn't stop validation if it find errors. I believe I have a patch for this, controlled with a flag.
I've solved this before by checking for errors in the validate method and not proceeding if errors existed.
The order is always one, that is hardcoded order.
The process of validation is performed by the ValidationInterceptor class (at least version 2.3.8).
This interceptor runs the action through the standard validation framework, which in turn checks the action against any validation rules (found in files such as ActionClass-validation.xml) and adds field-level and action-level error messages (provided that the action implements ValidationAware). This interceptor is often one of the last (or second to last) interceptors applied in a stack, as it assumes that all values have already been set on the action.
This interceptor does nothing if the name of the method being invoked is specified in the excludeMethods parameter. excludeMethods accepts a comma-delimited list of method names. For example, requests to foo!input.action and foo!back.action will be skipped by this interceptor if you set the excludeMethods parameter to "input, back".
The workflow of the action request does not change due to this interceptor. Rather, this interceptor is often used in conjunction with the workflow interceptor.
NOTE: As this method extends off MethodFilterInterceptor, it is capable of deciding if it is applicable only to selective methods in the action class. See MethodFilterInterceptor for more info.
First, it checks if the declarative validation is enabled and do it, then it checks if programmatic validation is enabled and do it.
You can turn on/off each type of validation via the interceptor parameters.
Interceptor parameters:
alwaysInvokeValidate - Defaults to true. If true validate() method will always be invoked, otherwise it will not.
programmatic - Defaults to true. If true and the action is Validateable call validate(), and any method that starts with "validate".
declarative - Defaults to true. Perform validation based on xml or annotations.
We have Interceptor, we have custom interceptor where we can do all that we want to do before or after our action executes.
Then what is the need to use Preparable interface and implement prepare method for it?
Is this another option or there is some specific aim to do like that?
Well Preparable interface act in conjunction with Prepare Interceptor.This interface has one method defined prepare() and as its name suggest this method is responsible to allow the action to prepare itself.
Prepare interceptor calls prepare() on actions which implement Preparable. This interceptor is very useful for any situation where you need to ensure some logic runs before the actual execute method runs.So if you see this is some kind if init for your action class and it makes sure that before the Action's execute or any other method get called, this method prepare your execute method to work fine.
If you see the default-stack define in core, you will come to know that this interceptor is being called before params or workflow interceptor which indicates its purpose.
A typical use of this is to run some logic to load an object from the database so that when parameters are set they can be set on this object. For details read the doc of Prepare interceptor for details how it work closely with Preparable interface.In short Prepare interceptor will come in to act only when action implements Preparable.
Prepare-Interceptor
Prepare interface assures that if object in use is already on value stack then no need to query database it populates form properties using existing object on value stack.
Im new to Struts2.... I have some few doubts below...
a) In Struts2, how does application finds struts.xml?? (we don't define struts.xml in web.xml file unlike in Struts1 which we define struts-config.xml in web.xml file, so how its going to see that struts.xml file)
b) why dont we write extends ActionSupport for our Action class.. I have seen many examples without extending with any other predefined Action class.. How does it find execute() method or populate() method in our Action class if we dont extend any other predefined action class or implement Action interface methods ??
c) In what cases we use extends Action Support
a) If you don't override the configuration file name ("config" parameter to the Struts filter in web.xml), then it will default to "struts.xml". This is simply a hard-coded default, hence "configuration by convention".
b) The framework allows "plain old java objects" (POJOs) for actions. Just tell it what method to call (in struts.xml), and it will use reflection to find such a method (must be no-args and return a String) and call it. On the other hand, some interfaces are used for additional functionality, for example if your class implements Preparable then the prepare() method will automatically be called prior to execution (perhaps probably similar to "populate" in Struts1?)
c) Extending ActionSupport is entirely optional, but gives access to some functionality that might be useful, such as default implementations for some action methods such as "input", convenient methods for internationalization, etc.
+1 to Todd's answer.
To b) : notice that there is no need to specify a method (though one can do it), by default ("convention") the execute() method will be called.
To c) : extending ActionSupport is optional, and IMO quite frequent. Sometimes it's also advisable to implement your own (say) BaseAction (which frequently extends ActionSupport) to factor out the common functionality of your webapp, and make all (or nearly all) your actions extend it.