It would be useful to allow configuration binding to work directly on fields if the user doesn't want to expose public setters.

Comment From: snicoll

That would completely compromise work on #1001 that rely on the presence of a standard javabean property.

I also find this useful but we need to chose our camp. If we support it, we need a way to exclude unwanted fields/properties through annotations.

We also could add a mode to the annotations that would provide a hint to the processor. In that mode only the field would be exposed (same for metadata harvesting)

Comment From: philwebb

What about if we support field based binding if there is a getter but no setter. Or another easier option might be to allow protected setters. What I wanted was a quick way to expose configuration properties in a read-only form.

Yet another option might be to allow @ConfigurationProperties on an interface, generating an implementation proxy class.

@ConfigurationProperties
public interface SomeProperties {
    String getDateToolAttribute();
    String getNumberToolAttribute();
    getProperties();
    String getResourceLoaderPath();
    String getToolboxConfigLocation();
}

Comment From: wilkinsona

RJo on StackOverflow is interested in this functionality:

If the setters were not visible, the configuration properties would be unmodifiable without resorting to violence :)

Comment From: snicoll

I am fine either way but we have to understand the consequence for the annotation processor. We can go with any crazy option as long as it's explicit (i.e. you have to enable a flag on the @ConfigurationProperties annotation). If we don't, then we'll have to update the algorithm auto-detection and potentially expose thing we don't want in the metadata

(reminder: we have no way to exclude a property)

Comment From: fromi

I would be happy to be able to use @ConfigurationProperties with constructor injection, so I can create immutable and encapsulated classes.

Comment From: mwisnicki

I, for one, would like to have it working with plain fields.

Comment From: mwisnicki

Maybe use transient or @Transient to exclude properties from serialization/metadata ?

Comment From: mwisnicki

BTW spring-boot documentation has an example that shows binding to field which I guess is a mistake.

Comment From: philwebb

@mwisnicki Good spot on the docs. I've raised #2813 to address this.

Comment From: michaeltecourt

In order to have an "immutable" configuration properties object, I currently use a workaround with an interface, whose implementation is a "Java Bean" annotated with @ConfigurationProperties. Any shortcut would be appreciated. By the way, enabling field based injection would make a lot of sense, as the behavior would be more consistent with @Value. Having to add both getters/setters can be counter-intuitive the first time around.

Comment From: jordanjennings

@michaeltecourt Thanks for the suggestion. Doing this in combination with Lombok's @Data annotation on the implementation class makes this fairly painless.

Comment From: snicoll

@michaeltecourt that's not the same thing at all. With @Value you're giving the full id in a regular Spring Framework annotation (i.e. that you can put on field, setter or constructor argument). @ConfigurationProperties is a strongly-typed binder on a regular class where properties are discovered.

If we were enabling field access by default, all the fields of your class would be exposed which isn't what you want. The presence of accessors defines if it should be exposed or not.

I think our best shot at it is to add a flag to enable field support explicitly. In that case, you're at least aware they are all exposed.

Comment From: michaeltecourt

@snicoll By "all the fields of your class would be exposed" do you mean "injectable/bindable" ?

We mostly use @ConfigurationProperties like a bulk @Value. The semantic and precise use cases might be different, but isn't the purpose the same? binding properties from the Spring context to Spring beans in a type-safe manner?

In the end, what I find slightly confusing as a user is that you can do this :

/** Works on fields, constructor, etc */
@Component
class Props {
  @Value("${cfg.props.a}") String a;
  @Value("${cfg.props.b}") BigDecimal b;

  public Props(a, b) { this.a = a; this.b = b; }
  public String getA() { return this.a; }
  public BigDecimal getB() { return this.b; }
 }

and not this :

@ConfigurationProperties("cfg.props")
class Props {
  String a;
  BigDecimal b;

  public Props(a, b) { this.a = a; this.b = b; }
  public String getA() { return this.a; }
  public BigDecimal getB() { return this.b; }
  // SETTERS NEEDED
}

Comment From: snicoll

Yes, that is what I mean.

I think we already covered why it is confusing (see my previous comment). I am not arguing we shouldn't do it, I am arguing it must be opt-in.

Comment From: michaeltecourt

oh just realized ConfigurationProperties are also exposed through the /configprops actuator endpoint while "regular" properties are not.

From a humble user standpoint, I know that Spring has implicit write access to my class attributes as soon as it's annotated with @ConfigurationProperties, I wouldn't mind if field binding became the default, with some kind of exclusion mechanism as described by @mwisnicki, like the vast majority of annotation based binding frameworks (JAXB, Jackson, JPA...). I know the use case is different, as config properties are often directly injected to beans whose purpose is far more complex than holding values, so any additional option over getters+setters would be cool :)

@ConfigurationProperties("cfg.props")
 class Props {

      /** requires accessors by default */
      String a; 

      /** Enable field access explicitely */
      @ConfigurationProperty BigDecimal b;

      /** Explicit exclusion ? */
      @Transient Integer c;
 }

@philwebb 's proxy based solution looks a lot like the "old" (not pejorative) property binder framework : http://pholser.github.io/property-binder/examples.html

Comment From: AndersDJohnson

+1 I'd like a @ConfigurationProperty annotation valid on fields, which could accept an optional value parameter to specify the property path rather than reflecting on the field name, as well as other applicable parameters from @ConfigurationProperties.

Comment From: laxika

+1 from me. Setters are entirely useless for my user case and still, I should provide them. Having an immutable configuration would be a lot better. I'm not exactly sure how it can by supported sadly but it would be a lot better.

Comment From: sta-szek

:+1: getters and setters on all my property classes... :cry:

Comment From: MHarris021

+1

Comment From: victorherraiz

I'd love to have that feature. Annotated constructor parameters should be another option, something like @JsonCreator annotation, to build actual inmutable objects.

Comment From: tgianos

+1 Also like the idea of mimicking how Jackson uses @JsonCreator

Comment From: krzyk

This could be achieved by using java 8 -parameters so Spring would know which property should be set at which constructor argument.

Comment From: thinkbigthings

+1 for immutable configuration.

Comment From: lpandzic

You don't need @JsonCreator if you use jackson-module-parameter-names, except in case of single param constructor and even that case will most likely be covered in jackson 3.

Back to this issue, instead of using reflection to mutate fields, Spring Boot should similarly use parameter names and types to construct @ConfigurationProperties marked class instances.

Comment From: wilkinsona

The plan is:

  • Support binding to an interface that is annotated with @ConfigurationProperties
  • Automatically create a proxy that implements the interface and intercepts calls to the interface's getters. The interceptor will query the Environment for a property's value
  • Default values can be specified via an annotation (@DefaultValue) on the getter. The annotation will take a String. We can use the annotation processor to fail at compile time if the default cannot be coerced to the getter's return type. We also considered using default methods, but the result is significantly more verbose.
  • Provide a mechanism for property retrieval to be dynamic or static. If it's static, the interceptor will query the environment the first time the method is called and cache the result. If it's dynamic, the interceptor will query the environment each time the method is called

Comment From: mwisnicki

No chance of field binding? For POCs and microservices I usually prefer quick and dirty approach.

Comment From: wilkinsona

No chance of field binding? For POCs and microservices I usually prefer quick and dirty approach.

No, we don't think so. The main goal for this is to make it easier for a configuration properties class to be immutable. If we bound directly to fields, you'd still have to write the getter methods along with the fields which I think would be more code than writing an interface. The alternative would be to encourage people to make the fields public and access them directly and we don't want to do that.

Comment From: mwisnicki

That's unfortunate. Making fields public and avoiding accessor methods is exactly what I want when writing throwaway or minimalistic code.

On Thu, Jan 12, 2017, 11:55 Andy Wilkinson notifications@github.com wrote:

No chance of field binding? For POCs and microservices I usually prefer quick and dirty approach.

No, we don't think so. The main goal for this is to make it easier for a configuration properties class to be immutable. If we bound directly to fields, you'd still have to write the getter methods along with the fields which I think would be more code than writing an interface. The alternative would be to encourage people to make the fields public and access them directly and we don't want to do that.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-boot/issues/1254#issuecomment-272218151, or mute the thread https://github.com/notifications/unsubscribe-auth/AAF3IJkC4T6ThzjbCs1lYbuD58G5dGf9ks5rRlsdgaJpZM4CNFOC .

Comment From: fromi

@mwisnicki, you only have to write a constructor. Then, you can make all the fields public and final, which is perfectly clean for a data structure. You get immutable minimalist code.

Comment From: mwisnicki

This actually means I have to repeat every property name 3 times. Interface proxies are far better wrt. to DRY principle.

On 13 January 2017 at 03:47, Romain Fromi notifications@github.com wrote:

@mwisnicki https://github.com/mwisnicki, you only have to write a constructor. Then, you can make all the fields public and final, which is perfectly clean for a data structure. You get immutable minimalist code.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-boot/issues/1254#issuecomment-272390948, or mute the thread https://github.com/notifications/unsubscribe-auth/AAF3IGhNmVycfmcxefIwGm0B-WDpWuqhks5rRzovgaJpZM4CNFOC .

Comment From: victorherraiz

How interfaces are going to deal with Java config?. When I want to have the same config estructure at several prefixes I normally use Java config with @ConfigurationProperties annotation at @Beanmethod.

@Bean
@ConfigurationProperties("something")
public Config aConfig(){
    return new Config();
}

Comment From: wilkinsona

They won't. This change is going to be an addition to the existing support so you can continue to use your current approach with a POJO.

Comment From: victorherraiz

could I extend the interface several times and annotate those to map several prefixes with the same structure?

I prefer to have actual inmutable classes, but I must admit your solution is simpler and requiere less code.

Comment From: sdeleuze

As discussed on this comment and previous ones, support for Kotlin interfaces with val properties is needed on Kotlin, and is even more critical if constructor-based POJO binding is not supported in Boot 2.0. I guess it could look like:

@ConfigurationProperties
interface Fooproperties {
    val firstName: String
    val bar: Bar
}

If I decompile this Kotlin interface to bytecode then convert it to Java I obtain:

@ConfigurationProperties
@Metadata(
   mv = {1, 1, 7},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"..."},
   d2 = {"..."}
)
public interface Fooproperties {
   @NotNull
   String getFirstName();

   @NotNull
   Bar getBar();
}

Which seems to be a good fit with what you expect to support on Java side.

Comment From: GertVil

This is no longer planned for the near future?

Comment From: snicoll

@GertVil this issue is assigned to the Backlog, please review what Backlog means on our milestones page.

TL;DR 2.1.

Comment From: lievendoclo

@snicoll, since the backlog is an ordered list, any chance on this issue rising a bit on the ladder? Otherwise I'm afraid we won't be seeing this in 2.1 either. The fact that there's still an important part of Spring Boot that requires setters is something that I'd love to see fixed sooner than later.

Comment From: philwebb

I think we should hold off on this one until we see how immutable constructor based properties work out.

Comment From: philwebb

We've decided not to investigate this for now for the reason mentioned above.

Comment From: thekalinga

immutable constructor based properties

Is there a problem with this?

Comment From: snicoll

@thekalinga no, that's why we've decided to close this one. We recommend using immutable configuration properties and we feel interface binding is very similar and not worth investigating any further at this point.

Comment From: kiriakos

@snicoll please help me understand this, if I read the docs correctly the immutable config props proposal is doing something like this:

@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
    private final boolean enabled;
    public AcmeProperties(boolean enabled) {
        this.enabled = enabled;
    }
    public isEnabled(){
        return enabled;
    }
}

(simplified from example) how does this compare to simply declaring

@ConfigurationProperties("acme")
public interface AcmeProperties {
    public isEnabled()
}

The one is imperative and wordy the other is a succinct declaration. Are there any non apparent drawbacks that I'm missing here?

Thanks

EDIT: whitespace

Comment From: philwebb

Are there any non apparent drawbacks that I'm missing here?

The drawbacks are not really technical but more to do with where we should invest our time. Our experience with immutable configuration properties has shown that there are quite a few things that we need to consider when changing the configuration properties model (and these are often quite time consuming). For example, one problem that's often overlooked is the generation of the meta-data file that's used to provide IDE support.

Closing this issue doesn't mean that interface based properties are something that we'll never consider. We may well decide to re-open this one again in the future. For now though, we think that it's best if we see how useful people find constructor binder and how many problems the new code causes.

Comment From: dragneelfps

Can this be reopened it as we already have support for constructor based immutable properties? (at least in Kotlin afaik)

Comment From: laxika

@dragneelfps

You can already do this add the following annotation to your application class:

@ConfigurationPropertiesScan(basePackages = "com.github.loa")

Then you can create a configuration properties class with final values like this:

package com.github.loa.vault.configuration;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;

/**
 * Holds the configuration properties to the vault.
 */
@Getter
@ConstructorBinding
@RequiredArgsConstructor
@ConfigurationProperties("loa.vault")
public class VaultConfigurationProperties {

    /**
     * The unique name of the vault. This name will be saved when archiving new documents and will be used to identify
     * the vault that holds a given document. Do not change this after creating the vault because the documents
     * previously archived by this vault are not going to be accessible.
     */
    private final String name;

    /**
     * If this vault should be able to modify documents (e.g. remove) after they are archived. If your vault is available
     * publicly on the internet then set this to false!
     */
    private final boolean modificationEnabled;

    /**
     * If this vault should archive new documents.
     */
    private final boolean archiving;

    /**
     * This version number will be saved to the database for every document that has been archived. It will be used
     * later on if it's necessary to run cleanup or fixing tasks that are specific to a given version.
     */
    private final int versionNumber;
}

Why is this not enough for your usecase? You want to set the values via reflection, without constructors?

Comment From: snicoll

@dragneelfps if you're willing us to reconsider, you'd have to provide a bit more context and justification. Immutable configuration properties are available for both Java and Kotlin and this comment still stands.

Comment From: krzyk

@dragneelfps You can also use records for that (or just pure immutable class like shown above). I'm not sure why you would prefer interface.

Comment From: dragneelfps

So, I have this scenario where there is supposed to be some base config and its different child which may override and add new properties to that config, as follows

http-base: &httpBase
  connect-timeout: 5s

connectors:
  clientA:
    <<: *httpBase
    clientId: foobar

One way to solve is using composition instead of inheritance, but lets talk about inheritance for a bit One possible way would be:

open class Base { lateinit var connectTimeout: Duration }
class ClientA(val clientId: String): Base()

The issue with above would be that the property check will throw error at runtime instead of start time when connectTimeout is missing. Also, it makes connectTimeout mutable, which I do not want.

Second way would be:

open class Base(val connectTimeout: Duration)
class ClientA(val clientId: String, connectTimeout: Duration): Base(connectTimeout)

Now, I do not want to write connectTimeout redundantly in ClientX classes. Same issue if I make Base an interface then it becomes

interface Base { val connectTImeout: Duration }
class ClientA(val clientId: String, override val connectTimeout: Duration): Base

Now, IMO, following would be best suited for this kind of usecase

interface Base { val connectTimeout: Duration }
interface Client { val clientId: String } : Base

It is clean and provides immutability and makes sense.

PS: A solution with a composition approach would be something like

class Base(val connectTimeout: Duration)
class ClientA(val clientId: String, val baseConfig: Base)

This has its own quirks, but it seems best solution compared to other currently possible ones.

PS-2: I would be more than happy if someone can suggest a cleaner solution other than the ones I mentioned.