RequestParameters (or any object) using a sequence (varargs) fVisit = builder.build(Visit.class, ID, RESTAURANT, LUNCH_DATE, MESSAGE); } catch (ModelCtorException ex){ addError(ex); } }
The order of the sequence params passed to {@link #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 {@link #build(Class,Object)} need not be a {@link 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 {@link 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 {@link hirondelle.web4j.request.RequestParameter} into a building block class, this class supports only the types supported by the implementation of {@link 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 {@link #build(Class,Object)}
- the constructor is allowed to throw only {@link hirondelle.web4j.model.ModelCtorException} - no unchecked exceptions should be (knowingly) permitted