Skip to content

Allow @ConfigurationProperties binding for immutable POJOs #8762

Closed
@sdeleuze

Description

@sdeleuze
Contributor

Currently, it seems we are forced to use Kotlin classes with mutable nullable properties and default constructor with @ConfigurationProperties while idiomatic Kotlin code would be using classes with immutable properties initialized via constructor. I think there is a way to supporting that by leveraging kotlin-reflect library like jackson-module-kotlin do.

More concretely, in MiXiT app I would like to be able to convert this MixitProperties class implementation to:

@ConfigurationProperties("mixit")
class MixitProperties(
    val baseUri: String,
    val admin: Credential,
    val drive: Drive
)

class Credential(
    val username: String,
    val password: String
)

class Drive(
    val fr: DriveDocuments,
    val en: DriveDocuments
)

class DriveDocuments(
    val sponsorform: String,
    val sponsor: String,
    val speaker: String,
    val press: String
)

We could imagine to support optional properties by using nullable types, like val sponsorform: String? for example.

I will be happy to help. I have also already worked with @apatrida who maintains Jackson Kotlin module, he may provide us some guidance I think.

Activity

snicoll

snicoll commented on Mar 28, 2017

@snicoll
Member

We currently use Spring Framework's binder (that's also used in the MVC world) and it does not support binding via constructor. I guess that's the problem you want to solve?

We're rewriting the binder for Boot 2.0, perhaps @philwebb has some plans about that?

snicoll

snicoll commented on Mar 28, 2017

@snicoll
Member

@jhoeller just pinged me to mention SPR-15199. Would be pretty cool if we could use that somehow but I guess the best course of action is our binder and 2.0 anyway...

Having said that, perhaps we can reuse some bits?

apatrida

apatrida commented on Mar 28, 2017

@apatrida

There are two models that work with Kotlin. The first, is that a plugin model to the binder let's Kotlin describe the constructors and properties providing information about which can be used to construct the class (or a combination of constructor + properties set after). The second, is that a source of all settable things is made available and the decision is made by a Kotlin instantiator that does the work based on what it has available.

The best support considers all of:

  • what properties are set in the constructor
  • what properties are writeable after construction
  • for any property if it is nullable
  • for any property in the constructor has a default value that can be used if it is absent

Kotlin reflection has a callBy method on the constructor that can be used in the case that default values are being used, otherwise it should use call method.

So the binder should give the opportunity to a plugin to do the introspection and instantiation so that the plugin can do the best job for the language.

Binding examples for Kotlin:

Jackson Kotlin Module (pulls parameter name information, then hands it back along with actual parameters to a custom instantiator)

JDBI 3 (the Kotlin module handles all binding tasks when the target is a Kotlin class)

apatrida

apatrida commented on Mar 28, 2017

@apatrida

If there is a branch to track for the new binder, I can look at it and see what needs to be done to support Kotlin, and add that support.

philwebb

philwebb commented on Mar 28, 2017

@philwebb
Member

The experimental binder code is here, but it's still very much a work in progress. The plan is to make a binder that's specifically designed for binding from our configuration properties. It'll allow us to do some nice things like track the line/column number that a property was loaded from.

The Binder class is pretty complete, and there are quite a few tests. It deals with Collections, Arrays, Maps and Scalar types directly. When it finds something it can't handle it delegates to BeanBinder implementations.

We currently have a JavaBeanBinder that works with mutable classes but the plan is to add a couple more. We'd like to have a ValueObjectBeanBinder that binds using constructor arguments (this should work well with Kotlin).

We've also got plans for an InterfaceBeanBinder. The idea would be that you can so something like this:

@ConfigurationProperties(prefix="mine")
public interface MyProperties {
 
    @DefaultValue("spring")
    public String getName();

    public int getAge();

}

Which would be used to generate a proxy class with the appropriate implementation.

The first step is to get the binder working with our existing mutable configuration property beans. We'll then look at extending the support.

bclozel

bclozel commented on Apr 28, 2017

@bclozel
Member

Quick update here: #8868 has been merged, the new binder is in master.

sdeleuze

sdeleuze commented on Jun 5, 2017

@sdeleuze
ContributorAuthor

@apatrida Since the new binder is now in master, any chance you could have a look to identify what needs to be done to provide first class support for immatable data classes in Kotlin?

serandel

serandel commented on Jun 28, 2017

@serandel

Is this planned for the 2.0 release or for later in the roadmap? @ConfigurationProperties are a bit confusing without it.

snicoll

snicoll commented on Jun 28, 2017

@snicoll
Member

To summarize the discussion I just had with @sdeleuze we have interface binding on the pipe for 2.0 (see #1254). This issue is really about supporting constructor binding as well and it brings a number of challenges. One of them is that we need to upgrade the annotation processor to be able to detect and generate the metadata in such a case.

I bet Java developers will be interested by this feature as well and will use it with Lombok which will force us to detect all of these cases and I anticipate it is a lot of work. And supporting constructor binding without the metadata support is a no-go on my end.

I am flagging this one for team attention so that the rest of the team has a chance to review this.

wilkinsona

wilkinsona commented on Jun 28, 2017

@wilkinsona
Member

@serandel Can you please expand a bit on what you find confusing at the moment?

105 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @bclozel@dsyer@sdeleuze@apatrida@thekalinga

      Issue actions

        Allow @ConfigurationProperties binding for immutable POJOs · Issue #8762 · spring-projects/spring-boot