Complex type DefaultValue for ConfigurationProperties and ConstructorBinding

Viewed 1982

I want to have a immutable property class with all field by default. To include property into a library. I can create a immutable property class with simple type by default, but I can't with a complex type. Is there a way to set a default value for a complexe type into immutable ConfigurationProperties class ?

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

@ConfigurationProperties(prefix = "foo")
@ConstructorBinding
@Getter
public final class AnyProperties {
   private final String something
   private final AnySubProperties sub;

   public AnyProperties(
      @DefaultValue("foo") String something, 
      AnySubProperties sub // Any annotation here ? Like @DefaultValue
   ) {
       this.something = something;
       this.sub = sub; // Always null !
   }

   @Getter
   public static final class AnySubProperties {
       private String finalValue;

       public AnySubProperties(@DefaultValue("bar") String finalValue) {
          this.finalValue = finalValue;
       }
   }
}

In exemple sub is null if no properties defined (with yaml or property file).
I would like to have sub with setted finalValue (with bar value).

Thanks for answers.

EDIT with solution without annotation

I find a solution without annotation, but I'm a lazy boy, that why it isn't possible to have a solution with spring annotation ?

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

@ConfigurationProperties(prefix = "foo")
@ConstructorBinding
@Getter
public final class AnyProperties {
   private final String something
   private final AnySubProperties sub;

   @ConstructorBinding
   public AnyProperties(
      @DefaultValue("foo") String something, 
      AnySubProperties sub // Any annotation here ? Like @DefaultValue
   ) {
       this.something = something;
       this.sub = null != sub ? sub : new AnySubProperties();
   }

   @Getter
   public static final class AnySubProperties {
       private static final String DEFAULT_FINAL_VALUE = "bar";
       private String finalValue;

       public AnySubProperties() {
           this(DEFAULT_FINAL_VALUE);
       }

       @ConstructorBinding
       public AnySubProperties(@DefaultValue(DEFAULT_FINAL_VALUE) String finalValue) {
          this.finalValue = finalValue;
       }
   }
}
1 Answers

You were very close. You can simply add a @DefaultValue annotation to the field, without parameters, to the annotation:

public AnyProperties(
      @DefaultValue("foo") String something, 
      @DefaultValue AnySubProperties sub
   ) {
       this.something = something;
       this.sub = sub; // Always null !
   }

This way you don't need a default constructor for AnySubProperties. The remaining constructor will be used to create an instance of AnySubProperties with its default values.

Related