1

We're building a Spring-based application which will be delivered to end users as a distribution package. Users are responsible for properly configuring whatever needs to be configured (it's mostly about various filesystem locations, folder access permissions, etc). There's a good idea to make the app help users understand what is not configured or which parts of configuration are invalid.

Our current approach is a custom ApplicationContextInitializer which does all the environment validation "manually" and then registers few "low level" beans in the application context explicitly. If something is wrong, initializer throws, exception is caught somewhere in main(), interpreted (converted into plain English) and then displayed.

While this approach works fine, I'm wondering if there are any best practices to minimize hand-written code and use Spring whenever possible.

Here's an illustrative example. The application requires a folder for file uploads. This means:

  1. There should be a configuration file
  2. This file should be accessible by the app
  3. This file should have no syntax errors
  4. This file should explicitly define some specific property (let it be app.uploads.folder)
  5. This property should describe the existing filesystem entity
  6. This entity should be a folder
  7. The app should have read/write access to this folder

Does Spring provide any tools to implement this sort of validation easily?

Andrey Agibalov
  • 7,624
  • 8
  • 66
  • 111
  • possible duplicate of [Best practices for validating the configuration of a Spring web application](http://stackoverflow.com/questions/8832790/best-practices-for-validating-the-configuration-of-a-spring-web-application) – Andrey Agibalov Mar 19 '14 at 21:40
  • There's some overlap, but this question is better posed and more detailed IMO. – Dave Syer Mar 20 '14 at 07:45

1 Answers1

1

Spring Boot has a nice feature for context and external configuration validation. If you define a POJO class and declare it as @ConfigurationProperties then Spring will bind the Environment (external properties and System/OS typically) to its properties using a DataBinder. E.g.

@ConfigurationProperties(name="app.uploads")
public class FileUploadProperties {
    private File folder;
    // getters and setters ommitted
}

will bind to app.uploads.folder and ensure that it is a File. For extra validation you can do it manually in the setter, or you can implement Validator in your FileUploadProperties or you can use JSR-303 annotations on the fields. By default an external property in app.uploads.* that doesn't bind will throw an exception (e.g. a mis-spelled property name, or a conversion/format error).

If you use Spring Boot Autoconfigure @EnableAutoConfigure you don't have to do anything else, but if it's just vanilla Spring (Boot) you need to say @EnableConfigurationProperties in your @Configuration somewhere as well.

A bonus feature: if you also use the Spring Boot Actuator you will also get JMX and HTTP support (in a webapp) for inspecting the bindable and bound properties of @ConfigurationProperties beans. The HTTP endpoint is "/configprops".

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • Thanks a lot for you answer, Dave. This feature is definitely relevant, though I'm slightly confused that throwing from setter (`setFolder()` based on your example) doesn't actually affect anything: context is successfully initialized and the app runs as if there were no issues at all :-( – Andrey Agibalov Mar 22 '14 at 21:08
  • On the other hand, looks like it doesn't work without a setter at all - value is always null. – Andrey Agibalov Mar 22 '14 at 22:12
  • I it's a single valued field the setter should be called. If you want to paste an example into a github project I'll see if I can explain. – Dave Syer Mar 23 '14 at 06:47
  • Can't see anything wrong with that. Are you sure you have `app.uploads.folder` set somewhere to something that isn't a File? – Dave Syer Mar 23 '14 at 12:57
  • For all these experiments, the rest of the codebase and configuration files is absolutely the same. – Andrey Agibalov Mar 23 '14 at 13:52