We now inspect controller method return types and the generics of RepresentationModelAssembler for EntityModel and CollectionModel types and unwrap the type they box to register that for constructor and method invocation reflection.
We now register proxy types for all controller beans and the return types of their methods if suitable for proxying. This allows the link creation by pointing to controller methods.
We now also register all types (de)serialized by Jackson for reflection.
We now relax the generic bound of D to … extends RepresentationModel<?> as otherwise implementation code of, for example, toModel(…) has to produce a concrete representation model and cannot be typed to return RepresentationModel<?>.
Introduced UriMapping to contain the original request mapping used on a controller method as well as a MappingVariables instance that captures all used variables of those mappings. These mappings and variables are not following URI template semantics but rather PathPattern. One example of this playing into the processing is the path segment capture syntax {*…}. This is roughly equivalent to URI template's composite path syntax {/…*}, which however looks different (as the leading slash is contained in the variable expression).
While the handling of those has been added in the commit before, we now introduce the proper abstractions that cause a couple of internal deprecations and binary-incompatible changes and we only want to impose them on implementors upgrading to 2.0. Also, this allows simplifying WebHandler which has accumulated quite a bit of logic already.
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
Slightly more compact default regex pattern. Untangle defaulting condition in PropertyMetdata.getPattern(). Extract test cases into dedicated methods. Couple of Javadoc fixes. Java-9-based polishing by using Optional.or(…) in JSR 303 PropertyMetadata implementation.
The presence of @NonBlank on a representation model's property now causes it to be considered required. It will also cause a default pattern exposed that allows clients to validate input values.
Fixes#1757.
DefaultUriTemplateHandler was deprecated and removed in Spring 6.0. We now use DefaultUriBuilderFactory as recommended in the deprecation part of DUTH's Javadoc.
Upgrade to Java 17 and Spring Framework 6. Switch to JakartaEE 9 version of the Servlet API. Drop support for Joda Time.
Configure Kotlin plugin to target JDK 1.8 as it doesn't support 17, yet.
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.
As per the discussion in mamund/hal-forms#88, the list of property types in HAL FORMS is not exhaustive. This means we cannot align them with HTML input types and even more so not drop anything not an HTML input type.
This is now implemented by switching to generic Strings in the HAL FORMS property DTO and directly piping the value originally registered on the affordance into it.
When adding a request parameter template variable and the URI part of the template already contains a request parameter we now automatically turn the variable type into request parameter continuation. That apparently got lost in the move to level 4 URI templates in #1583.
The unwrapping nature of EntityModel.getContent() does not work well with value that would result in an empty object being rendered. We now skip the rendering if failing for empty beans is disabled.