As discussed in #5537 and this Stackoverflow question, Spring default property placeholder prefix is not a good fit with Kotlin because it is already used in the language for String interpolation and #{...}
can't be used as a droppin replacement and has other meaning.
The current workaround I suggest to Kotlin users is to declare these customized PropertySourcesPlaceholderConfigurer
that allow to support @Value("%{foo}")
without breaking existing Java @Value("${foo}")
or Kotlin @Value("\${foo}")
annotations.
@Bean
fun kotlinPropertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply {
setPlaceholderPrefix("%{")
setIgnoreUnresolvablePlaceholders(true)
}
@Bean
fun defaultPropertyConfigurer() = PropertySourcesPlaceholderConfigurer()
I suggest @Value("%{foo}")
since that sounds a not so bad convention, but it could obviously be a different one.
It would be nice if that could be done by default (and documented) in Spring Boot 2.0, using for example @ConditionalOnClass(Unit.class)
(kotlin.Unit
is the Kotlin class equivalent for Void
in Java).
Another way to tackle this issue could be to allow customizing such prefix with an application.properties
property + configuring that by default for start.spring.io
Kotlin projects, but I tend to think providing such default convention for Kotlin projects is more what I would expect from Spring Boot, but that's open to discussion ;-)
We've moved almost full gears to @ConfigurationProperties
and aren't really advising the use of @Value
(I can see @dsyer objecting to that in a min). @Value
is a Spring Framework feature and we don't do anything special in Spring Boot about it (AFAIK).
I'd be tempted to leave things as they are.
I don't think it matters if we advise using it or not. If it doesn't work in Kotlin we should try and support it, and the suggestion sounds pragmatic.
In Groovy you can just use '${foo}'. Is there no equivalent in Kotlin (a String literal with no replacements)?
In Kotlin you have to escape the $
: @Value("\${foo}")
, it's not the end of the world but it's ugly so Kotlin developers almost never write this in practice.
Ugliness is in the eye of the beholder, I suppose. It doesn't seem so bad to me, and it's a Spring annotation, so Spring dictates the contents, and if that means escaping, that's just the way it is.
I guess I agree with @snicoll after all (it's fine the way it is).
I understand, I guess we can just promote @ConfigurationProperties
usage. Please just continue providing alternative to @Value
like you did with @LocalServerPort
in order to avoid situation when @Value
is mandatory ;-)
I have updated the related Stack Overflow question accordingly. An eventual improvement could be to support @ConfigurationProperties
on Kotlin data classes with immutable (val
) properties provided via the constructor, but I need to experiment about that and that's not critical since I think you can just use regular Kotlin classes with mutable (var
) properties currently.
For what it's worth, here is my opinion: I use injection through constructor whenever possible and I also prefer to have my properties immutable, so I use @Value
most of the time with it's corresponding escaped $
. It's ugly, but it's not the end of the world like @dsyer said and definitely better (for me) than having mutable properties all over the place. I've used @ConfigurationProperties
for some special property loading and I like it, but I'll be willing to use it more when it supports val
properties.
@eacasanovaspedre We're not really happy with the mutable nature of @ConfigurationProperties
either. We've recently completed a big piece of work that will make it easier to support immutable configuration properties in the future and hopefully you'll soon be able to use Kotlin data classes as configuration properties (watch #8762 for updates).
Most helpful comment
In Kotlin you have to escape the
$
:@Value("\${foo}")
, it's not the end of the world but it's ugly so Kotlin developers almost never write this in practice.