spring-hateoas
spring-hateoas copied to clipboard
Creating templated links when pointing to controller methods in Kotlin
Currently, if we want a templated URI that we do not manually build ourselves, we can do
linkTo(methodOn(UserController::class.java).getUser(null)).withRel("user")
This works fine with Java as we can pass null parameters to any method, but it does not work well in Kotlin, as in Kotlin we have to explicitly make our method's parameters nullable. This creates opportunities for mistakes and undermines the inherent safety of kotlin, making us do null checks just like in java instead of being able to assure that this controller method can not accept nullable parameters.
It would be nice if we had some other way to do this that isnt building the URI manually.
I’m not sure what would work. We literally invoke the method but use a proxy to trap the results. This gives us the Method object to reflectively glean information. What happens if you try a concrete “fake” value?
I also have this problem right now. If I use a fake value it gets populated and the link is not templated anymore. I even tried things like "{myParam}" but this gets (correctly) escaped.
This behavior can be greatly improved by using Kotlin's really great reflection and introspection capabilities.
I think something like linkTo(function: KFunction<*>, vararg params: Any?)
is a solution here. Call it like this linkTo(FooController::getFoos)
or linkTo(FooController::getFoo, foo.id)
.
As far as I can tell though, there's no way to further optimize this and it will require runtime-validation to ensure that your params don't break null-safety.
I'm also kinda unsure what the original problem is. It seems that methodOn<T>
will pass a T
to the block--which means that inner proxy of T
should also meet all of the null-safety constraints of the actual T
.
A somewhat null-safe way to achieve the above is already available - unfortunately it doesn't work with partially-filled templates. A syntax that would work with this lib is: linkTo(UserController::getUser.javaMethod!!).withRel("user")
.
Unfortunately, this results in an exception as template parameters are missing, caused by: https://github.com/spring-projects/spring-hateoas/blob/646e73c8c5ca5f1302bd6722e0ad338be0309fc9/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilder.java#L139 . Using methodOn
instead results in a call to UriComponentsBuilder.buildAndExpand
in https://github.com/spring-projects/spring-hateoas/blob/646e73c8c5ca5f1302bd6722e0ad338be0309fc9/src/main/java/org/springframework/hateoas/server/core/WebHandler.java#L151 which, with the setup that was done before, can handle null
parameters.
Is there a way to unify the behaviour of these to components, ideally applying the one of WebHandler
, so that type-safe link creation with templates in Kotlin are possible?
Anyone looked into this issue recently?
I am curious as well if this has any updates.
A workaround for the time being is a utils method:
fun <T> nullType(): T = null as T
Providing null as a non-nullable type.