atoua
atoua

Reputation: 31

Spring boot and arguments validation

I'm writing a Spring boot application and I would like to validate that all expected arguments or externalized properties are set before that my application run. When I can do it ? I find commons-cli or args4j libraries but I don't how use it with a Spring boot application and if it is a good solution. Thanks

Upvotes: 0

Views: 3889

Answers (4)

Woodchuck
Woodchuck

Reputation: 4474

Another approach is to create a @ConfigurationProperties class that implements Validator:

@Data
@Validated
@ConfigurationProperties(prefix="my")
public class AppProperties implements Validator {

    private String name;
    private List<String> validNames;

    @Override
    public boolean supports(Class<?> clazz) {
        return AppProperties.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        AppProperties config = (AppProperties) target;

        ValidationUtils.rejectIfEmpty(
            errors, "name", "required-field", "name is required");

        if (!config.validApiNames.contains(config.apiName)) {
            errors.rejectValue("apiName " + apiName, "invalid");
        }
    }
}

And make sure to enable your ConfigurationProperties class via @EnableConfigurationProperties:

@SpringBootApplication
@EnableConfigurationProperties(AppProperties.class)
public class Application {
  // ...
}

The above should work where you have something like this in application.properties:

validNames=name1,name2
name=name1

I added the check against valid values mostly as a usage example. But it does guard against invalid command line arguments (which, when provided, override those in application.properties).

Note the prefix parameter on ConfigurationProperties is optional as of around Spring Boot 2.6.3.

Upvotes: 0

MaCloudR
MaCloudR

Reputation: 11

First, Use @Validated annotation to enable property validation. Then configure the appropriate fields for the way you want to check them, for example, using a regular expression (@Pattern annotation).

Example configuration bean with two fields set:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

@Data
@Validated
@Configuration
@ConfigurationProperties(prefix = "mail-service")
public class MailServiceConfiguration {

    @Min(1)
    @Max(20)
    private int numberOfThreads;

    @NotBlank
    @Pattern(regexp = "/^[A-Za-z0-9]{3,10}$/"
            , message = "No special characters"
    )
    private String clientType;

}

My invalid configuration from aplpication.properties:

mail-service.numberOfThreads=21
mail-service.clientType=***

... and the message spring generated after attempting to run:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'mail-service' to com.MailServiceConfiguration failed:

    Property: mail-service.numberOfThreads
    Value: 21
    Origin: class path resource [application.properties]:1:30
    Reason: must be less than or equal to 20

    Property: mail-service.clientType
    Value: ***
    Origin: class path resource [application.properties]:2:25
    Reason: No special characters

Upvotes: 1

ndrone
ndrone

Reputation: 3572

There are several was of doing this. This link explains all that is available https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

If you are just checking for not null's then you can use @Value like so

@Configuration
public class ApplicationConfiguration
{
   @Value("${name}")
   private String name;
 }

with the about the application will halt on startup if the value null

If you have other properties that you need to make sure they have a specific value being set you can use @ConfigurationProperties

@ConfigurationProperties(prefix = "test")
public class ConfigProps
{
     private String name;

     public String getName()
     {
          return name;
     }
}

@Configuration
@EnableConfigurationProperties
public class AppConfig
{
     @Autowired
     public AppConfig(ConfigProps configProps)
     {
          if (!"test".equals(configProps.getName())
          {
               throw new IllegalArugmentException("name not correct value");
          }
     }
}

Upvotes: 1

Praneeth Ramesh
Praneeth Ramesh

Reputation: 3564

Put your Validation logic inside Spring boot main method. There is not separate way of using these libs in Spring boot application. U can add your validation code inside your main method, to parse the args and do the validation. U can use any args parser libs for this.

@SpringBootApplication
public class MyApplication{
    public static void main(String[] args){
        validateArguments(args);
        SpringApplication.run(MyApplication.class);
    }
    private static validateArguments(args){
        // validation logic - If validation fails throw IllegalStateException(); 
    }
}

Upvotes: 0

Related Questions