|
From: Dirk M. <pos...@gm...> - 2005-01-27 07:12:46
|
Hello Drew,
this all sounds *very* good. I would like this to be a core part of
spring.
Do you already distribute your configurer somewhere? I would like to
use it right now :-)
Wednesday, January 26, 2005, 9:06:47 PM, you wrote:
DD> I wrote an OGNL-based property configurer (BeanFactoryPostProcessor
DD> implementor) that evaluates OGNL expressions in <value>, <map> and
DD> <list> entries, etc.
DD> It is similar in spirit to the PropertyPlaceholderConfigurer in that is
DD> substitutes values during the post processing phase. It looks for
DD> values delimitted by :[ and ] and processes them as OGNL expressions,
DD> which return a value.
DD> Advantages of OGNL expressions in Spring configurations:
DD> * Reference static members of classes directly (great for setting
DD> values from "static final int" constants):
DD> <property name="aConstValue"><value>:[
DD> @org.ognl.SomeClass@CONSTANT_VALUE ]</value>
DD> * Access Java data structures (and Collections) more easily than in
DD> Spring. Here are some examples, but I can't do justice to the amount of
DD> data structure manipulation possibilities in OGNL in this small space:
DD> - Create a Map:
DD> #{
DD> "name": "MyName",
DD> "description:" "This is a description of myName"
DD> }
DD> - Create a List of Strings:
DD> { "one", "two", "three" }
DD> - Create a List, filtered for certain elements:
DD> #someObjectInContext.items.{? name.startsWith("foo") }
DD> * Call methods on any object reachable by the bean factory
DD> * Reference and navigate other objects in the factory by name
DD> Example from my commerce library of configuring a factory that produces
DD> OrderQueryCriteria objects. These objects have setup requiring bindings
DD> to helper objects (OrderStatus is a custom enumerated type, SortOrdering
DD> is similar to Hibernate's Order class but slightly different usage
DD> pattern). One way to do this is to change the objects to take
DD> primitive-based setters and getters to construct these, or to complexify
DD> the Spring configuration file to provide these objects through
DD> factories, etc. I tried that and the config file was a bit heavy with
DD> "noise" due to the number of custom classes I needed just to get to
DD> static members, constructors, etc.
DD> public class OrderQueryCriteria extends AbstractQueryCriteria
DD> {
DD> ...
DD> public List getOrderStatus()
DD> {
DD> return orderStatus;
DD> }
DD> public void setOrderStatus(List value)
DD> {
DD> orderStatus = value;
DD> }
DD> public SortOrdering getPrimaryOrdering()
DD> {
DD> return primaryOrdering;
DD> }
DD> public void setPrimaryOrdering(SortOrdering value)
DD> {
DD> primaryOrdering = value;
DD> }
DD> public int getPageSize()
DD> {
DD> return pageSize;
DD> }
DD> public void setPageSize(int value)
DD> {
DD> pageSize = value;
DD> }
DD> }
DD> applicationContext-dao.xml:
DD> <bean id="orderQueryCriteria"
DD> class="org.ognl.dao.OrderQueryCriteria" singleton="false" autowire="byName">
DD> <property name="orderStatus"><value>:[
DD> @EnumeratedType@getFactory(@OrderStatus@class).instances.{ #this }
DD> ]</value></property>
DD> <property name="primaryOrdering"><value>:[ new
DD> SortOrdering('orderDate', @SortOrdering@DESCENDING) ]</value></property>
DD> <property name="pageSize"><value>10</value></property>
DD> </bean>
DD> EnumeratedType is an abstraction for managing enumerated type objects.
DD> It allows you to get lists of instances and manages indexing the
DD> enumerations by other properties as well. Access is through static
DD> factory that implements the getInstances() method.
DD> orderStatus is a List of OrderStatus objects. To construct this we need
DD> to get the List from the EnumeratedType's factory and get a copy of the
DD> list that is returned (the copy is done by "projecting" the instances
DD> list via { #this }, which creates a new List as a result).
DD> primaryOrdering is a SortOrdering object that has an Object "target" and
DD> an ordering value (ASCENDING, DESCENDING or NONE). Note here that we
DD> are constructing this object using it's own static constant fields.
DD> The above code is accessing SortOrdering, EnumeratedType, and
DD> OrderStatus without any package specifications, you may note. This
DD> works here because the processor is looking for beans of type
DD> ognl.ClassResolver to use to resolve class names to actual Class
DD> objects. I've written an ImportClassResolver that is configured thus:
DD> <!-- id does not matter; only the fact that it exists in the context -->
DD> <bean id="imports"
DD> class="org.ognl.spring.config.ImportClassResolver">
DD> <property name="imports">
DD> <list>
DD> <value>org.ognl.util.*</value>
DD> <value>org.ognl.model.shop.*</value>
DD> <value>org.ognl.pager.*</value>
DD> </list>
DD> </property>
DD> </bean>
DD> You can define as many of these as you like and they do inherit.
DD> Another feature is that the OGNL "context" object allows access to the
DD> rest of the Spring applicationContext through OGNL's "context variable"
DD> syntax.
DD> In the above code you saw reference to "#this" - this is the implicit
DD> value of the current object of the navigation; also available is #root
DD> (the original root object of the expression). This syntax also is used
DD> to access other elements in the context:
DD> <!-- a ListFactory produces, as the result of the factory, a List
object -->>
DD> <bean id="itemSortProperties"
DD> class="org.ognl.spring.config.ListFactory">
DD> <property name="list">
DD> <value>:[
DD> {
DD> #{ "name": "Item #",
DD> "property": "itemNumber",
DD> "advanced": false
DD> },
DD> #{ "name": "Name",
DD> "property": "name",
DD> "advanced": false
DD> },
DD> #{ "name": "Categorization",
DD> "property": { "product.category.name",
DD> "product.name" },
DD> "advanced": false
DD> },
DD> }
DD> ]</value>
DD> </property>
DD> </bean>
DD> <bean id="itemQueryCriteria"
DD> class="org.ognl.dao.ItemQueryCriteria"
DD> singleton="false" autowire="byName">
DD> ...
DD> <property name="primaryOrdering"><value>:[
DD> new SortOrdering(#itemSortProperties.{? name ==
DD> "Categorization" }[^].property, @SortOrdering@ASCENDING)
DD> ]</value></property>
DD> <property name="secondaryOrdering"><value>:[
DD> new SortOrdering(#itemSortProperties.{? name == "Item #"
DD> }[^].property, @SortOrdering@ASCENDING)
DD> ]</value></property>
DD> <property name="tertiaryOrdering"><value>:[
DD> new SortOrdering(#itemSortProperties.{? name == "Name"
DD> }[^].property, @SortOrdering@ASCENDING)
DD> ]</value></property>
DD> <property name="pageSize"><value>10</value></property>
DD> </bean>
DD> The above configures a List of Map objects, each of which has a "name",
DD> "property" and "advanced" key/value pair. The itemQueryCriteria object
DD> is configured from this list by referencing the other bean via
DD> "#itemSortProperties". Each of these uses the selection syntax to get a
DD> specific item out of the list, then the dynamic subscript "[^]" to
DD> return the first item of the list.
DD> You can also navigate through other objects in the context for other
DD> purposes such as mirroring another configuration value:
DD> <bean id="myObject" class="...">
DD> <property name="foo"><value>1254</value></property>
DD> ...
DD> </bean>
DD> <bean id="otherObject" class="...">
DD> <property name="bar"><value>:[ #myObject.foo ]</value></property>
DD> </bean>
DD> This can help cut down on error where properties are used repetitively.
DD> I'm not sure how I should distribute the source to this or if the
DD> project takes contributions. The code has a dependency on OGNL 2.6.3
DD> and above (1 jar file of ~185k). Is there a contribution mechanism that
DD> I can use to put instructions for use, the jar and the source up somewhere?
DD> - Drew
--
Best regards,
Dirk Markert
|