Backend Development 6 min read

How to Build a Custom Annotation‑Based Data Formatter in Spring Boot

This tutorial demonstrates how to create a custom annotation and formatter in Spring Boot 3.2.5 to automatically convert request parameters like "666,China" into a User object, covering the required interfaces, implementation, registration, and testing with code examples and screenshots.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How to Build a Custom Annotation‑Based Data Formatter in Spring Boot

1. Introduction

Spring MVC provides powerful data type conversion, automatic binding, and formatting, but its default binding may not satisfy custom business needs such as parsing a specially formatted string into a custom object. Spring allows developers to create custom annotations and formatters to handle such conversions.

2. Practical Example

2.1 Goal

The aim is to bind a request parameter to a User object simply by adding a custom annotation on the method parameter, e.g. @UserFormat .

<code>@GetMapping("/user")</code>
<code>public User getUser(@UserFormat User user) {</code>
<code>    return user;</code>
<code>}</code>

2.2 Custom Annotation Formatter Factory

To enable annotation‑driven formatting, implement the AnnotationFormatterFactory interface.

<code>// The generic type is the annotation we will use to mark the parameter
public interface AnnotationFormatterFactory&lt;A extends Annotation&gt; {
    // Which field types can be annotated
    Set&lt;Class&lt;?&gt;&gt; getFieldTypes();
    // Convert object to String
    Printer&lt;?&gt; getPrinter(A annotation, Class&lt;?&gt; fieldType);
    // Parse String to object
    Parser&lt;?&gt; getParser(A annotation, Class&lt;?&gt; fieldType);
}</code>

2.3 Formatter Implementation

<code>public class StringToUserFormatter implements AnnotationFormatterFactory&lt;UserFormat&gt; {
    @Override
    public Set&lt;Class&lt;?&gt;&gt; getFieldTypes() {
        return Set.of(User.class);
    }
    @Override
    public Printer&lt;User&gt; getPrinter(UserFormat annotation, Class&lt;?&gt; fieldType) {
        return (object, locale) -> object.toString();
    }
    @Override
    public Parser&lt;User&gt; getParser(UserFormat annotation, Class&lt;?&gt; fieldType) {
        return (text, locale) -> {
            Assert.hasText(text, "Data error");
            String[] s = text.split(",");
            User user = new User();
            user.setId(Long.parseLong(s[0]));
            user.setName(s[1]);
            return user;
        };
    }
}</code>

2.4 Custom Annotation

<code>@Retention(RetentionPolicy.RUNTIME)</code>
<code>@Target(ElementType.PARAMETER)</code>
<code>public @interface UserFormat {}</code>

2.5 Register Formatter

<code>@Component
public class WebDataTypeConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatterForFieldAnnotation(new StringToUserFormatter());
    }
}</code>

2.6 Testing the Parameter Annotation

<code>@GetMapping("/user")
public User getUser(@UserFormat User user) {
    return user;
}</code>

When calling http://localhost:9001/api/objects/user?user=666,China , the request is correctly converted to a User instance.

2.7 Using the Annotation on a Field

<code>public static class DTO {
    @UserFormat
    private User user;
    private Integer age;
}</code>
<code>// Note: keep it as GET, not POST with @RequestBody
@GetMapping("/dto")
public DTO save(DTO dto) {
    return dto;
}</code>

Calling the /dto endpoint also yields the correctly populated DTO object.

Spring BootCustom AnnotationWeb MVCAnnotationFormatterFactoryData Formatter
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.