On Thu, Mar 11, 2010 at 16:41, Kin-man Chung <Kin-Man.Chung_at_sun.com> wrote:
> From the discussions we;ve had so far, it has been clear that we need a
> simpler API for getting an ExpressionFactory and ELContext, outside of JSP
> or
> JSF. We'll need an object to setup a defualt for ELContext
> ELResolvers, etc. I'll call it ELProcessor, because it also can be
> used to simplify EL parsing and evaluations.
>
> Here's my tentative proposal. I'm trying to keep it simple and use
> a design that seems to fit in the current EL. Therefore there are no
> CDI extensions, or listeners. :-)
>
> Use example:
>
> ELProcessor elp = new ELProcessor();
> boolean t = elp.getValue("${'2 > 1'}", Boolean.class);
I really like how simple that is. +1
> An alternative is to make ELProcessor an interface instead of a
> concrete class, and use a ELFactory to create an instance of
> ELProcessor, as suggested by Pete in one of his mails.
>
> interface ELProcessor {
>
> ExpressionFactory getExpressionFactory();
> void setExpressionFactory(ExpressionFactory ef); // Note 2
>
> ELParseContext getELParseContext();
> void setELParseContext(ELParseContext elpc);
>
> ELEvaluationContext getELEvaluationContext();
> void setELEvaluationContext(ELEvaluationContext elec);
>
> ELResolver getELResolver();
> void setELResolver(ELResolver elr);
>
> // May also need getter/setters for function mapper and variables
>
> // Add an user defined ELResolver
> void addELResolver(ELResolver elr);
>
> // See note 4 below for BeanLookup
> void setBeanLookup(BeanLookup blu);
>
> ValueExpression createValueExpression(String expression,
> Class expectedType);
> Object getValue(String expression);
> Object getValue(String expression,
> expectedReturnType);
> MethodExpression createMethodExpression(String expression,
> Class expectedReturnType,
> Class[] extectedParamTypes);
> Object invoke(String expression, Object[] params, Class returnType);
> }
This helps keep the API fairly small (at least the currently discussed
changes). I like having the interface, perhaps having a base abstract
class or something the provides the basic functionality so creating
your own ELProcessor isn't as involved. Such things in a base class
would be create*Expression as well as invoke. If we don't feel like we
gain a whole lot with that approach I'm fine without it, I don't think
this is something a typical user would be doing for every application
they create.
> Notes:
>
> 1. The life time of ELProcessor instances should be controlled by
> the application, not EL. The application can use a single instance
> of ELProcessor for the entire application, or use an instance of
> shorter life. For instance, JSP and JSF applications can use one
> for application, and one in each of the servlet listeners.
I completely agree with this. How the client ends up using EL, and
it's lifecycle really doesn't need to be in spec. I think this would
also allow more flexibility in how EL is used and could even give it
some application context and life time, both good things.
> 2. I am not sure we need or even should allow setter for ExpressionFactory.
Not really sure this buys us anything either.
> 3. Objects in ELProcessor has the following defaults:
>
> a. ExpressionFactory: singleton from ExpressionFactory.newInstance().
> b. ELParseContext: with null function mapper and variable mapper.
> c. ELEvalutaionContext: with the default ELResolver, below
> d. ELResolver: a composite ELResolver, consists of:
> MapELResolver,
> ResourceBundleELResolver,
> ListELResolver,
> ArrayELResolver,
> BeanELResolver,
> BeanNameELResolver (proposed, see below)
+1
> 4. Expressions such as #{foo.bar} will need a way to resolve "foo". I think
> bean discovery is the job of the bean containers, and not EL. Therefore I
> propose the following:
>
> interface BeanLookup {
> Object getBean(String name);
> }
>
> The method ELProcessor.setBeanLookup() let the application or container
> specify how to lookup a bean with the registered name.
>
> As an example, in the servlet listener, EL can be used to evaluate
> expressions involving an request scope object "foo":
>
> ELProcessor elp;
> elp.setBeanLookup(new BeanLookup {
> Object getBean(String name) {
> return request.getAttribute(name);
> }
> });
> elp.getValue("#{foo.bar}");
>
> BeanNameELResolver is a (proposed) ELResolver that uses the BeanLookup
> instance to resolve beans with names.
I like it, it gives us a nice, clean way to add additional resolvers
for simple cases. If we have this, is there a need for the full
ELResolver (besides backwards compatibility)? If we're going to have
a BeanNameELResolver, would it make sense to have a MethodELResolver,
seems like a logic split of the current ELResolver.
> 5. Of course we can also have different ELProcessors with slightly different
> defaults. The question is whether we need to specify them in the
> EL api, or just left as an implementation for the bean container.
> Ideally, the container should generate the appropiate ELProcessor
> depending
> on life cycle events of the applications, but that'll require tight
> coupling between EL and the container.
Seems to me if there could be a broad usage of any other ELProcessor
then it would be appropriate to add them to the spec. What those
ELProcessors might be I'm not sure.
--
Jason Porter
Real Programmers think better when playing Adventure or Rogue.
PGP key id: 926CCFF5
PGP fingerprint: 64C2 C078 13A9 5B23 7738 F7E5 1046 C39B 926C CFF5
PGP key available at: keyserver.net, pgp.mit.edu