2020.0.20 snapshots seem to be incompatible with Spring Framework 5.3.21 snapshots:
2022-05-30 18:59:55,051 ERROR reactor.core.scheduler.Schedulers: 315 - Scheduler worker in group main failed with an uncaught exception
java.lang.NoSuchMethodError: 'reactor.core.publisher.Sinks$RootSpec reactor.core.publisher.Sinks.unsafe()'
at org.springframework.test.web.reactive.server.HttpHandlerConnector.doConnect(HttpHandlerConnector.java:87)
at org.springframework.test.web.reactive.server.HttpHandlerConnector.lambda$connect$0(HttpHandlerConnector.java:79)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
at reactor.core.publisher.Mono.subscribe(Mono.java:4400)
at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
We now properly handle path segment capture variables in URI mappings. Values handed into the dummy method invocations are expanded properly and a given null results in the composite segment template variable {/…*} being rendered to advertise the ability to add further segments.
We unfortunately cannot use UriComponentsBuilder in a way that we can populate it with encoded parameters *and* expand encoded path variable values. We currently use ….buildAndExpand(…) which considers the values provided unencoded but we never actually call ….toUri() on the resulting UriComponents instance.
We unfortunately cannot fix the problem at its root, as the only alternative would be to call ….build(true) indicating values already encoded but that stumbles above the template variables still present in the original template.
The only workaround right now is never calling UriComponents.toUri() but ….toUriString() as that doesn't apply the pending encoding that's not actually needed as we start with fully encoded values in the first place.
Heavily inspired by the PR @MikeRocke, we removed all usage of String.format(…) from hot code paths triggered by ….toString() as it's used in general output a lot.
Before:
Benchmark Mode Cnt Score Error Units
TemplateVariableBenchmark.toString(…) thrpt 3 2803239,270 ± 110258,955 ops/s
After:
Benchmark Mode Cnt Score Error Units
TemplateVariableBenchmark.toString(…) thrpt 3 10753653,459 ± 156684,459 ops/s
The commits for #467 significantly degraded performance as CachingMappingDiscoverer.getParams(Method) doesn't properly cache the result of the call which causes quite expensive, unnecessarily repeated annotation lookups for the very same method. We also avoid the creation of an Optional instance for the sole purpose of a simple null check.
Introduce FormatterFactory to potentially cache the to-String formatting functions and thus avoid repeated evaluation and Function object creation.
We now also avoid the creation of ParamRequestCondition instances if no @RequestParams(params = …) values could be found in the first place.
We now constrain the cache of controller proxy instances to 256 elements using Spring's ConcurrentLruCache to avoid instances created via DummyInvocationUtils.methodOn(Class<?>, Object…). The parameters are part of the cache key and used to expand the type-level mappings. If those vary for each call and a request creates a lot of links (>100000) the memory consumption grows significantly, first and foremost indefinitely.
Using the ThreadLocal will still make sure that the cache is local to a current request, so the proxies can actually be reused as the method invocations used to record the mappings would interfere for concurrent requests otherwise.
Removed obsolete generic parameter on the CacheKey type.