What is Spring's ConversionService, and how does it relate to converting a String from @Value into a typed field like an int or Duration?
answer
- canConvert + convert = two operations
- stateless, thread-safe, shared (unlike PropertyEditor)
- @Value resolves String then converts
- bean must be named 'conversionService'
- Boot: ApplicationConversionService (Duration, DataSize)
basics
~10 sConversionService is Spring's central component for converting one type to another (e.g. String to int). When @Value injects a text value, Spring uses it to coerce the String into the field's declared type.
solid answer
~40 sConversionService is Spring's central, type-safe SPI for converting a value from one type to another. Its two core methods are canConvert(sourceType, targetType) and convert(source, targetType). It replaces the old per-thread JavaBeans PropertyEditor mechanism with a single, stateless, thread-safe, shareable service. When you write @Value("${server.timeout}") Duration timeout, Spring resolves the placeholder to a String, then asks the ConversionService to convert that String to a Duration. In Spring Boot, ApplicationConversionService registers many defaults out of the box (String→Number, String→Enum, String→Duration like "10s", String→DataSize, delimited String→List). If no converter exists for the requested pair, it throws ConversionFailedException (or ConverterNotFoundException). You extend it by registering Converters and Formatters.
code
java · 13 linesimport org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.ConversionService;
ConversionService cs = DefaultConversionService.getSharedInstance();
Integer n = cs.convert("42", Integer.class); // 42
boolean b = cs.convert("true", Boolean.class); // true
DayOfWeek d = cs.convert("MONDAY", DayOfWeek.class); // enum via ConverterFactory
boolean ok = cs.canConvert(String.class, Integer.class); // true
// In a bean, @Value uses the container's ConversionService:
// @Value("${app.timeout:30s}") Duration timeout; // "30s" -> Duration (Boot)go deeper
Know it converts one type to another and that @Value uses it for String→typed injection.
Distinguish DefaultConversionService vs DefaultFormattingConversionService; know canConvert/convert and the exceptions.
Explain the naming requirement for @Value, PropertyEditor fallback, and Boot's ApplicationConversionService extras.
Reason about where the service lives (bean factory vs MVC vs manual), sharing/thread-safety, and how it underpins property binding.
## What ConversionService is `org.springframework.core.convert.ConversionService` is the central interface Spring uses to turn a value of one type into a value of another type — for example turning the `String` `"42"` into the `int` `42`, or `"10s"` into a `java.time.Duration`. It is the modern, unified replacement for the older JavaBeans `PropertyEditor` approach. The interface has four methods (two logical operations): - `boolean canConvert(Class<?> sourceType, Class<?> targetType)` — can I convert between these types? - `boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType)` — same, but `TypeDescriptor` also carries generics, annotations and field context. - `<T> T convert(Object source, Class<T> targetType)` — do the conversion. - `Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType)` — the rich variant used internally. ## Why it exists / key properties - **Stateless and thread-safe**: unlike a `PropertyEditor` (which holds a value between `setAsText`/`getValue` and therefore needs one instance per thread), a `ConversionService` is a single shared, immutable-in-use service. This makes it usable outside the web tier — in the core container, in configuration binding, anywhere. - **Central**: one service knows about all registered conversions. ## Common implementations - `GenericConversionService` — the base engine that also implements `ConverterRegistry` (so you can add converters to it). - `DefaultConversionService` — `GenericConversionService` pre-populated with common converters (String↔Number, String↔Boolean, String→Enum, collections/arrays, etc.). - `DefaultFormattingConversionService` — adds locale-aware `Formatter` support (dates, numbers) on top. - `ApplicationConversionService` (Spring Boot) — `DefaultFormattingConversionService` plus Boot extras like `String→Duration`, `String→DataSize`, delimited `String→Collection`, lenient enum parsing. ## How @Value uses it When you write `@Value("${app.timeout}") Duration timeout`: 1. The placeholder `${app.timeout}` is resolved by property sources to a raw `String` (e.g. `"30s"`). 2. The `ConfigurableBeanFactory` holds a `ConversionService` (set via `setConversionService`). If a bean **named `conversionService`** exists, Spring uses it for `@Value`; otherwise it falls back to a `SimpleTypeConverter` that uses `PropertyEditor`s. 3. Spring calls `convert("30s", Duration.class)` and injects the result. SpEL expressions inside `@Value` likewise use this service to coerce their result to the target type. ## Gotchas - If **no** converter is registered for the pair, `convert` throws `ConverterNotFoundException`; if a converter is found but blows up, you get `ConversionFailedException`. - Registering a custom core-container converter for `@Value` requires the bean to be named exactly `conversionService` (or wiring it into the bean factory), otherwise `@Value` won't see it — a very common surprise. - A `null` source: the service short-circuits and returns `null` for object targets (your `Converter` is never handed a `null`).
- What happens if no converter is registered for the requested source/target pair?convert() throws ConverterNotFoundException. If a converter is found but fails at runtime, you instead get ConversionFailedException, which wraps the underlying cause.
- Why must a custom core ConversionService bean be named 'conversionService' to affect @Value?ConfigurableBeanFactory looks up a bean by that conventional name to set as its conversionService. Any other name registers a service that MVC or manual code can use, but the bean factory won't pick it up for @Value coercion.