I'm thinking that FormAction is currently too limited. It only allows creation of one form object per action. My thought is that if using hibernate or another ORM tool what you want instead is multiple objects (one per each domain object) so that at the time you run the action the object graph will already be created and all you need to do is extract it from the context and use it to query or persist. This avoids the bulk of the work generally in actions to assemble domain objects.
So basically this is IoC for a scope object to either create object in scope and set properties, set property on object already in specified scope or add object to collection of an object already in specified scope.
Code:
<bean id="phoneBookInjector" class="spring.ContextInjector">
<property name="defaultAttributeSourceChain" value="parameter,request,flow,session,context"/>
<property name="defaultPopulation" value="true"/>
<property name="propertyAttributeResolvers">
<map>
<entry key="phoneNumber">
<bean class="spring.PortletAttributeResolver">
<property name="from" value="PHONE_NUMBER"/>
<property name="attributeSourceChain"
value="parameter,request,flow,session,context"/>
</bean>
</entry>
</map>
</property>
<property name="formObjectName" value="phoneBook"/>
<property name="formObjectClass" value="app.domain.PhoneBook"/>
<property name="formObjectScopeAsString" value="request"/>
<property name="validator">
<bean id="queryValidator" class="app.domain.PhoneBookValidator"/>
</property>
</bean>
<bean id="phoneBookInjector">
<property name="propertyResolver">
<map>
<entry key="phoneNumber">
<bean class="spring.PropertyResolver">
<property name="to" value="street">
<property name="from" value="STREET"/>
<property name="attributeSourceChain"
value="request"/>
</bean>
</entry>
</map>
</property>
<property name="formObjectName" value="phoneBook.addresses"/>
<property name="formObjectClass" value="app.domain.PhoneBook"/>
<property name="formObjectScopeAsString" value="request"/>
<property name="validator">
<bean id="queryValidator" class="app.domain.PhoneBookValidator"/>
</property>
</bean>
<bean id="app.phone.SavePhone"
class="org.springframework.web.flow.action.SavePhoneInjectionAction">
<property name="injectors">
<list>
<ref bean="phoneBookInjector"/>
<ref bean="phoneBookAddressInjector"/>
</list>
</proerty>
</bean>
Basically an explanation of the intended implementation is as follows.
The functionality of InjectionAction class is as follows:
1) In example action in flow SavePhone is implemented by SavePhoneInjectionAction which extends InjectionAction and probably extends FormAction (if FormAction is not deprecated)
2) It reads list of injectors in order and proccess them
The functionality of ContextInjector class is as follows:
1) instantiate formObjectClass in scope if it does not already exist.
2) for each property in class find a property resolver in following precedence
- a) an explicit PropertyResolver in propertyResolvers
b) a default PropertyResolver (which can be injected) if none specified and defaultPopulation is true
3) for each property instantiate PropertyResolver and
- a) inject defaultAttributeSourceChain if not already specified for the property resolver
b) inject property name as "to"
4) Once instantiated object has been populated, validate if necessary and then set formObjectName to point to object in the scope formObjectScopeAsString specified
5) If formObjectName in the form "phoneBook.addresses" and addresses is a collection then find phoneBook in the scope specified by formObjectScopeAsString and invoke add method to insert newly populated object in collection.
The functionality of PropertyResolver is as follows:
1) For each scope specified in attributeSourceChain, search in that scope for "from" name or "to" name if "from" not specified.
To retreive the object PhoneBook you would simply call:
Code:
PhoneBook phoneBook = (PhoneBook)context.getRequestScope().getAttribute("phoneBook");
and save it since it is already populated (both the properties and the associated addresses).
I am looking for feedback in the following categories:
1) Will this be as useful to you as it will be for me?
2) Does anyone have any feedback on the intended implementation (including improvements)?
3) Is anyone interested in implementing or helping with the intended implementation?