0

I was looking to move away from @Value annotation to using @ConfigurationProperties primarily because I ended up having too many properties so adding all of them in the target class seemed to clutter the class with Value annotations and if I were to mark them as final then the constructor would have a long list of parameters.

application.properties

sms-gateway:
  sms:
    authorization:
      token: xyz
    username: abc
    password: pass
    url: http://example.com
    lynx:
      cmd: lynx -dump -display_charset=utf-8 <%= @sms-gateway_sms_url %>
    via:
      cmd: true
  admin:
    status:
      url: http://admin.example.com/status

SmsService.java

...

@Value("${sms-gateway.sms.url}")
private String url;

@Value("${sms-gateway.sms.username}")
private String username;

@Value("${sms-gateway.sms.password}")
private String password;

and so on ...

As an alternate @ConfigurationProperties allows you to have a dedicated class that groups together properties. However, you have end up binding it to a common namespace for the properties to bind with the fields of the class being annotated with @ConfigurationProperties.

SmsConfig.java

...

@Getter
@RequiredArgsConstructor
@Configuration
@ConfigurationProperties(prefix = "sms-gateway.sms")
public class SmsConfig.java {
  
  private final String username;
  private final String password;
  private final String url;
  ...
}

However to add other nested properties you would need to add classes for each of the nested properties along with @NestedConfigurationProperty to indicate that's a nested property. This could again get a bit out of hand if there are many nested properties.

My question is two fold -

  1. Is there a cleaner way to implement this without having to involve inner classes and binding the nested properties under a field in the same common namespace. For instance in the above example - How can we bind the authorization token or lynx command properties without having to add a single field inner or completely new classes.

  2. Is there a way to change the field names and bind those to the property names so say if I want a different name private final String SmsGatewayUsername and want to bind this to the username property ?

Thank you and much appreciated for any comments and answers !

1 Answers1

0
  1. No, you cannot change the structure. You can however bind a Map<String, Object> if you don't mind losing the bean typing.

  2. Properties are bound by bean properties, which are determined by the public getters and setters, not the field names. You could add a setter with any name you like, and with any logic you want inside it. To get really complex, you could write a custom bean property binder, but I don't recommend it for your use-case. The default one does things like converting kebab-case to camelCase.

Both your property names and your configuration classes should follow a logical structure, and it's far easier to deal with if they're the same structure.

OrangeDog
  • 36,653
  • 12
  • 122
  • 207