shibboleth.Functions.Compose constructs a function by composing two other functions together. Mathematically, it takes the arguments "f" and "g" and an input "x" and builds a function that returns g(f(x))

Out of necessity the output of "f" must be the input type of "g".

It is an abstract bean so requires two constructor arguments, which are the two aforementioned functions.

Note that since the resulting bean is itself a function, you can nest composition arbitrarily deep to build chains of function calls.

shibboleth.BiFunctions.Compose starts a function composition chain with a BiFunction. It is a static version of the BiFunction.andThen() method and connects a BiFunction "f" returning a type T that is then input to a function "g", returning its value. Given inputs "x" and "y", this represents g(f(x,y)).

Because it narrows the inputs to a single value, it can be nested within an arbitrarily deep chain of subsequent function calls.


Non-contrived examples are difficult, but the most common use is to compose functions together that either navigate the IdP ProfileRequestContext tree of objects and/or to return a value from a context object. This allows any data in the tree to be reached declaratively using wired up function beans even when the path to the data is potentially very complex. But note that it doesn't allow the wiring to be simple, only possible.

Many examples of this approach can be found inside the system-defined auditing configuration, which uses composed functions to pull audited data out of the request context tree.

The following demonstrates combining a function that takes a ProfileRequestContext and returns a child context of type SessionContext with a function that takes a SessionContext and returns the session ID from it.

Thus, "f" is of type Function<ProfileRequestContext, SessionContext> and "g" is of type Function<SessionContext, String>, so composing them produces Function<ProfileRequestContext,String> and reuses two primitive building blocks to produce a more complex tool.

By convention named arguments are used, but if the names are left out the order of arguments is the outer function and then the inner function.

Function<ProfileRequestContext,String> returning Session ID
<bean parent="shibboleth.Functions.Compose"> <constructor-arg name="g"> <bean class="net.shibboleth.idp.session.context.navigate.SessionContextIDLookupFunction" /> </constructor-arg> <constructor-arg name="f"> <ref bean="shibboleth.ChildLookup.SessionContext" /> </constructor-arg> </bean>