Skip to content

No metadata generated with @ConstructorBinding and Kotlin #17560

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
To-da opened this issue Jul 17, 2019 · 6 comments
Closed

No metadata generated with @ConstructorBinding and Kotlin #17560

To-da opened this issue Jul 17, 2019 · 6 comments
Labels
status: superseded An issue that has been superseded by another type: bug A general bug

Comments

@To-da
Copy link

To-da commented Jul 17, 2019

Generation of metadata for configuration properties doesn't work work with immutable var Kotlin properties.

Module: spring-boot-configuration-processor
Version: 2.2.0.M4
Build system: Maven
Language: Kotlin
Related to: #8762

Property class:

@ConfigurationProperties(prefix = "spring.pulsar")
data class PulsarProperties(      
   val serviceUrl: String = "pulsar://localhost:6650", 
   val listenerThreads: Int = 1,
   ...
)

Maven plugin setup:

            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>kapt</id>
                        <goals>
                            <goal>kapt</goal>
                        </goals>
                        <configuration>
                            <sourceDirs>
                                <sourceDir>src/main/kotlin</sourceDir>
                            </sourceDirs>
                            <output></output>
                            <annotationProcessorPaths>
                                <annotationProcessorPath>
                                    <groupId>org.springframework.boot</groupId>
                                    <artifactId>spring-boot-configuration-processor</artifactId>
                                    <version>2.2.0.M4</version>
                                </annotationProcessorPath>
                            </annotationProcessorPaths>
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <args>
                        <arg>-Xjsr305=strict</arg>
                    </args>
                    <compilerPlugins>
                        <plugin>spring</plugin>
                    </compilerPlugins>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-allopen</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                </dependencies>
            </plugin>

Generated spring-configuration.metadata.json:

{
  "groups": [
    {
      "name": "spring.pulsar",
      "type": "sample.config.PulsarProperties",
      "sourceType": "sample.config.PulsarProperties"
    }
  ],
  "properties": [],
  "hints": []
}

... so it's missing properties completely.

In case that property is specified outside of the constructor (lateinit var property - like before #8762 was implemented) then metadata is generated properly.

In documentation there're mentioned some features are not working with kapt but I do believe this should work (and in case of immutable props also with defaults).

@To-da To-da changed the title spring-boot-configuration-processor do not work with immutable var Kotlin properties Spring-boot-configuration-processor doesn't work with immutable var Kotlin properties Jul 17, 2019
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 17, 2019
@snicoll
Copy link
Member

snicoll commented Jul 18, 2019

Defaults definitely don't work as KAPT does not generate that information at all, see #15397. I am surprised there is the creation of a group but no properties. Can you please move that to a small sample I can run myself?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Jul 18, 2019
@To-da
Copy link
Author

To-da commented Jul 18, 2019

@snicoll sample: https://github.com/To-da/spring-boot-config-md-kotlin-immutable-props

observations: in case that I specify default value (by Kotlin way - not by Spring annotation) for the property with type String the metadata are not generated. For Int property it's ok (known issue is that default value is not retrieved from assigned value due to KAPT limitations).
In case that there's String property without assigned default value and after that second on it works.

It definitely needs more detailed tests.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 18, 2019
@To-da
Copy link
Author

To-da commented Jul 18, 2019

workaround - use @org.springframework.boot.context.properties.bind.DefaultValue annotation and do not use Kotlin default values.
Example:

@ConfigurationProperties(prefix = "spring.pulsar")
data class PulsarProperties(
        /**
         *  Note that pulsar client also support reloadable [org.apache.pulsar.client.api.ServiceUrlProvider] interface
         *  to dynamically provide a service URL.
         *  It can be coma separated value in case of non-kubernetes deployment
         */
        @DefaultValue("pulsar://localhost:6650")
        val serviceUrl: String,

        /**
         * Thread pool used to manage the TCP connections with brokers.
         * If you're producing/consuming across many topics, you'll most likely be
         * interacting with multiple brokers and thus have multiple TCP connections opened.
         * Increasing the ioThreads count might remove the "single thread bottleneck",
         * though it would only be effective if such bottleneck is indeed present
         * (most of the time it will not be the case...).
         * You can check the CPU utilization in your consumer process,
         * across all threads, to see if there's any thread approaching 100% (of a single CPU core).
         */
        @DefaultValue("1")
        val ioThreads: Int,

        /**
         * Thread pool size when you are using the message listener in the consumer.
         * Typically this is the thread-pool used by application to process the messages
         * (unless it hops to a different thread). It might make sense to increase
         * the threads count here if the app processing is reaching the 1 CPU core limit.
         */
        @DefaultValue("1")
        val listenerThreads: Int = 1
)
{
  "groups": [
    {
      "name": "spring.pulsar",
      "type": "sample.config.PulsarProperties",
      "sourceType": "sample.config.PulsarProperties"
    }
  ],
  "properties": [
    {
      "name": "spring.pulsar.io-threads",
      "type": "java.lang.Integer",
      "description": "Thread pool used to manage the TCP connections with brokers. If you're producing\/consuming across many topics, you'll most likely be interacting with multiple brokers and thus have multiple TCP connections opened. Increasing the ioThreads count might remove the \"single thread bottleneck\", though it would only be effective if such bottleneck is indeed present (most of the time it will not be the case...). You can check the CPU utilization in your consumer process, across all threads, to see if there's any thread approaching 100% (of a single CPU core).",
      "sourceType": "sample.config.PulsarProperties",
      "defaultValue": 1
    },
    {
      "name": "spring.pulsar.listener-threads",
      "type": "java.lang.Integer",
      "description": "Thread pool size when you are using the message listener in the consumer. Typically this is the thread-pool used by application to process the messages (unless it hops to a different thread). It might make sense to increase the threads count here if the app processing is reaching the 1 CPU core limit.",
      "sourceType": "sample.config.PulsarProperties",
      "defaultValue": 1
    },
    {
      "name": "spring.pulsar.service-url",
      "type": "java.lang.String",
      "description": "Note that pulsar client also support reloadable [org.apache.pulsar.client.api.ServiceUrlProvider] interface to dynamically provide a service URL. It can be coma separated value in case of non-kubernetes deployment",
      "sourceType": "sample.config.PulsarProperties",
      "defaultValue": "pulsar:\/\/localhost:6650"
    }
  ],
  "hints": []
}

@wilkinsona wilkinsona assigned wilkinsona and snicoll and unassigned wilkinsona Mar 12, 2020
@snicoll snicoll changed the title Spring-boot-configuration-processor doesn't work with immutable var Kotlin properties No metadata generated with @ConstructorBinding and Kotlin Mar 25, 2020
@snicoll snicoll added type: bug A general bug and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Mar 25, 2020
@snicoll snicoll added this to the 2.2.x milestone Mar 25, 2020
@davinkevin
Copy link
Contributor

davinkevin commented Apr 17, 2020

Same problem if you are using nested data class.

You have to add @ConstructorBinding on nested class to be able to have the documentation generated for it.

@boris1993
Copy link

You have to add @ConstructorBinding on nested class to be able to have the documentation generated for it.

This annotation is not necessary for the nested data class, but the nested data class must be inside the outer class like this:

@ConstructorBinding
@ConfigurationProperties(“credentials”)
data class Credentials(
    val someClient: Credential
) {
    data class Credential(
        val clientId: String,
        val clientSecret: String
    )
}

@snicoll
Copy link
Member

snicoll commented Nov 5, 2020

The sample was built with a milestone of 2.2.0 but adding @ConstructorBinding generates the properties for both the NotOk and Ok POJO so I am going to close this now.

@snicoll snicoll closed this as completed Nov 5, 2020
@snicoll snicoll added the status: superseded An issue that has been superseded by another label Nov 5, 2020
@snicoll snicoll removed this from the 2.2.x milestone Nov 5, 2020
@snicoll snicoll removed their assignment Nov 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: superseded An issue that has been superseded by another type: bug A general bug
Projects
None yet
Development

No branches or pull requests

6 participants