Interface ELMethodContributor

All Superinterfaces:
io.micronaut.core.order.Ordered
Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

@FunctionalInterface public interface ELMethodContributor extends io.micronaut.core.order.Ordered
Contributes the methods, constructors and functions that expressions parsed at runtime may call, without reflection.

This is the service an application implements to make a type callable from a runtime-parsed expression. Where ELMethodExecutor decides at every call which method a name refers to — which is what a reflective or otherwise dynamic provider needs — a contributor declares its callable surface once, at startup, and the registry does the rest: it selects the overload as the section 1.6 of the specification requires, coerces the arguments to the declared parameter types, packs the variable arity ones, reports the metadata a jakarta.el.MethodExpression exposes, and builds an identity that compares equal to the same expression compiled at build time.

Implementations are discovered as services, so a contributor is a class named in META-INF/services/io.micronaut.el.ELMethodContributor:

public final class BookMethods implements ELMethodContributor {

    @Override
    public void contribute(ELMethodRegistry registry) {
        registry.method(Book.class, "discounted", double.class, Integer.class, Book::discounted)
                .staticMethod(Math.class, "abs", int.class, int.class, Math::abs)
                .constructor(Book.class, Book::new, String.class)
                .function("fmt", "join", Formatting.class, "join", String.class, Formatting::join,
                          String.class, String[].class)
                .functionalInterface(TextMapper.class,
                          (context, lambda) -> value -> (String) lambda.invoke(context, value));
    }
}

A contributor also says how a functional interface the application declares is implemented, which is the one coercion that cannot be resolved while compiling and otherwise reaches a java.lang.reflect.Proxy.

Contributions are collected once, on first use, and indexed by type and name. A contributor therefore cannot see the jakarta.el.ELContext: anything that depends on it — a jakarta.el.FunctionMapper lookup, a per-request bean — belongs on the ELMethodExecutor contract instead. The receiver of an instance method is not affected, since it reaches the invocation at evaluation time.

Since:
1.1
Author:
Denis Stepanov
See Also:
  • Field Summary

    Fields inherited from interface io.micronaut.core.order.Ordered

    HIGHEST_PRECEDENCE, LOWEST_PRECEDENCE
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Registers the methods, constructors and functions this contributor makes callable.
    default int
    Returns the order in which contributors are consulted.
  • Method Details

    • contribute

      void contribute(ELMethodRegistry registry)
      Registers the methods, constructors and functions this contributor makes callable.

      Called once, when the expression parser is created. Registering the same signature twice makes the reference to it ambiguous, exactly as two equally specific overloads would.

      Parameters:
      registry - The registry to declare them in
    • getOrder

      default int getOrder()
      Returns the order in which contributors are consulted. Lower values run first, following the Micronaut Ordered contract; registrations of different contributors are merged, so the order only decides which of two identical signatures is declared first.
      Specified by:
      getOrder in interface io.micronaut.core.order.Ordered
      Returns:
      The order, zero by default