Generating configuration metadata from @ConfigurationProperties items written in Kotlin doesn't work for defaultValue fields. It works fine for all the other fields. In java, it works fine for everything. Here is an example. Note that I'm using Spring Boot 2.0 and Gradle.

kapt 'org.springframework.boot:spring-boot-configuration-processor'
kapt {
  arguments {
    arg("org.springframework.boot.configurationprocessor.additionalMetadataLocations", "$projectDir/src/main/resources")
   }
}
compileJava.dependsOn(processResources)

My @ConfigurationProperties file looks like this:

@Component
@ConfigurationProperties("flowr.epg")
class EpgProperties {
    /** Whether or not schedules should be computed/refreshed on (re)start */
    var refreshOnRestart = true
    /** Number of threads used to store new images */
    var nImagesUploadThreads = 10
}

The result looks like this:

{
  "hints": [],
  "groups": [
    {
      "sourceType": "com.taktik.flowr.epg.properties.EpgProperties",
      "name": "flowr.epg",
      "type": "com.taktik.flowr.epg.properties.EpgProperties"
    }
  ],
  "properties": [
{
  "sourceType": "com.taktik.flowr.epg.properties.EpgProperties",
  "defaultValue": false,
  "name": "flowr.epg.refresh-on-restart",
  "description": "Whether or not schedules should be computed\/refreshed on (re)start",
  "type": "java.lang.Boolean"
},
{
  "sourceType": "com.taktik.flowr.epg.properties.EpgProperties",
  "defaultValue": 0,
  "name": "flowr.epg.n-images-upload-threads",
  "description": "Number of threads used to store new images",
  "type": "java.lang.Integer"
}
}

Support for default values in Kotlin would be a really nice feature to have for my company.

Note: replicated from https://stackoverflow.com/questions/53636533/spring-boot-configurationproperties-metadata-generation-wrong-default-values

Comment From: snicoll

It's actually worse. It doesn't detect the default value and use default value for the underlying type. I guess we will need to see if we can't hook into some low-level APIs as we've done for the Java compiler.

Comment From: darioseidl

I'm seeing the same problem. Just to be clear: the problem is only with the generated metadata, the default values specified in Kotlin @ConfigurationProperties do get picked up, they are just not documented in the metadata, right?

Comment From: Simon3

Correct.

Comment From: snicoll

Unfortunately there's not much we can do at the moment, please vote for KT-30164. In the meantime, we could attempt to detect that the source model is a Kotlin class and then deactivate default handling to avoid writing wrong value in the metadata.

Comment From: Simon3

Ok, yes I guess it would be a good idea to do that in the meantime. Thanks for everything!

Comment From: snicoll

It works fine for all the other fields.

@Simon3 that doesn't match my analysis. Can you please share a sample where other Kotlin fields have a proper default value in the generated metadata? (a small project I can run would be ideal). Thanks!

Comment From: Simon3

What I meant is that the "name", "description" and "type" fields are all always correct. But the "defaultValue" field is always incorrect. It is illustrated by the example in my first post.

Comment From: snicoll

Cool, we're on the same page now. Thanks for the feedback.

Comment From: snicoll

Unfortunately, there hasn't been enough progress on the kotlin side of things to implement this. My gut feeling is that another hook point might be required (Kotlin compiler plugin?). We'll adapt to whatever is available to us and I'll update this issue accordingly.

Comment From: m-kay

Any update on this? KT-30164 is fixed now.

Comment From: snicoll

@m-kay I need to double check but I don't think this is changing much for most use cases, per

Moreover, since Kotlin 1.4 the compiler will emit value attributes only for const vals.

That definitely isn't helping for what we're trying to achieve here.

Comment From: darioseidl

KT-30164 is marked as fixed in 1.3.70 and Kotlin 1.3.70 has just been released. We just updated our projects to that version now and after a rebuild the spring-configuration-metadata.json contains the correct defaultValues for our configuration properties now.

So this seems to be fixed to me, or at least something has changed for the better.

Comment From: snicoll

@darioseidl thanks for the nudge. We'll ugprade to 1.3.70 and then revisit this one. I've a number of test cases and it's great to hear your use cases are working as expected.

Comment From: sdeleuze

@darioseidl I have been unable to get defaultValues generated correctly in spring-configuration-metadata.json, could you please double check on your side? I have published my repro project , could you please have a look and send me your feedback?

Comment From: Simon3

Default values now work fine for me too! All I had to do regarding my original post was to upgrade Kotlin to 1.3.70 :) Thanks snicoll!

Comment From: sdeleuze

Ok I have found the difference, it works for regular var properties but not with @ConstructorBinding.

Works:

@ConfigurationProperties("demo")
class DemoProperties {
    var title: String = "foo"
}

Does not work and require @DefaultValue to get defaultValues metadata generated correctly:

@ConstructorBinding
@ConfigurationProperties("demo")
class DemoProperties(val title: String = "foo")

This issues is already tracked on Kotlin side by https://youtrack.jetbrains.com/issue/KT-29355.

Comment From: darioseidl

Ah, yes, we are using var properties and it works for them. We haven't tried @ConstructorBinding yet.

Comment From: snicoll

This issue has been superseded by a fix in Kotlin, see KT-30164. This will be available as of 2.2.6 or if you override to Kotlin 1.3.70 or later.

Comment From: izeye

This seems to be meant to be closed based on the last comment from @snicoll.

Comment From: mbhave

Thanks @izeye.

Comment From: rainmanhhh

met same problem with kotlin 1.5.0

@ConfigurationProperties("gateway.auth")
@Component
class AuthFilterConfig {
  /**
   * filter order
   */
  var order = 200
}
{
      "name": "gateway.auth.order",
      "type": "java.lang.Integer",
      "description": "filter order",
      "sourceType": "fy.eurekagateway.auth.AuthFilterConfig"
    }

Comment From: wilkinsona

@rainmanhhh Thanks for letting us know. It sounds like a regression in Kotlin 1.5. Assuming that it still works as expected with Kotlin 1.4 and earlier, can you please raise an issue with JetBrains referencing KT-30164?

Comment From: rainmanhhh

@rainmanhhh Thanks for letting us know. It sounds like a regression in Kotlin 1.5. Assuming that it still works as expected with Kotlin 1.4 and earlier, can you please raise an issue with JetBrains referencing KT-30164?

fyi: tried maven plugin and it's OK(except enum field). kapt gradle plugin ignores all default values

Comment From: wilkinsona

I don't think we've seen that difference in behaviour before. How does it behave for you with earlier versions of Kotlin?

Comment From: spyro2000

Same problem with Kotlin 1.7 and 2022.2.2. Default values are either not picked up at all (like for Strings) or just set to 0 (for Int) when using @ConstructorBinding

Comment From: wilkinsona

@spyro2000 As above, that's quite possibly a regression in Kotlin. Have you checked the behavior with earlier versions?

Comment From: spyro2000

@wilkinsona: No, I didn't. Only tested it with current version 1.7(.10).

Comment From: wilkinsona

IMO, it would be worth checking. If it works with an earlier version you could then report the regression to JetBrains.

Comment From: artemptushkin

Kotlin 1.7.20 and Spring Boot 2.7.6 - same issue, Long defaults to 0

data class MyClass(
  val fixedBackoffAttempts: Long = 10,
)
"defaultValue": 0

in the generated JSON

works with annotation @DefaultValue("1")

Comment From: wilkinsona

In the absence of any evidence to the contrary, a regression in Kotlin is the most likely cause of this and my comment above still stands.

Comment From: sdeleuze

I will check and raise an issue on Kotlin side if confirmed.

Comment From: sdeleuze

If I am not mistaken, I think it never worked and it is by design not possible to retrieve the default value via reflection because default value could be expressions depending on other parameters as mentioned in KT-56893.