hirondelle.web4j.model
Class ModelFromRequest

Since HTTP is entirely textual, the problem always arises in a web application of
building Model Objects (whose constructors may take arguments of any type) out of
the text taken from HTTP request parameters. (See the hirondelle.web4j.database
package for the similar problem of translating rows of a ResultSet into a Model Object.)

Somewhat surprisingly, some web application frameworks do not assist the programmer
in this regard. That is, they leave the programmer to always translate raw HTTP request
parameters (Strings) into target types (Integer, Boolean,
etc), and then to in turn build complete Model Objects. This usually results in
much code repetition.

This class, along with implementations of ConvertParam and RequestParser,
help an Action build a Model Object by defining such "type translation"
policies in one place.

Example use case of building a 'Visit' Model Object out of four
RequestParameter objects (ID, RESTAURANT, etc.):

The order of the sequence params passed to build(Class, Object...)
must match the order of arguments passed to the Model Object constructor.
This mechanism is quite effective and compact.

The sequence parameters passed to build(Class, Object...) need not be a RequestParameter.
They can be any object whatsoever. Before calling the Model Object constructor, the sequence
parameters are examined and treated as follows :

if the item is not an instance of RequestParameter
- do not alter it in any way
- it will be passed to the MO ctor 'as is'
else
- fetch the corresponding param value from the request
- attempt to translate its text to the target type required
by the corresponding MO ctor argument, using policies
defined by RequestParser and ConvertParam
if the translation attempt fails
- create a ModelCtorException

If no ModelCtorException has been constructed, then the MO constructor is
called using reflection. Note that the MO constructor may itself in turn throw
a ModelCtorException.
In fact, in order for this class to be well-behaved, the MO
constructor cannot throw anything other than a ModelCtorException as part of
its contract. This includes
RuntimeExceptions. For example, if a null is not permitted
by a MO constructor, it should not throw a NullPointerException (unchecked).
Rather, it should throw a ModelCtorException (checked). This allows the caller to
be notified of all faulty user input in a uniform manner. It also makes MO constructors
simpler, since all irregular input will result in a ModelCtorException, instead
of a mixture of checked and unchecked exceptions.

This unusual policy is related to the unusual character of Model Objects,
which attempt to build an object out of arbitrary user input.
Unchecked exceptions should be thrown only if a bug is present.
However, irregular user input is not a bug.

When converting from a RequestParameter into a building block class,
this class supports only the types supported by the implementation of ConvertParam.

In summary, to work with this class, a Model Object must :

be public

have a public constructor, whose number of arguments matches the number of Object[] params
passed to build(Class, Object...)

the constructor is allowed to throw only ModelCtorException - no
unchecked exceptions should be (knowingly) permitted

aCandidateArgs - represents the ordered list of items to be passed
to the Model Object's constructor, and can contain null elements. Usually contains RequestParameter
objects, but may contain objects of any type, as long as they are expected by the target Model Object constructor.

Throws:

ModelCtorException - if either an element of aCandidateArgs
cannot be translated into the target type, or if all such translations succeed,
but the call to the MO constructor itself fails.