Injection
Injection is the process of setting action object properties from
various scopes. Similarly, outjection is the process of setting
attributes of various scopes with values of action object properties.
Injection is usually executed by some interceptor (such:
ServletConfigInterceptor
) before action method invocation, while
outjection is executed after the invocation, before result rendering.
Injection and outjection is performed by so-called injectors. Injectors are simple Java classes that contains all necessary logic, usually for single scope.
All injectors scan action object for injection points. Injection point
is a spot annotated with @In
and/or @Out
annotations. There are
three possible spots that can be an injection point:
- object property - you can put annotation either on just field or on access method (getter/setter). It is a good practice to just annotate the fields, to keep the action class small and clean.
- inner class property - you can group your injection properties into inner classes, and then use this class as action method argument. This approach make sense when your action class contains few action methods and each one has a lot of properties to process. btw, it does not have to be an inner class, but its the best practice.
- action method arguments - and finally, you can annotate method arguments. This way your action method is complete handler. However, this approach has few drawbacks, more on that later.
Since this is just a matter of semantics, we will discuss these little bit later.
Scopes
Madvoc recognize following scopes:
ScopeType.REQUEST
- HTTP request scope: request attributes and parameters. Madvoc detects multi-part requests and encapsulates uploaded files.ScopeType.SESSION
- HTTP session scope: session attributes.ScopeType.APPLICATION
- servlet context scope.ScopeType.SERVET
- special scope for injecting servlet-related objects (request, session…). Servlet objects may be used directly or via map adapter.ScopeType.CONTEXT
- special scope for injecting Madvoc components.
@In
Properties annotated with @In
annotation are marked as injection
targets. This annotation has the following elements:
value
- name of scope value, if different then property name;scope
- indicates the scope, default isScopeType.REQUEST
.
Example:
@MadvocAction public class HelloAction { @In MutableInteger data; @In private String name; public void setName(String name) { this.name = name + "xxx"; } @Action public void world() { } }
Above code shows several injection features. First, property 'data' is
defined just as class field (no setter/getter). Then, it shows that
Madvoc performs implicit type conversion to the target type. This is
done using BeanUtil
, Madvocs bean manipulator.
Then, second property shows how its setter will be invoked during the
injection and will change the injection value.
Entity mapping
Very often input forms matches entities (aka domain objects, dto objects, entity beans…). Madvoc offers easy way to map input parameters to entity objects.
For example, some POJO object Person
has simple properties: name, data
etc. Now, there is a form where application user enters data for the
person. If the form input fields are named in the following way:
<form action="..."> name: <input type="text" name="p.name"><br> data: <input type="text" name="p.data"><br> <input type="submit"> </form>
Request parameters p.name
and p.data
may be mapped in the
following way:
@MadvocAction public class HelloAction { @In("p") Person person; @Action public void world() { } }
Request injectors will create a new instance of Person
(since create
element of @In
is true
by default) and inject values for name and
data properties. Of course, in the real life, input fields would be
named more meaningfully as 'person.xxx' instead of 'p.xxx'.
Entity list mapping
Madvoc offers way to map list of entity data in similar manner. For
example, some input form may contain list of Person
objects, where
each person element is named as: 'ppp[index].xxx':
<form action="..."> name 1: <input type="text" name="ppp[0].name"><br> data 1: <input type="text" name="ppp[0].data"><br> name 2: <input type="text" name="ppp[1].name"><br> data 2: <input type="text" name="ppp[1].data"><br> ... <input type="submit"> </form>
This form may be mapped in the several ways:
@MadvocAction public class HelloAction { @In("ppp") List<Person> plist; @In("ppp") Person[] parray; @In("ppp") Map<String, Person> pmap; @Action public void world() { } }
Madvoc recognizes correct type from generics declaration! Of course, in the real-life, input fields would be named more meaningfully as 'person.xxx' instead of 'ppp.xxx'.
Context and Servlet scope
Madvoc context and servlet scope are special scopes. Their purpose is to provide special data to the action object. It allows to inject the following:
- servlet objects: when
@In
property is type ofHttpServletRequest
,HttpSession
,ServletContext
. Property name is ignored, just property type is considered. - adapter map for servlet objects: when
@In
property is named as:requestMap
,sessionMap
orcontextMap
, corresponding map adapter will be injected in the property. Of course, it is expected that property type isMap
. - Madvoc components: it is possible to inject any of registered internal Madvoc components.
Example:
@MadvocAction public class MiscAction { @In(scope = ScopeType.SERVLET) Map<String, Object> sessionMap; @In(value="requestMap", scope = ScopeType.SERVLET) Map<String, Object> rmap; @In(scope = ScopeType.SERVLET) Map<String, Object> contextMap; @In(scope = ScopeType.SERVLET) HttpServletResponse servletResponse; ...
Results & Injectors
Injection is performed not only on action objects, but on results
handlers and injectors. Both results and injectors are instantiated
lazy, on their first usage. After the instantiation, Madvoc controller
will perform the injection, but only for APPLICATION
and CONTEXT
scopes.
@Out
Similar as for injection, @Out
annotation is used on action object
properties that has to be outjected to the scopes.
@InOut
Just a shortcut for both @In
and @Out
annotations. May be useful
when property name differs from scope value name.
Injection points in inner classes
When your action has more then one action method, the number of @In
and @Out
properties may be big, and usually, some fields are shared for both methods.
Such action class does not look pretty and you might loose a track what
is injected/outjected for each action method.
For this reason, Madvoc supports to group @In
and @Out
properties into
separated classes that will be parameter(s) for action method. In other words,
you may do the following refactoring, from this:
@MadvocAction public class MyAction { @In String one; @Out int two; ... public void view() {} }
to this:
@MadvocAction public class MyAction { class ViewData { @In String one; @Out int two; ... } public void view(ViewData viewData) {} }
We just made an inner class that simply groups parameters of one action method. This way you can separate input and outputs between action methods in the same action class.
You may have more the one action method parameter. And you can use inner classes or static classes, or even separate classes for grouping parameters.
Injection points as action method parameters
Finally, you can use action method parameters as injection points. Example from above:
@MadvocAction public class MyAction { @In String one; @Out int two; ... public void view() {} }
can be written as:
@MadvocAction public class MyAction { public void view( @In String one, @Out MutableInteger two) {} }
To have this approach working fine, you should have jodd-proxetta module in the project. It is needed to resolve parameter names as this can't be done using reflection. Otherwise, you would need to explicitly set the names of parameters in the annotations.
There is one more thing to be careful with: you can't use
immutable classes as output injection points. For example,
you can't outject int
or a String
. All objects have to
be created before method is called, so any change after
is simply not visible to outside of the method. Thats why
we had to use here MutableInteger
as we can change its value
during the method execution.