|
From: Drew D. <dr...@og...> - 2005-01-26 20:06:54
|
I wrote an OGNL-based property configurer (BeanFactoryPostProcessor
implementor) that evaluates OGNL expressions in <value>, <map> and
<list> entries, etc.
It is similar in spirit to the PropertyPlaceholderConfigurer in that is
substitutes values during the post processing phase. It looks for
values delimitted by :[ and ] and processes them as OGNL expressions,
which return a value.
Advantages of OGNL expressions in Spring configurations:
* Reference static members of classes directly (great for setting
values from "static final int" constants):
<property name="aConstValue"><value>:[
@org.ognl.SomeClass@CONSTANT_VALUE ]</value>
* Access Java data structures (and Collections) more easily than in
Spring. Here are some examples, but I can't do justice to the amount of
data structure manipulation possibilities in OGNL in this small space:
- Create a Map:
#{
"name": "MyName",
"description:" "This is a description of myName"
}
- Create a List of Strings:
{ "one", "two", "three" }
- Create a List, filtered for certain elements:
#someObjectInContext.items.{? name.startsWith("foo") }
* Call methods on any object reachable by the bean factory
* Reference and navigate other objects in the factory by name
Example from my commerce library of configuring a factory that produces
OrderQueryCriteria objects. These objects have setup requiring bindings
to helper objects (OrderStatus is a custom enumerated type, SortOrdering
is similar to Hibernate's Order class but slightly different usage
pattern). One way to do this is to change the objects to take
primitive-based setters and getters to construct these, or to complexify
the Spring configuration file to provide these objects through
factories, etc. I tried that and the config file was a bit heavy with
"noise" due to the number of custom classes I needed just to get to
static members, constructors, etc.
public class OrderQueryCriteria extends AbstractQueryCriteria
{
...
public List getOrderStatus()
{
return orderStatus;
}
public void setOrderStatus(List value)
{
orderStatus = value;
}
public SortOrdering getPrimaryOrdering()
{
return primaryOrdering;
}
public void setPrimaryOrdering(SortOrdering value)
{
primaryOrdering = value;
}
public int getPageSize()
{
return pageSize;
}
public void setPageSize(int value)
{
pageSize = value;
}
}
applicationContext-dao.xml:
<bean id="orderQueryCriteria"
class="org.ognl.dao.OrderQueryCriteria" singleton="false" autowire="byName">
<property name="orderStatus"><value>:[
@EnumeratedType@getFactory(@OrderStatus@class).instances.{ #this }
]</value></property>
<property name="primaryOrdering"><value>:[ new
SortOrdering('orderDate', @SortOrdering@DESCENDING) ]</value></property>
<property name="pageSize"><value>10</value></property>
</bean>
EnumeratedType is an abstraction for managing enumerated type objects.
It allows you to get lists of instances and manages indexing the
enumerations by other properties as well. Access is through static
factory that implements the getInstances() method.
orderStatus is a List of OrderStatus objects. To construct this we need
to get the List from the EnumeratedType's factory and get a copy of the
list that is returned (the copy is done by "projecting" the instances
list via { #this }, which creates a new List as a result).
primaryOrdering is a SortOrdering object that has an Object "target" and
an ordering value (ASCENDING, DESCENDING or NONE). Note here that we
are constructing this object using it's own static constant fields.
The above code is accessing SortOrdering, EnumeratedType, and
OrderStatus without any package specifications, you may note. This
works here because the processor is looking for beans of type
ognl.ClassResolver to use to resolve class names to actual Class
objects. I've written an ImportClassResolver that is configured thus:
<!-- id does not matter; only the fact that it exists in the context -->
<bean id="imports" class="org.ognl.spring.config.ImportClassResolver">
<property name="imports">
<list>
<value>org.ognl.util.*</value>
<value>org.ognl.model.shop.*</value>
<value>org.ognl.pager.*</value>
</list>
</property>
</bean>
You can define as many of these as you like and they do inherit.
Another feature is that the OGNL "context" object allows access to the
rest of the Spring applicationContext through OGNL's "context variable"
syntax.
In the above code you saw reference to "#this" - this is the implicit
value of the current object of the navigation; also available is #root
(the original root object of the expression). This syntax also is used
to access other elements in the context:
<!-- a ListFactory produces, as the result of the factory, a List
object -->
<bean id="itemSortProperties"
class="org.ognl.spring.config.ListFactory">
<property name="list">
<value>:[
{
#{ "name": "Item #",
"property": "itemNumber",
"advanced": false
},
#{ "name": "Name",
"property": "name",
"advanced": false
},
#{ "name": "Categorization",
"property": { "product.category.name",
"product.name" },
"advanced": false
},
}
]</value>
</property>
</bean>
<bean id="itemQueryCriteria" class="org.ognl.dao.ItemQueryCriteria"
singleton="false" autowire="byName">
...
<property name="primaryOrdering"><value>:[
new SortOrdering(#itemSortProperties.{? name ==
"Categorization" }[^].property, @SortOrdering@ASCENDING)
]</value></property>
<property name="secondaryOrdering"><value>:[
new SortOrdering(#itemSortProperties.{? name == "Item #"
}[^].property, @SortOrdering@ASCENDING)
]</value></property>
<property name="tertiaryOrdering"><value>:[
new SortOrdering(#itemSortProperties.{? name == "Name"
}[^].property, @SortOrdering@ASCENDING)
]</value></property>
<property name="pageSize"><value>10</value></property>
</bean>
The above configures a List of Map objects, each of which has a "name",
"property" and "advanced" key/value pair. The itemQueryCriteria object
is configured from this list by referencing the other bean via
"#itemSortProperties". Each of these uses the selection syntax to get a
specific item out of the list, then the dynamic subscript "[^]" to
return the first item of the list.
You can also navigate through other objects in the context for other
purposes such as mirroring another configuration value:
<bean id="myObject" class="...">
<property name="foo"><value>1254</value></property>
...
</bean>
<bean id="otherObject" class="...">
<property name="bar"><value>:[ #myObject.foo ]</value></property>
</bean>
This can help cut down on error where properties are used repetitively.
I'm not sure how I should distribute the source to this or if the
project takes contributions. The code has a dependency on OGNL 2.6.3
and above (1 jar file of ~185k). Is there a contribution mechanism that
I can use to put instructions for use, the jar and the source up somewhere?
- Drew
--
+---------------------------------+
< Drew Davidson | OGNL Technology >
+---------------------------------+
| Email: dr...@og... /
| Web: http://www.ognl.org /
| Vox: (520) 531-1966 <
| Fax: (520) 531-1965 \
| Mobile: (520) 405-2967 \
+---------------------------------+
|
|
From: jbetancourt <jbe...@co...> - 2005-01-27 01:16:43
|
I am using OGNL in conjunction with Spring. I will be publishing something
soon on this.
OGNL is really great!
----- Original Message -----
From: "Drew Davidson" <dr...@og...>
To: <spr...@li...>
Sent: Wednesday, January 26, 2005 3:06 PM
Subject: [Springframework-developer] OGNL property configurer bean factory
post-processor
> I wrote an OGNL-based property configurer (BeanFactoryPostProcessor
> implementor) that evaluates OGNL expressions in <value>, <map> and
> <list> entries, etc.
>
> It is similar in spirit to the PropertyPlaceholderConfigurer in that is
> substitutes values during the post processing phase. It looks for
> values delimitted by :[ and ] and processes them as OGNL expressions,
> which return a value.
>
> Advantages of OGNL expressions in Spring configurations:
> * Reference static members of classes directly (great for setting
> values from "static final int" constants):
>
> <property name="aConstValue"><value>:[
> @org.ognl.SomeClass@CONSTANT_VALUE ]</value>
>
> * Access Java data structures (and Collections) more easily than in
> Spring. Here are some examples, but I can't do justice to the amount of
> data structure manipulation possibilities in OGNL in this small space:
>
> - Create a Map:
> #{
> "name": "MyName",
> "description:" "This is a description of myName"
> }
>
> - Create a List of Strings:
>
> { "one", "two", "three" }
>
> - Create a List, filtered for certain elements:
>
> #someObjectInContext.items.{? name.startsWith("foo") }
>
> * Call methods on any object reachable by the bean factory
>
> * Reference and navigate other objects in the factory by name
>
>
> Example from my commerce library of configuring a factory that produces
> OrderQueryCriteria objects. These objects have setup requiring bindings
> to helper objects (OrderStatus is a custom enumerated type, SortOrdering
> is similar to Hibernate's Order class but slightly different usage
> pattern). One way to do this is to change the objects to take
> primitive-based setters and getters to construct these, or to complexify
> the Spring configuration file to provide these objects through
> factories, etc. I tried that and the config file was a bit heavy with
> "noise" due to the number of custom classes I needed just to get to
> static members, constructors, etc.
>
> public class OrderQueryCriteria extends AbstractQueryCriteria
> {
> ...
>
> public List getOrderStatus()
> {
> return orderStatus;
> }
>
> public void setOrderStatus(List value)
> {
> orderStatus = value;
> }
>
> public SortOrdering getPrimaryOrdering()
> {
> return primaryOrdering;
> }
>
> public void setPrimaryOrdering(SortOrdering value)
> {
> primaryOrdering = value;
> }
>
> public int getPageSize()
> {
> return pageSize;
> }
>
> public void setPageSize(int value)
> {
> pageSize = value;
> }
> }
>
> applicationContext-dao.xml:
>
> <bean id="orderQueryCriteria"
> class="org.ognl.dao.OrderQueryCriteria" singleton="false"
autowire="byName">
> <property name="orderStatus"><value>:[
> @EnumeratedType@getFactory(@OrderStatus@class).instances.{ #this }
> ]</value></property>
> <property name="primaryOrdering"><value>:[ new
> SortOrdering('orderDate', @SortOrdering@DESCENDING) ]</value></property>
> <property name="pageSize"><value>10</value></property>
> </bean>
>
> EnumeratedType is an abstraction for managing enumerated type objects.
> It allows you to get lists of instances and manages indexing the
> enumerations by other properties as well. Access is through static
> factory that implements the getInstances() method.
>
> orderStatus is a List of OrderStatus objects. To construct this we need
> to get the List from the EnumeratedType's factory and get a copy of the
> list that is returned (the copy is done by "projecting" the instances
> list via { #this }, which creates a new List as a result).
>
> primaryOrdering is a SortOrdering object that has an Object "target" and
> an ordering value (ASCENDING, DESCENDING or NONE). Note here that we
> are constructing this object using it's own static constant fields.
>
> The above code is accessing SortOrdering, EnumeratedType, and
> OrderStatus without any package specifications, you may note. This
> works here because the processor is looking for beans of type
> ognl.ClassResolver to use to resolve class names to actual Class
> objects. I've written an ImportClassResolver that is configured thus:
>
> <!-- id does not matter; only the fact that it exists in the
context -->
> <bean id="imports" class="org.ognl.spring.config.ImportClassResolver">
> <property name="imports">
> <list>
> <value>org.ognl.util.*</value>
> <value>org.ognl.model.shop.*</value>
> <value>org.ognl.pager.*</value>
> </list>
> </property>
> </bean>
>
> You can define as many of these as you like and they do inherit.
>
> Another feature is that the OGNL "context" object allows access to the
> rest of the Spring applicationContext through OGNL's "context variable"
> syntax.
>
> In the above code you saw reference to "#this" - this is the implicit
> value of the current object of the navigation; also available is #root
> (the original root object of the expression). This syntax also is used
> to access other elements in the context:
>
> <!-- a ListFactory produces, as the result of the factory, a List
> object -->
> <bean id="itemSortProperties"
> class="org.ognl.spring.config.ListFactory">
> <property name="list">
> <value>:[
> {
> #{ "name": "Item #",
> "property": "itemNumber",
> "advanced": false
> },
> #{ "name": "Name",
> "property": "name",
> "advanced": false
> },
> #{ "name": "Categorization",
> "property": { "product.category.name",
> "product.name" },
> "advanced": false
> },
> }
> ]</value>
> </property>
> </bean>
>
>
> <bean id="itemQueryCriteria" class="org.ognl.dao.ItemQueryCriteria"
> singleton="false" autowire="byName">
> ...
> <property name="primaryOrdering"><value>:[
> new SortOrdering(#itemSortProperties.{? name ==
> "Categorization" }[^].property, @SortOrdering@ASCENDING)
> ]</value></property>
>
> <property name="secondaryOrdering"><value>:[
> new SortOrdering(#itemSortProperties.{? name == "Item #"
> }[^].property, @SortOrdering@ASCENDING)
> ]</value></property>
>
> <property name="tertiaryOrdering"><value>:[
> new SortOrdering(#itemSortProperties.{? name == "Name"
> }[^].property, @SortOrdering@ASCENDING)
> ]</value></property>
>
> <property name="pageSize"><value>10</value></property>
>
> </bean>
>
> The above configures a List of Map objects, each of which has a "name",
> "property" and "advanced" key/value pair. The itemQueryCriteria object
> is configured from this list by referencing the other bean via
> "#itemSortProperties". Each of these uses the selection syntax to get a
> specific item out of the list, then the dynamic subscript "[^]" to
> return the first item of the list.
>
> You can also navigate through other objects in the context for other
> purposes such as mirroring another configuration value:
>
> <bean id="myObject" class="...">
> <property name="foo"><value>1254</value></property>
> ...
> </bean>
>
> <bean id="otherObject" class="...">
> <property name="bar"><value>:[ #myObject.foo ]</value></property>
> </bean>
>
> This can help cut down on error where properties are used repetitively.
>
> I'm not sure how I should distribute the source to this or if the
> project takes contributions. The code has a dependency on OGNL 2.6.3
> and above (1 jar file of ~185k). Is there a contribution mechanism that
> I can use to put instructions for use, the jar and the source up
somewhere?
>
> - Drew
>
> --
> +---------------------------------+
> < Drew Davidson | OGNL Technology >
> +---------------------------------+
> | Email: dr...@og... /
> | Web: http://www.ognl.org /
> | Vox: (520) 531-1966 <
> | Fax: (520) 531-1965 \
> | Mobile: (520) 405-2967 \
> +---------------------------------+
>
>
>
> -------------------------------------------------------
> This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting
> Tool for open source databases. Create drag-&-drop reports. Save time
> by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc.
> Download a FREE copy at http://www.intelliview.com/go/osdn_nl
> _______________________________________________
> Springframework-developer mailing list
> Spr...@li...
> https://lists.sourceforge.net/lists/listinfo/springframework-developer
>
|
|
From: Drew D. <dr...@og...> - 2005-01-27 14:26:13
|
jbetancourt wrote: >I am using OGNL in conjunction with Spring. I will be publishing something soon on this. >OGNL is really great! > > Thanks! Could you provide some details on exactly how you are using it in conjunction with Spring? Do you mean using it within Spring constructs or do you just use OGNL and Spring? - Drew -- +---------------------------------+ < Drew Davidson | OGNL Technology > +---------------------------------+ | Email: dr...@og... / | Web: http://www.ognl.org / | Vox: (520) 531-1966 < | Fax: (520) 531-1965 \ | Mobile: (520) 405-2967 \ +---------------------------------+ |
|
From: jbetancourt <jbe...@co...> - 2005-01-28 00:24:03
|
I used OGNL and Spring. The ability to evoke method call expressions on a managed pojo via OGNL is pretty interesting. ----- Original Message ----- From: "Drew Davidson" <dr...@og...> To: <spr...@li...> Sent: Thursday, January 27, 2005 9:26 AM Subject: Re: [Springframework-developer] OGNL property configurer bean factory post-processor > jbetancourt wrote: > > >I am using OGNL in conjunction with Spring. I will be publishing something soon on this. > >OGNL is really great! > > > > > > Thanks! > > Could you provide some details on exactly how you are using it in > conjunction with Spring? Do you mean using it within Spring constructs > or do you just use OGNL and Spring? > > - Drew > > -- > +---------------------------------+ > < Drew Davidson | OGNL Technology > > +---------------------------------+ > | Email: dr...@og... / > | Web: http://www.ognl.org / > | Vox: (520) 531-1966 < > | Fax: (520) 531-1965 \ > | Mobile: (520) 405-2967 \ > +---------------------------------+ > > > > ------------------------------------------------------- > This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting > Tool for open source databases. Create drag-&-drop reports. Save time > by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc. > Download a FREE copy at http://www.intelliview.com/go/osdn_nl > _______________________________________________ > Springframework-developer mailing list > Spr...@li... > https://lists.sourceforge.net/lists/listinfo/springframework-developer > |
|
From: jbetancourt <jbe...@co...> - 2005-02-15 09:53:15
|
The article is now in JavaWorld, "Let your Ant enjoy Spring": http://www.javaworld.com/javaworld/jw-02-2005/jw-0214-antspring.html "Summary This article presents an Ant task extension that allows the invocation of an IoC (Inversion of Control) managed object or any unmanaged object. It also shows how OGNL (Object Graph Navigation Language) can be used to easily let Ant invoke any method expression, including those with runtime arguments. The use of JUnit to test the Ant extension is also illustrated. In addition, an implementation is shown using the Spring framework. The Ant-IoC combination opens up new possibilities for creating loosely coupled software development support tasks. (2,500 words; February 14, 2005) " Yup, I did not give a great 'definition' of stuff like IoC. Perhaps I'm a little rusty in the prose department. ----- Original Message ----- From: "Drew Davidson" <dr...@og...> To: <spr...@li...> Sent: Thursday, January 27, 2005 9:26 AM Subject: Re: [Springframework-developer] OGNL property configurer bean factory post-processor > jbetancourt wrote: > > >I am using OGNL in conjunction with Spring. I will be publishing something soon on this. > >OGNL is really great! > > > > > > Thanks! > > Could you provide some details on exactly how you are using it in > conjunction with Spring? Do you mean using it within Spring constructs > or do you just use OGNL and Spring? > > - Drew > > -- > +---------------------------------+ > < Drew Davidson | OGNL Technology > > +---------------------------------+ > | Email: dr...@og... / > | Web: http://www.ognl.org / > | Vox: (520) 531-1966 < > | Fax: (520) 531-1965 \ > | Mobile: (520) 405-2967 \ > +---------------------------------+ > > > > ------------------------------------------------------- > This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting > Tool for open source databases. Create drag-&-drop reports. Save time > by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc. > Download a FREE copy at http://www.intelliview.com/go/osdn_nl > _______________________________________________ > Springframework-developer mailing list > Spr...@li... > https://lists.sourceforge.net/lists/listinfo/springframework-developer > |
|
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
|
|
From: Drew D. <dr...@og...> - 2005-01-27 14:24:33
|
Dirk Markert wrote:
>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 :-)
>
>
It's now available at:
http://www.ognl.org/resources/ognl-spring.zip
- Drew
--
+---------------------------------+
< Drew Davidson | OGNL Technology >
+---------------------------------+
| Email: dr...@og... /
| Web: http://www.ognl.org /
| Vox: (520) 531-1966 <
| Fax: (520) 531-1965 \
| Mobile: (520) 405-2967 \
+---------------------------------+
|
|
From: Dirk M. <pos...@gm...> - 2005-01-28 06:43:58
|
Hello Drew, great. Thank you. Thursday, January 27, 2005, 3:24:26 PM, you wrote: DD> Dirk Markert wrote: >>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 :-) >> >> DD> It's now available at: DD> http://www.ognl.org/resources/ognl-spring.zip DD> - Drew -- Best regards, Dirk |
|
From: Rob H. <ro...@ca...> - 2005-01-27 08:50:03
|
Drew,
This sounds excellent - I would certainly like to include it in the main
Spring codebase. If everyone else is in agreement feel free to either
post this to JIRA or send it to me and I'll put it in the sandbox. I
think it would be really nice to get this up and running for the 1.2
release.
Alternatively, I wonder if it is about time we started a separate
project for Spring add-ons. Still underneath the Spring umberella, just
a separate project away from the core. This way we can keep the core
compact and free from clutter. Thoughts everyone?
Rob
Drew Davidson wrote:
> I wrote an OGNL-based property configurer (BeanFactoryPostProcessor
> implementor) that evaluates OGNL expressions in <value>, <map> and
> <list> entries, etc.
>
> It is similar in spirit to the PropertyPlaceholderConfigurer in that
> is substitutes values during the post processing phase. It looks for
> values delimitted by :[ and ] and processes them as OGNL expressions,
> which return a value.
>
> Advantages of OGNL expressions in Spring configurations:
> * Reference static members of classes directly (great for setting
> values from "static final int" constants):
>
> <property name="aConstValue"><value>:[
> @org.ognl.SomeClass@CONSTANT_VALUE ]</value>
>
> * Access Java data structures (and Collections) more easily than in
> Spring. Here are some examples, but I can't do justice to the amount
> of data structure manipulation possibilities in OGNL in this small space:
>
> - Create a Map:
> #{
> "name": "MyName",
> "description:" "This is a description of myName"
> }
>
> - Create a List of Strings:
>
> { "one", "two", "three" }
>
> - Create a List, filtered for certain elements:
>
> #someObjectInContext.items.{? name.startsWith("foo") }
>
> * Call methods on any object reachable by the bean factory
>
> * Reference and navigate other objects in the factory by name
>
>
> Example from my commerce library of configuring a factory that
> produces OrderQueryCriteria objects. These objects have setup
> requiring bindings to helper objects (OrderStatus is a custom
> enumerated type, SortOrdering is similar to Hibernate's Order class
> but slightly different usage pattern). One way to do this is to
> change the objects to take primitive-based setters and getters to
> construct these, or to complexify the Spring configuration file to
> provide these objects through factories, etc. I tried that and the
> config file was a bit heavy with "noise" due to the number of custom
> classes I needed just to get to static members, constructors, etc.
>
> public class OrderQueryCriteria extends AbstractQueryCriteria
> {
> ...
>
> public List getOrderStatus()
> {
> return orderStatus;
> }
>
> public void setOrderStatus(List value)
> {
> orderStatus = value;
> }
>
> public SortOrdering getPrimaryOrdering()
> {
> return primaryOrdering;
> }
>
> public void setPrimaryOrdering(SortOrdering value)
> {
> primaryOrdering = value;
> }
>
> public int getPageSize()
> {
> return pageSize;
> }
>
> public void setPageSize(int value)
> {
> pageSize = value;
> }
> }
>
> applicationContext-dao.xml:
>
> <bean id="orderQueryCriteria"
> class="org.ognl.dao.OrderQueryCriteria" singleton="false"
> autowire="byName">
> <property name="orderStatus"><value>:[
> @EnumeratedType@getFactory(@OrderStatus@class).instances.{ #this }
> ]</value></property>
> <property name="primaryOrdering"><value>:[ new
> SortOrdering('orderDate', @SortOrdering@DESCENDING) ]</value></property>
> <property name="pageSize"><value>10</value></property>
> </bean>
>
> EnumeratedType is an abstraction for managing enumerated type
> objects. It allows you to get lists of instances and manages indexing
> the enumerations by other properties as well. Access is through
> static factory that implements the getInstances() method.
>
> orderStatus is a List of OrderStatus objects. To construct this we
> need to get the List from the EnumeratedType's factory and get a copy
> of the list that is returned (the copy is done by "projecting" the
> instances list via { #this }, which creates a new List as a result).
>
> primaryOrdering is a SortOrdering object that has an Object "target"
> and an ordering value (ASCENDING, DESCENDING or NONE). Note here that
> we are constructing this object using it's own static constant fields.
>
> The above code is accessing SortOrdering, EnumeratedType, and
> OrderStatus without any package specifications, you may note. This
> works here because the processor is looking for beans of type
> ognl.ClassResolver to use to resolve class names to actual Class
> objects. I've written an ImportClassResolver that is configured thus:
>
> <!-- id does not matter; only the fact that it exists in the
> context -->
> <bean id="imports" class="org.ognl.spring.config.ImportClassResolver">
> <property name="imports">
> <list>
> <value>org.ognl.util.*</value>
> <value>org.ognl.model.shop.*</value>
> <value>org.ognl.pager.*</value>
> </list>
> </property>
> </bean>
> You can define as many of these as you like and they do inherit.
>
> Another feature is that the OGNL "context" object allows access to the
> rest of the Spring applicationContext through OGNL's "context
> variable" syntax.
>
> In the above code you saw reference to "#this" - this is the implicit
> value of the current object of the navigation; also available is #root
> (the original root object of the expression). This syntax also is
> used to access other elements in the context:
>
> <!-- a ListFactory produces, as the result of the factory, a List
> object -->
> <bean id="itemSortProperties"
> class="org.ognl.spring.config.ListFactory">
> <property name="list">
> <value>:[
> {
> #{ "name": "Item #",
> "property": "itemNumber",
> "advanced": false
> },
> #{ "name": "Name",
> "property": "name",
> "advanced": false
> },
> #{ "name": "Categorization",
> "property": { "product.category.name",
> "product.name" },
> "advanced": false
> },
> }
> ]</value>
> </property>
> </bean>
>
>
> <bean id="itemQueryCriteria" class="org.ognl.dao.ItemQueryCriteria"
> singleton="false" autowire="byName">
> ...
> <property name="primaryOrdering"><value>:[
> new SortOrdering(#itemSortProperties.{? name ==
> "Categorization" }[^].property, @SortOrdering@ASCENDING)
> ]</value></property>
>
> <property name="secondaryOrdering"><value>:[
> new SortOrdering(#itemSortProperties.{? name == "Item #"
> }[^].property, @SortOrdering@ASCENDING)
> ]</value></property>
>
> <property name="tertiaryOrdering"><value>:[
> new SortOrdering(#itemSortProperties.{? name == "Name"
> }[^].property, @SortOrdering@ASCENDING)
> ]</value></property>
>
> <property name="pageSize"><value>10</value></property>
>
> </bean>
>
> The above configures a List of Map objects, each of which has a
> "name", "property" and "advanced" key/value pair. The
> itemQueryCriteria object is configured from this list by referencing
> the other bean via "#itemSortProperties". Each of these uses the
> selection syntax to get a specific item out of the list, then the
> dynamic subscript "[^]" to return the first item of the list.
>
> You can also navigate through other objects in the context for other
> purposes such as mirroring another configuration value:
>
> <bean id="myObject" class="...">
> <property name="foo"><value>1254</value></property>
> ...
> </bean>
>
> <bean id="otherObject" class="...">
> <property name="bar"><value>:[ #myObject.foo ]</value></property>
> </bean>
>
> This can help cut down on error where properties are used repetitively.
>
> I'm not sure how I should distribute the source to this or if the
> project takes contributions. The code has a dependency on OGNL 2.6.3
> and above (1 jar file of ~185k). Is there a contribution mechanism
> that I can use to put instructions for use, the jar and the source up
> somewhere?
>
> - Drew
>
|
|
From: Colin S. <col...@ex...> - 2005-01-27 15:09:23
|
(I am starting to hate SourceForge intensely. I got 3 replies to Drew's
message, but not Drew's message Add to the the ongoing CVS issue for
the better part of 2 years now (which seem to have gotten worse, I
simply can't do a proper update without trying dozens of times) or the
last week's disk space problems. I guess we get what we pay for).
This code looks pretty interesting. I agree about it probably making
sense to include in Spring. Drew, do you have any feel for performance,
i.e. how big an impact there would be to using a lot of these
expressions in a config file? I'm also trying to get my head around how
this affects lifecycles and when initialization happens.
PropertyPlaceholderConfigurer is obviously pretty simplistic, all it's
going to do is replace a placehold value in a text property value with
another. It can't trigger the initialization of another bean. Now in
this OGNL variant, if the OGNL script references the context, then it
can trigger the initialization of other beans, similar in fashion to how
a <ref bean="xxx"> will trigger the init of that other bean first. Now
the difference here is that while the <ref bean=""> will trigger that
init only if used, since this approach is as a bean factory
postprocessor and all expressions are evaluated at init time, all
references beans will be immediately initialized at init time. For this
reason, while I think this is a valid approach, and has the advantage
that it doesn't require changes to the guts of Spring, I think there's
still added value in having the idea of expressions known to Spring
itself, which are only evaluated on demand... Possibly the 2nd step...
Colin
Rob Harrop wrote:
> Drew,
> This sounds excellent - I would certainly like to include it in the
> main Spring codebase. If everyone else is in agreement feel free to
> either post this to JIRA or send it to me and I'll put it in the
> sandbox. I think it would be really nice to get this up and running
> for the 1.2 release.
>
> Alternatively, I wonder if it is about time we started a separate
> project for Spring add-ons. Still underneath the Spring umberella,
> just a separate project away from the core. This way we can keep the
> core compact and free from clutter. Thoughts everyone?
>
> Rob
>
> Drew Davidson wrote:
>
>> I wrote an OGNL-based property configurer (BeanFactoryPostProcessor
>> implementor) that evaluates OGNL expressions in <value>, <map> and
>> <list> entries, etc.
>>
>> It is similar in spirit to the PropertyPlaceholderConfigurer in that
>> is substitutes values during the post processing phase. It looks for
>> values delimitted by :[ and ] and processes them as OGNL expressions,
>> which return a value.
>>
>> Advantages of OGNL expressions in Spring configurations:
>> * Reference static members of classes directly (great for setting
>> values from "static final int" constants):
>>
>> <property name="aConstValue"><value>:[
>> @org.ognl.SomeClass@CONSTANT_VALUE ]</value>
>>
>> * Access Java data structures (and Collections) more easily than
>> in Spring. Here are some examples, but I can't do justice to the
>> amount of data structure manipulation possibilities in OGNL in this
>> small space:
>>
>> - Create a Map:
>> #{
>> "name": "MyName",
>> "description:" "This is a description of myName"
>> }
>>
>> - Create a List of Strings:
>>
>> { "one", "two", "three" }
>>
>> - Create a List, filtered for certain elements:
>>
>> #someObjectInContext.items.{? name.startsWith("foo") }
>>
>> * Call methods on any object reachable by the bean factory
>>
>> * Reference and navigate other objects in the factory by name
>>
>>
>> Example from my commerce library of configuring a factory that
>> produces OrderQueryCriteria objects. These objects have setup
>> requiring bindings to helper objects (OrderStatus is a custom
>> enumerated type, SortOrdering is similar to Hibernate's Order class
>> but slightly different usage pattern). One way to do this is to
>> change the objects to take primitive-based setters and getters to
>> construct these, or to complexify the Spring configuration file to
>> provide these objects through factories, etc. I tried that and the
>> config file was a bit heavy with "noise" due to the number of custom
>> classes I needed just to get to static members, constructors, etc.
>>
>> public class OrderQueryCriteria extends AbstractQueryCriteria
>> {
>> ...
>>
>> public List getOrderStatus()
>> {
>> return orderStatus;
>> }
>>
>> public void setOrderStatus(List value)
>> {
>> orderStatus = value;
>> }
>>
>> public SortOrdering getPrimaryOrdering()
>> {
>> return primaryOrdering;
>> }
>>
>> public void setPrimaryOrdering(SortOrdering value)
>> {
>> primaryOrdering = value;
>> }
>>
>> public int getPageSize()
>> {
>> return pageSize;
>> }
>>
>> public void setPageSize(int value)
>> {
>> pageSize = value;
>> }
>> }
>>
>> applicationContext-dao.xml:
>>
>> <bean id="orderQueryCriteria"
>> class="org.ognl.dao.OrderQueryCriteria" singleton="false"
>> autowire="byName">
>> <property name="orderStatus"><value>:[
>> @EnumeratedType@getFactory(@OrderStatus@class).instances.{ #this }
>> ]</value></property>
>> <property name="primaryOrdering"><value>:[ new
>> SortOrdering('orderDate', @SortOrdering@DESCENDING) ]</value></property>
>> <property name="pageSize"><value>10</value></property>
>> </bean>
>>
>> EnumeratedType is an abstraction for managing enumerated type
>> objects. It allows you to get lists of instances and manages
>> indexing the enumerations by other properties as well. Access is
>> through static factory that implements the getInstances() method.
>>
>> orderStatus is a List of OrderStatus objects. To construct this we
>> need to get the List from the EnumeratedType's factory and get a copy
>> of the list that is returned (the copy is done by "projecting" the
>> instances list via { #this }, which creates a new List as a result).
>>
>> primaryOrdering is a SortOrdering object that has an Object "target"
>> and an ordering value (ASCENDING, DESCENDING or NONE). Note here
>> that we are constructing this object using it's own static constant
>> fields.
>>
>> The above code is accessing SortOrdering, EnumeratedType, and
>> OrderStatus without any package specifications, you may note. This
>> works here because the processor is looking for beans of type
>> ognl.ClassResolver to use to resolve class names to actual Class
>> objects. I've written an ImportClassResolver that is configured thus:
>>
>> <!-- id does not matter; only the fact that it exists in the
>> context -->
>> <bean id="imports"
>> class="org.ognl.spring.config.ImportClassResolver">
>> <property name="imports">
>> <list>
>> <value>org.ognl.util.*</value>
>> <value>org.ognl.model.shop.*</value>
>> <value>org.ognl.pager.*</value>
>> </list>
>> </property>
>> </bean>
>> You can define as many of these as you like and they do inherit.
>>
>> Another feature is that the OGNL "context" object allows access to
>> the rest of the Spring applicationContext through OGNL's "context
>> variable" syntax.
>>
>> In the above code you saw reference to "#this" - this is the implicit
>> value of the current object of the navigation; also available is
>> #root (the original root object of the expression). This syntax also
>> is used to access other elements in the context:
>>
>> <!-- a ListFactory produces, as the result of the factory, a List
>> object -->
>> <bean id="itemSortProperties"
>> class="org.ognl.spring.config.ListFactory">
>> <property name="list">
>> <value>:[
>> {
>> #{ "name": "Item #",
>> "property": "itemNumber",
>> "advanced": false
>> },
>> #{ "name": "Name",
>> "property": "name",
>> "advanced": false
>> },
>> #{ "name": "Categorization",
>> "property": { "product.category.name",
>> "product.name" },
>> "advanced": false
>> },
>> }
>> ]</value>
>> </property>
>> </bean>
>>
>>
>> <bean id="itemQueryCriteria"
>> class="org.ognl.dao.ItemQueryCriteria" singleton="false"
>> autowire="byName">
>> ...
>> <property name="primaryOrdering"><value>:[
>> new SortOrdering(#itemSortProperties.{? name ==
>> "Categorization" }[^].property, @SortOrdering@ASCENDING)
>> ]</value></property>
>>
>> <property name="secondaryOrdering"><value>:[
>> new SortOrdering(#itemSortProperties.{? name == "Item #"
>> }[^].property, @SortOrdering@ASCENDING)
>> ]</value></property>
>>
>> <property name="tertiaryOrdering"><value>:[
>> new SortOrdering(#itemSortProperties.{? name == "Name"
>> }[^].property, @SortOrdering@ASCENDING)
>> ]</value></property>
>>
>> <property name="pageSize"><value>10</value></property>
>>
>> </bean>
>>
>> The above configures a List of Map objects, each of which has a
>> "name", "property" and "advanced" key/value pair. The
>> itemQueryCriteria object is configured from this list by referencing
>> the other bean via "#itemSortProperties". Each of these uses the
>> selection syntax to get a specific item out of the list, then the
>> dynamic subscript "[^]" to return the first item of the list.
>>
>> You can also navigate through other objects in the context for other
>> purposes such as mirroring another configuration value:
>>
>> <bean id="myObject" class="...">
>> <property name="foo"><value>1254</value></property>
>> ...
>> </bean>
>>
>> <bean id="otherObject" class="...">
>> <property name="bar"><value>:[ #myObject.foo ]</value></property>
>> </bean>
>>
>> This can help cut down on error where properties are used repetitively.
>>
>> I'm not sure how I should distribute the source to this or if the
>> project takes contributions. The code has a dependency on OGNL 2.6.3
>> and above (1 jar file of ~185k). Is there a contribution mechanism
>> that I can use to put instructions for use, the jar and the source up
>> somewhere?
>>
>> - Drew
>
|
|
From: Drew D. <dr...@og...> - 2005-01-29 20:59:43
|
Colin Sampaleanu wrote:
> This code looks pretty interesting. I agree about it probably making
> sense to include in Spring. Drew, do you have any feel for
> performance, i.e. how big an impact there would be to using a lot of
> these expressions in a config file?
I wouldn't expect the effect to be very noticeable at all. I haven't
done any performance comparisons with bare spring contexts and
OGNL-decorated ones so all I have is my own experience with my
Hibernate/Spring/Tapestry webapps. I currently am using this on 3
different projects and have developed on these for months before popping
this configurer in, so I have a good idea of the "real world" startup
time of my contexts.
My opinion is that the OGNL parsing/evaluation is "dust on the scale"
when compared with the startup time for Spring's parsing and
(especially) Hibernate initialization. OGNL uses reflection heavily (as
does Spring), but the fact is that most of the time (probably all of the
time) you read the contexts once at startup, so any compilation step at
this point would slow down the process (the incarnation of OGNL that I'm
working on has back-ends for Janino and one for Javassist code
generation for faster expression evaluation).
Since I wrote this I went a bit off the deep end using OGNL expressions
in my contexts; I've since settled down a bit and backed off of using
them so much. The reason is that I was doing some things with OGNL that
should be done with Spring just because OGNL provides a slightly more
convenient syntax for some things (collections, mostly). I didn't do it
for performance reasons (I had a context with about 30 objects that were
configured using at least one OGNL-replaced expression each and it had
no noticeable performance impact).
The OGNL performance suite should give you an idea of the general speed
for some common operations:
performance:
[java] Constant: 100 + 20 * 5
[java] java: 3720098 iterations in 1000 ms
[java] compiled: 912719 iterations in 1000 ms (4.1 times slower
than java)
[java] interpreted: 869808 iterations in 1000 ms (4.3 times slower
than java)
[java] Single Property: bean2
[java] java: 3772105 iterations in 1000 ms
[java] compiled: 362914 iterations in 1000 ms (10.4 times slower
than java)
[java] interpreted: 167400 iterations in 1000 ms (22.5 times slower
than java)
[java] Property Navigation: bean2.bean3.value
[java] java: 3601668 iterations in 1000 ms
[java] compiled: 102586 iterations in 1000 ms (35.1 times slower
than java)
[java] interpreted: 52078 iterations in 1000 ms (69.2 times slower
than java)
[java] Property Navigation and Comparison: bean2.bean3.value <= 24
[java] java: 3394879 iterations in 1000 ms
[java] compiled: 68599 iterations in 1000 ms (49.5 times slower
than java)
[java] interpreted: 43283 iterations in 1000 ms (78.4 times slower
than java)
[java] Property Navigation with Indexed Access:
bean2.bean3.indexedValue[25]
[java] java: 3624147 iterations in 1000 ms
[java] compiled: 43374 iterations in 1000 ms (83.6 times slower
than java)
[java] interpreted: 33505 iterations in 1000 ms (108.2 times slower
than java)
[java] Property Navigation with Map Access: bean2.bean3.map["foo"]
[java] java: 2149048 iterations in 1000 ms
[java] compiled: 55539 iterations in 1000 ms (38.7 times slower
than java)
[java] interpreted: 35116 iterations in 1000 ms (61.2 times slower
than java)
Note that the compiled: entries denote the earlier, simpler version of
the Javassist-based compiler that only generated property accessors for
expressions. These tests run for a fixed length of time to test how
many times the statement will be executed.
Although seeing things like "61.2 times slower than java" is a bit
daunting, remember that the last one executed 35,116 times in 1 second.
If you put 100 OGNL expressions of medium complexity in your context it
will be slower, but not noticeably.
> I'm also trying to get my head around how this affects lifecycles and
> when initialization happens. PropertyPlaceholderConfigurer is
> obviously pretty simplistic, all it's going to do is replace a
> placehold value in a text property value with another. It can't
> trigger the initialization of another bean. Now in this OGNL variant,
> if the OGNL script references the context, then it can trigger the
> initialization of other beans, similar in fashion to how a <ref
> bean="xxx"> will trigger the init of that other bean first. Now the
> difference here is that while the <ref bean=""> will trigger that init
> only if used, since this approach is as a bean factory postprocessor
> and all expressions are evaluated at init time, all references beans
> will be immediately initialized at init time. For this reason, while I
> think this is a valid approach, and has the advantage that it doesn't
> require changes to the guts of Spring, I think there's still added
> value in having the idea of expressions known to Spring itself, which
> are only evaluated on demand... Possibly the 2nd step...
Yes, there could be lifecycle issues here that I'm ignorant of. I'm not
as conversant with the internals of Spring as I'd like but my initial
usage has been successful in referencing other beans in the context.
Ideally the OGNL stuff would have the same effect as doing a <ref
bean=""> reference, so that the semantics are consistent.
I chose to implement this as a BeanFactoryPostProcessor instead of some
other approach (like a custom <value>-type tag) because it's less
intrusive and is drop-in compatible. To make it semantically like <ref
bean=""> there might have to be tighter integration. Correct? Or is
the <ref> stuff implemented using the same basic mechanism?
- Drew
--
+---------------------------------+
< Drew Davidson | OGNL Technology >
+---------------------------------+
| Email: dr...@og... /
| Web: http://www.ognl.org /
| Vox: (520) 531-1966 <
| Fax: (520) 531-1965 \
| Mobile: (520) 405-2967 \
+---------------------------------+
|
|
From: Michael S. <mi...@sc...> - 2005-01-28 09:05:38
|
On Thursday 27 January 2005 09:48, Rob Harrop wrote: > Alternatively, I wonder if it is about time we started a separate > project for Spring add-ons. Still underneath the Spring umberella, > just a separate project away from the core. Yes, please. > This way we can keep the > core compact and free from clutter. Thoughts everyone? Altough in the case of Drew's OGNL contribution, I hope it migrates to the core. Michael -- Michael Schuerig There is no matrix, mailto:mi...@sc... only reality. http://www.schuerig.de/michael/ --Lawrence Fishburn |