The web module doesn't really need to depend on tomcat and all of
the Spring Boot web stack, but users need a way to grab that stuff
quickly if they want it (hence the new starter).
Also removed all spring-boot-starter dependencies from core and
context modules.
Functions with Flux and Message (as well as POJOs and Flux of POJO
which were already supported) should now work if they are created in
an isolated class loader. Preconditions:
* The class loaders must have the reactor-core (and reactive-streams)
shared between the app and the function. Practically speaking this means
there has to be a parent class loader with just reactive types, and
sibling children for the app and the function. This is not a new
requirement (it was needed for Flux of POJO anyway).
* Message types are handled reflectively, so they don't have to be in a
shared class loader. But they do have to be on the class path on
both sides (obviously).
Fixes: gh-118
When the `BeanDefinition` for `Function` is a `FactoryBean`
(e.g. `GatewayProxyFactoryBean` in Spring Integration) and that
`BeanDefinition` isn't registered as `@Bean` method (e.g.
Spring Integration Java DSL parser), the `ContextFunctionCatalogAutoConfiguration`
doesn't resolve the target `Function` type properly
* Get the target `Function` bean type via `BeanFactory.getType(String)`
* Make fallback to the `Object.class` instead of bean type since we are
expecting here a generic type anyway
When a function is created using an isolated class loader it might
want to use that class loader again for its invocations, and a lot
of tools (Spring etc.) use the context class loader for that kind
of thing if they don't have an explicit default value. So we
set the context class loader before, and unset it after, the
function invocation using a convenience wrapper.
This makes dynamic function registration (after context starts) much
easier. Also frees us from having to employ BeanFactoryPostProcessor
and other tricks to get the functions registered on startup.
A registered singleton doesn't have a BeanDefinition, but it might have
a compiled type with enough generic information to pull out the
input and output types.
- attempted to make code more functional (eat our own dog food) and concise
- addressed PR comment
- additional cleanup/polishing of FunctionUtils and related classes
- Removed Function/Supplier/ConsumerProxy classes by extending type info on their super interface
- Renamed FunctionUtils to FunctionFactoryUtils
- Added javadoc to FunctionFactoryUtils to explain its design considerations as well as what it can and can not doi
Fixes gh-90
- minor refactoring of FunctionRegistration and some javadoc
- general cleanup of ContextFunctionCatalogAutoConfiguration (mainly consolidated repeatable code)
Fixes gh-98
- Removed constructor in InMemoryFunctionCatalog that creates empty maps and no registrations since there is no way to register anything after catalog is created.
- Refactored registration logic a bit more functional/concise in the FunctionRegistration constructor of InMemoryFunctionCatalog
- Added additional assertions in tests
rebased and removed the assertion that was causing certain test failures
If the incoming message has a stream_routekey header, we use that
to route the message to a named function. Also adding the header
to messages coming out of suppliers.
The biggest change here is sort of orthogonal: it fixes a bug where
Spring Integration would subscribe twice to the same input channel
if the FunctionCatalog contains both functions and consumers. Then
when a message comes in it is dispatched to one or the other, but not
both. So the routing key couldn't work without fixing that
problem.
Also applies to output types, wrapper types and identifying if
messages can be processed directly.
See gh-81 (the ambiguity is still there, but the indirection bug
is fixed).
The FunctionInspector needs to be able to distinguish between a
function of Flux<Foo> and a function of Flux<Message<Foo>>. Then
it can do the conversion a level below.
Only supports Message->Message or POJO->POJO (no mixtures), so there
is only one new method in FunctionInspector.
No support in the web endpoints yet. But it's probably not so hard
to add.
The compiled functions implement that interface which means you can inspect
the signature of the method that created them and discover its
generic types.
Compiled functions always show up with no metadata, and you can only
guess what the types are from the bean definition. Probably we should
add more information to the bean definition if we have it when we
compile the function.
There is still a problem if user defines functions that are not of
Flux<String> (but that has always been the case).
These can be used to more reliably discover whether the user
has declared a function with flux types or "bare" POJOs. They
then pave the way to supporting single valued types in a special
way.
Also consolidate and simplify the logic in FunctionInspector
So that single Strings can be POSTed without JSON conversion.
There's still some work to do to support single POJOs in JSON, and
to reach parity with the WebFlux reactive type handlers, but it's
now closer to what we had before we moved the String conversion
out of the function layer.
There is one behaviour change (you have to POST an array to a function
endpoint if you are sending a body), and also a message converter that
needed to be removed so that arrays are not toStringed in the response
body.