Typical problem with web applications is update of (domain) objects. It is done in two steps: the first is presenting HTML form with only editable properties of an object, and, the second, is the actual update when form is submitted. The problem is that on submission in second step we must be aware of what object's properties to update.
The obvious solution is to put values of all non-editable object properties in the form using hidden input fields. Some web framework then would inject all those values into an empty domain object and it becomes ready for actual update.
However, this problem has its disadvantageous: values of all object properties should be presented in the form, hidden or not. Not only that this makes forms bigger and increases amount of posted (and sent) data, slows down the runtime and development time (all hidden values has to be properly encoded, too), but it also reduces the maintainability, since every time a property is changed, added or removed from the object, all forms where object is used have to be manually updated.
Madvoc offers another approach for this problem: to run some logic to load an object from the database, so that when parameters are set they can be set on this object. This may be done by using PrepareInterceptor before ServletConfigInterceptor. During action preparation object would be loaded from the database and after parameters will be injected in the loaded object.
First (good) consequence is that usually, there is no need for extra code in action method for viewing the form. Second (bad) consequence is that prepare() needs ID parameters to load object from database. Hopefully, Madvoc saves from getting IDs from parameters manually: IdRequestInjectorInterceptor. It simply injects only parameters that ends with ".id"!
There is one more (and last) caveat: we have to be sure that empty request parameters are not ignored. By default, everything is ok, empty parameters are not ignored. Anyhow, this can be set by setting Madvoc parameter: injectorsManager.requestScopeInjector.ignoreEmptyRequestParams.
It is all about the interceptors. Default interceptors stack:
public class AppInterceptorStack extends ActionInterceptorStack {
public AppInterceptorStack() {
super(
IdRequestInjectorInterceptor.class,
PrepareInterceptor.class,
ServletConfigInterceptor.class
);
}
}Here is the most interesting part of an action from web application that uses Madvoc, Spring and Hibernate.
@MadvocAction
@InterceptedBy(AppInterceptorStack.class)
public class BankEditAction implements Preparable {
@Inject
BankService bankService; // injected by spring, on action creation, before injections
@In @Out
Bank bank;
@Override
public void prepare() {
bank = bankService.findBankById(bank); // returns null if entity is null
}
@Action
public void view() {}
@Action
public Object store() {
// validate somehow
bankService.storeBank(bank); // merge it by hibernate
return OK;
}
}Plain and simple. The same action is used both for creating new or updating existing banks. Next example is more complicated: it is a form where user enters employee data and where it assigns a client to which employee belongs.
@MadvocAction
@InterceptedBy(AppInterceptorStack.class)
public class EmployeeEditAction implements Preparable {
@Inject
ClientService clientService; // injected by spring
@In @Out
Employee employee;
@In @Out
Client client;
@Override
public void prepare() {
employee = clientService.findEmployeeById(employee);
if (client == null) {
// reads client from current employee, if exist
client = employee != null ? employee.getClient() : null;
} else {
client = clientService.findClientById(client);
}
}
@Action
public void view() {}
@Action
public Object store() {
// validate somehow
employee.setClient(client); // set employee's client
clientService.storeEmployee(employee);
return OK;
}
}