Spring treats conversion, presentation formatting, object binding, and validation as separate operations. A request parameter can therefore become a typed property and still produce structured errors without coupling the domain object to a web controller.
Conversion and Formatting #
ConversionService is the facade for type conversion. It can first answer
whether a conversion is available and then convert by raw class or by
TypeDescriptor, which preserves annotations and nested generic information.
The extension interfaces cover different requirements:
Converter<S, T>implements one strongly typed conversion.ConverterFactory<S, R>creates converters for a family of target subtypes, such asStringto any enum type.GenericConverterdeclares sets of convertible source/target pairs and receivesTypeDescriptorvalues for context-sensitive conversion.ConditionalGenericConvertercan also decide whether it matches a particular source and target.
final class StringToOrderId implements Converter<String, OrderId> {
@Override
public OrderId convert(String source) {
return new OrderId(UUID.fromString(source.strip()));
}
}Formatter<T> belongs to the presentation layer. Its Printer and Parser
operations use a Locale, which makes it suitable for numbers, dates, and
human-facing text. Use a converter for context-free type changes and a formatter
when textual representation depends on locale or UI policy. Register both
through FormatterRegistry; DefaultFormattingConversionService implements
both registry and conversion-service contracts.
Legacy JavaBeans Property Editors #
Spring still supports java.beans.PropertyEditor for compatibility.
PropertyEditor is stateful, works primarily through text and an internal
value, and is not thread-safe. The container consequently creates editors per
binding operation rather than sharing instances.
The JavaBeans convention looks for an editor named TypeEditor beside Type,
and PropertyEditorManager also supports explicit registration and search
paths. Spring adds PropertyEditorRegistry for type-wide or property-path
registration and PropertyEditorRegistrar for reusable registration logic.
BeanWrapper and DataBinder expose those registries.
New application conversion should use ConversionService; an editor remains
appropriate when integrating a JavaBeans API that requires one. An HTTP message
body is not generally decoded by a property editor: Spring MVC uses
HttpMessageConverter for body formats such as JSON.
Binding With DataBinder
#
DataBinder applies input property values to a target object. It resolves
nested property paths, invokes conversion or property editors, records failures
in a BindingResult, and can invoke validators.
var binder = new DataBinder(command, "order");
binder.setAllowedFields("customerId", "quantity");
binder.setConversionService(conversionService);
binder.addValidators(new OrderValidator());
binder.bind(propertyValues);
binder.validate();
BindingResult result = binder.getBindingResult();Binding untrusted input is a security boundary. Define allowed fields or use a dedicated command object rather than expose a broad domain object. A conversion failure becomes a field error instead of requiring an exception to escape the binding operation. Auto-growing nested paths and collections is configurable and should be bounded for attacker-controlled input.
Spring’s Validator Contract
#
A Spring Validator declares whether it supports a class and reports failures
through Errors:
final class OrderValidator implements Validator {
public boolean supports(Class<?> type) {
return OrderCommand.class.isAssignableFrom(type);
}
public void validate(Object target, Errors errors) {
var order = (OrderCommand) target;
ValidationUtils.rejectIfEmpty(errors, "customerId", "required");
if (order.quantity() <= 0) {
errors.rejectValue("quantity", "positive");
}
}
}Errors.pushNestedPath() and popNestedPath() let a composite validator report
child errors with correct paths. Error codes are logical identifiers; message
resolution can later select localized text.
Jakarta Bean Validation #
Spring 6 integrates with jakarta.validation Bean Validation 3.x.
LocalValidatorFactoryBean bootstraps a provider such as Hibernate Validator
and implements both Jakarta’s ValidatorFactory/Validator access and Spring’s
Validator interface. It participates in Spring lifecycle management and closes
the underlying factory on shutdown.
MVC binding can apply constraint annotations through @Valid or
@Validated. Method validation applies constraints to method parameters and
return values through Spring’s method-validation infrastructure. Validation
does not replace conversion: values must first be represented in the types on
which constraints operate.
Comments
Read or comment on GitHub (sign-in required to comment)