Annotation Type Value


  • @Retention(RUNTIME)
    @Target({METHOD,FIELD,PARAMETER})
    public @interface Value
    Annotation used to customize behaviour of JavaBean deserialization support.

    The first option for generic Config to JavaBean deserialization works just with class with no-parameter constructor. Each JavaBean property value is then set by value mapped from appropriate configuration node. Each public setter method and public non-final fields are taken as JavaBean properties that will be set. The deserialization process is applied recursively on each property.

    Use Transient annotation to exclude setter or field from set of processed JavaBean properties.

    By default JavaBean property name is used as config key to get configuration node. The config key can be customized by key() attribute. Use the annotation on public setter or public field. Annotation on method has precedence over annotation used on field. The second one is ignored.

    If the appropriate configuration node does not exist it is possible to specify default value:

    • withDefaultSupplier() - instance of supplier class is used to get default value of target type; or
    • withDefault() - default value in String form that will be mapped to target type by associated config mapping function
    In case of both default attributes are set the withDefaultSupplier is used and withDefault is ignored.
    
     public class AppConfig {
         private String greeting;
         private int pageSize;
         private List<Integer> range;
    
         public AppConfig() { // <1>
         }
    
         public void setGreeting(String greeting) { // <2>
             this.greeting = greeting;
         }
    
         @Value(key = "page-size", withDefault = "10") // <3>
         public void setPageSize(int pageSize) {
             this.pageSize = pageSize;
         }
    
         @Value(withDefaultSupplier = DefaultRangeSupplier.class) // <4>
         public void setRange(List<Integer> basicRange) {
             this.range = basicRange;
         }
    
         //...
    
         public static class DefaultRangeSupplier // <5>
                     implements Supplier<List<Integer>> {
             @Override
             public List<Integer> get() {
                 return CollectionsHelper.listOf(0, 10);
             }
         }
     }
     
    1. public no-parameter constructor;
    2. property greeting is not customized; will be set from config node with greeting key, if exists;
    3. property pageSize customizes key of config node to page-size; if the config node does not exist, value "10" will be mapped to int;
    4. property range will be set from config node with same range key; if the config node does not exist, DefaultRangeSupplier instance will be used to get default value;
    5. DefaultRangeSupplier is used to supply List<Integer> value.

    The second option is to provide factory public static method from with parameters set from configuration. Or public "factory" constructor with parameters can be used too.

    
     public class AppConfig {
         private final String greeting;
         private final int pageSize;
         private final List<Integer> basicRange;
    
         private AppConfig(String greeting, int pageSize, List<Integer> basicRange) {
             this.greeting = greeting;
             this.pageSize = pageSize;
             this.basicRange = basicRange;
         }
    
         //...
    
         // FACTORY METHOD
         public static AppConfig create(@Value(key = "greeting", withDefault = "Hi")
                                      String greeting,
                                      @Value(key = "page-size", withDefault = "10")
                                      int pageSize,
                                      @Value(key = "basic-range",
                                              withDefaultSupplier = DefaultBasicRangeSupplier.class)
                                      List<Integer> basicRange) {
             return new AppConfig(greeting, pageSize, basicRange);
         }
     }
     

    The third option is to provide Builder accessible by public static builder() method. The Builder instances is initialized via public setters or fields, similar to the first deserialization option. Finally, Builder has build() method that creates new instances of a bean.

    
     public class AppConfig {
         private final String greeting;
         private final int pageSize;
         private final List<Integer> basicRange;
    
         private AppConfig(String greeting, int pageSize, List<Integer> basicRange) {
             this.greeting = greeting;
             this.pageSize = pageSize;
             this.basicRange = basicRange;
         }
    
         // BUILDER METHOD
         public static Builder builder() {
             return new Builder();
         }
    
         public static class Builder {
             private String greeting;
             private int pageSize;
             private List<Integer> basicRange;
    
             private Builder() {
             }
    
             @Value(withDefault = "Hi")
             public void setGreeting(String greeting) {
                 this.greeting = greeting;
             }
    
             @Value(key = "page-size", withDefault = "10")
             public void setPageSize(int pageSize) {
                 this.pageSize = pageSize;
             }
    
             @Value(key = "basic-range",
                     withDefaultSupplier = DefaultBasicRangeSupplier.class)
             public void setBasicRange(List<Integer> basicRange) {
                 this.basicRange = basicRange;
             }
    
             // BUILD METHOD
             public AppConfig build() {
                 return new AppConfig(greeting, pageSize, basicRange);
             }
         }
     }
     

    Configuration example:

    
     {
         "app": {
             "greeting": "Hello",
             "page-size": 20,
             "range": [ -20, 20 ]
         }
     }
     
    Getting app config node as AppConfig instance:
    
     AppConfig appConfig = config.get("app").as(AppConfig.class);
     assert appConfig.getGreeting().equals("Hello");
     assert appConfig.getPageSize() == 20;
     assert appConfig.getRange().get(0) == -20;
     assert appConfig.getRange().get(1) == 20;
     
    In this case default values where not used because JSON contains all expected nodes.

    The annotation cannot be applied on same JavaBean property together with Transient.

    See Also:
    Transient
    • Optional Element Summary

      Optional Elements 
      Modifier and Type Optional Element Description
      String key
      Specifies a key of configuration node to be used to set JavaBean property value from.
      String withDefault
      Specifies default value in form of single String value that will be used to set JavaBean property value in case configuration does not contain a config node of appropriate config key.
      Class<? extends Supplier<?>> withDefaultSupplier
      Specifies supplier of default value that will be used to set JavaBean property value in case configuration does not contain config node of appropriate config key.
    • Element Detail

      • key

        String key
        Specifies a key of configuration node to be used to set JavaBean property value from.

        If not specified original JavaBean property name is used.

        Returns:
        config property key
        Default:
        ""
      • withDefault

        String withDefault
        Specifies default value in form of single String value that will be used to set JavaBean property value in case configuration does not contain a config node of appropriate config key.

        In case withDefaultSupplier() is also used current value is ignored.

        Returns:
        single default value that will be converted into target type
        Default:
        "io.helidon.config:default=null"
      • withDefaultSupplier

        Class<? extends Supplier<?>> withDefaultSupplier
        Specifies supplier of default value that will be used to set JavaBean property value in case configuration does not contain config node of appropriate config key.

        Default value is used in case appropriate config value is not set. In case withDefault() is also used this one has higher priority and will be used.

        Returns:
        supplier that will provide default value in target type
        Default:
        io.helidon.config.objectmapping.Value.None.class