Mastering Custom Type Converters for Spring Boot @ConfigurationProperties
Learn how to create and register custom type converters for Spring Boot @ConfigurationProperties, enabling seamless binding of complex objects from property files using @ConfigurationPropertiesBinding and BeanFactoryPostProcessor techniques, including code examples, configuration snippets, and two registration approaches for practical implementation.
Environment: Spring Boot 3.2.5
1. Introduction
@ConfigurationProperties is a Spring Boot annotation that binds properties from configuration files (application.properties or application.yml) to a Java bean, simplifying type‑safe injection. It is usually used together with @Component or @Configuration and a prefix to map properties.
Spring automatically converts common types (List, Integer, Date, etc.) but for custom types you need to implement a converter.
<code>@ConfigurationProperties(prefix = "pack.properties")
public class ConfigurationPropertiesBindingBean {
private String title;
private String name;
private PackObject object;
// getters, setters
}
public class PackObject {
private Integer age;
private String name;
// getters, setters
}
</code>Configuration file example:
<code>pack:
properties:
title: ConfigurationPropertiesBinding
name: Properties Config
object: 20,Pack
</code>The object value is a comma‑separated string that should be converted to a custom PackObject . Spring does not know how, so a custom converter is required.
2. Practical Example
2.1 Custom Type Converter
<code>public class StringToPackObject implements Converter<String, PackObject> {
@Override
public PackObject convert(String source) {
if (!StringUtils.hasLength(source)) {
return null;
}
String[] values = source.split(",");
if (values.length == 1) {
return null;
}
PackObject obj = new PackObject();
obj.setAge(Integer.valueOf(values[0]));
obj.setName(values[1]);
return obj;
}
}
</code>Spring discovers converters by implementing the Converter interface, or you can implement ConverterFactory for more flexibility.
<code>public class StringToPackObjectFactory implements ConverterFactory<String, PackObject> {
@Override
public <T extends PackObject> Converter<String, T> getConverter(Class<T> targetType) {
// TODO
}
}
</code>To register the converter you can use a BeanFactoryPostProcessor :
<code>public class PackConverterBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ConversionService conversionService = beanFactory.getConversionService();
if (conversionService instanceof ConfigurableConversionService ccs) {
ccs.addConverter(new StringToPackObject());
}
}
}
</code>After registration, a simple application can inject the bound bean:
<code>public class App implements CommandLineRunner {
@Resource
private ConfigurationPropertiesBindingBean bean;
@Override
public void run(String... args) throws Exception {
System.err.println(bean);
}
}
</code>Output example:
<code>xxxBean [title=xxxooo, name=admin, object=PackObject [age=20, name=Pack]]
</code>Alternatively, you can register the converter as a bean annotated with @Component and @ConfigurationPropertiesBinding :
<code>@Component
@ConfigurationPropertiesBinding
public class StringToPackObject implements Converter<String, PackObject> {
// ... implementation ...
}
</code>The @ConfigurationPropertiesBinding annotation works like a qualified bean name, allowing Spring to automatically pick up all Converter beans during property binding.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.