Spring Boot 3 Essentials: @Delimiter, Custom Converters, YAML & Filters

This guide walks you through powerful Spring Boot 3 features—including the @Delimiter annotation for automatic collection parsing, custom type converters for @Value, loading YAML files via a FactoryBean, a suite of ordered filters, and using DeferredImportSelector for conditional configuration imports.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Boot 3 Essentials: @Delimiter, Custom Converters, YAML & Filters

@Delimiter Annotation

The @Delimiter annotation can automatically split incoming string data (e.g., comma "," or pipe "|") into a Collection or array. Example:

public class User {
    private String name;
    private Integer age;
    @Delimiter(",")
    private List<String> addresses = new ArrayList<>();
    // getters, setters
}

@GetMapping("/user")
public Object users(User user) {
    System.out.println(user);
    return user;
}

When the endpoint is called, the address string is split by commas and populated into the list.

Custom @Value Type Conversion

Spring provides many default converters via DefaultConversionService#addDefaultConverters. For types that cannot be converted, you can define a custom converter. Example: converting a configuration string to an enum.

# Configuration
pack:
  payway: weixin
public enum PaywayEnum {
    WEIXIN("weixin"), ALIPAY("alipay"), BANK("bank");
    private final String code;
    PaywayEnum(String code) { this.code = code; }
    public String getCode() { return code; }
    public static PaywayEnum getEnum(String code) {
        return Arrays.stream(PaywayEnum.values())
                     .filter(e -> e.getCode().equals(code))
                     .findFirst()
                     .orElse(null);
    }
}
@Value("${pack.payway}")
private PaywayEnum payway;

If no converter is registered, the application fails with a conversion error. The following custom converter solves the problem:

public class StringToPaywayEnumConverter implements ConverterFactory<String, Enum> {
    @Override
    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnum();
    }
    private class StringToEnum<T extends Enum> implements Converter<String, T> {
        @Override
        public T convert(String source) {
            if (source.isEmpty()) return null;
            return (T) PaywayEnum.getEnum(source);
        }
    }
    public static Class<?> getEnumType(Class<?> targetType) {
        Class<?> enumType = targetType;
        while (enumType != null && !enumType.isEnum()) {
            enumType = enumType.getSuperclass();
        }
        if (enumType == null) {
            throw new IllegalArgumentException("Conversion error");
        }
        return enumType;
    }
}

Register this converter in the Spring container to enable the conversion.

Loading YAML Files

Standard @PropertySource only supports .properties. To load a .yml file, define a YamlPropertiesFactoryBean and expose it as a bean.

@Configuration
@PropertySource("config.properties")
public class AppConfig {}

// pack.yml
pack:
  title: xxxooo
  author: pack
@Bean
public YamlPropertiesFactoryBean packYaml(@Value("classpath:pack.yml") Resource resource) {
    YamlPropertiesFactoryBean bean = new YamlPropertiesFactoryBean();
    bean.setResources(resource);
    return bean;
}
@Resource
private Properties packYaml;

The bean returns a Properties object that can be injected wherever needed.

Convenient Ordered Filters

OrderedCharacterEncodingFilter – Handles request/response character encoding.

OrderedFormContentFilter – Parses form data for PUT, PATCH, DELETE when Content-Type is application/x-www-form-urlencoded.

OrderedHiddenHttpMethodFilter – Simulates HTTP methods (PUT, DELETE, PATCH) via a hidden _method field in forms.

OrderedRequestContextFilter – Binds the current request’s locale to the thread context (via LocaleContextHolder).

ApplicationContextHeaderFilter – Adds the application context ID to the response header X-Application-Context.

DeferredImportSelector

A DeferredImportSelector runs after all @Configuration beans have been processed, useful for conditional imports based on @Conditional. You can also set ordering by implementing Ordered or using @Order.

public class PackDeferredImportSelector implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // Import Config1 when Config2 is processed
        return new String[]{"com.pack.test.import_selector.Config1"};
    }
}

Example configuration classes:

public class C1 {
    @PostConstruct
    public void init() { System.err.println("C1 init..."); }
}
public class C2 {
    @PostConstruct
    public void init() { System.err.println("C2 init..."); }
}

@Configuration
public class Config1 {
    @PostConstruct
    public void init() { System.err.println("Config1 init..."); }
    @Bean C1 c1() { return new C1(); }
}

@Configuration
public class Config2 {
    @PostConstruct
    public void init() { System.err.println("Config2 init..."); }
    @Bean C2 c2() { return new C2(); }
}

When Config2 imports PackDeferredImportSelector, Spring logs show that Config1 processing is deferred until other configurations finish.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backend-developmentspring-bootYAMLCustom ConverterDeferredImportSelector
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

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.