Specify whether evaluating `ValueExpression`s mapped in `VariableMapper` or created via `createValueExpression(Object, Class)` triggers `EvaluationListener`

Open
#503 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 7 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
46/100
Issue type
Documentation
Clarity
Mostly clear
Activity status
Active
Tech stack
java

Research direction

Start by reading Section 3.7 of the specification, the ExpressionFactory#createValueExpression(Object, Class<?>) and EvaluationListener Javadocs, and the existing TCK tests for evaluation listeners. The issue identifies divergent behavior but leaves the expected notifications undecided, so first trace how the specification and TCK cover these APIs. Done means the expected behavior is clarified in the specification and Javadoc and a TCK test validates it.

Written by the indexing model from the issue text.

Description

Section 3.7 ("Variables") of the Jakarta Expression Language 6.1 specification states:

An EL variable does not directly refer to a model object that can then be resolved by an ELResolver. Instead, an EL variable refers to an EL expression. The evaluation of that EL expression yields the value associated with the EL variable.

When a variable is registered in VariableMapper using ExpressionFactory#createValueExpression(Object instance, Class<?> expectedType) and referenced inside another expression (e.g. ${person.name}), implementations diverge on whether evaluating the mapped ValueExpression fires EvaluationListener#beforeEvaluation and afterEvaluation:

  • Eclipse Expressly: Fires beforeEvaluation and afterEvaluation only once for the outer expression ${person.name}. Evaluating the ValueExpressionLiteral created by createValueExpression(Object, Class) does not notify EvaluationListener.
  • Apache Tomcat Jasper EL: Fires beforeEvaluation("${person.name}"), then fires beforeEvaluation(person.toString()) and afterEvaluation(person.toString()) when ValueExpressionLiteral#getValue is called, and finally fires afterEvaluation("${person.name}").
Steps to Reproduce
import jakarta.el.*;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
public class VariableMapperListenerTest {
    public record Person(String name) {}
    @Test
    void testListenerWithVariableMapper() {
        ExpressionFactory factory = ExpressionFactory.newInstance();
        StandardELContext context = new StandardELContext(factory);
        List<String> events = new ArrayList<>();
        context.addEvaluationListener(new EvaluationListener() {
            @Override
            public void beforeEvaluation(ELContext ctx, String expr) {
                events.add("before:" + expr);
            }
            @Override
            public void afterEvaluation(ELContext ctx, String expr) {
                events.add("after:" + expr);
            }
            @Override
            public void propertyResolved(ELContext ctx, Object base, Object property) {
                events.add("resolved:" + property);
            }
        });
        Person person = new Person("Alice");
        context.getVariableMapper().setVariable(
                "person",
                factory.createValueExpression(person, Person.class)
        );
        ValueExpression ve = factory.createValueExpression(context, "${person.name}", String.class);
        ve.getValue(context);
        // Expressly (3 events): [before:${person.name}, resolved:name, after:${person.name}]
        // Jasper EL (5 events): [before:${person.name}, before:Person[name=Alice], after:Person[name=Alice], resolved:name, after:${person.name}]
        System.out.println(events);
    }
}
Request

Please clarify in the specification and Javadoc:

  1. Should ValueExpressions created via ExpressionFactory#createValueExpression(Object, Class) notify EvaluationListener#beforeEvaluation and afterEvaluation when getValue(ELContext) is called?
  2. When resolving an identifier mapped via VariableMapper, should beforeEvaluation/afterEvaluation be fired for the mapped ValueExpression, or only for the top-level expression being evaluated?
  3. Please add a TCK test validating the expected listener notifications.
Dominant language
Java
Stars
86
Forks
54
Avg merge
6d 9h
Merged PRs (30d)
11

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from jakartaee/expression-language

All issues in jakartaee/expression-language

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.