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).
Use of BeanProcessor to catch a bean before it is used is a bit
agricultural these days. SmartInitializingSingleton is better and
frees application logs from one more annoying INFO log on an
early instantiation
2018-01-04 14:17:05.930 INFO 23472 --- [ Thread-0] trationDelegate$BeanPostProcessorChecker :
Bean 'org.springframework.cloud.function.web.flux.ReactorAutoConfiguration' of type
[org.springframework.cloud.function.web.flux.ReactorAutoConfiguration$$EnhancerBySpringCGLIB$$8d4844e]
is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
With this change there are now 2 choices for web endpoints. The
stream servlet binder is useful for multi-binder use cases
(e.g. HTTP -> message broker).
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.
Spring Boot apps often run with --debug (no boolean value), so
we need to be defensive and not barf if it's empty (and therefore
not convertible to a boolean)
If the output is a Message we grab the headers from the first one
and send those as response headers.
A function can add headers to messages. The HTTP response will
contain only headers that are in x-* _or_ were added to the message
by user (i.e. they weren't in the request).
We certainly do not want to pass through all HTTP headers (request
headers can conflict with or invalidate response headers).
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).
If the request is a single value, we already know, so if we also
know that the function returned a single-valued type, then we can
render the single value, instead of an array with a single item.
See gh-36
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.
When the user has sent us a single value, we can make the signature
of the handler and the format of the HTTP response much more
natural if it is single valued too (i.e. a Mono).