Injecting Lists, Arrays, Sets, and Maps in Spring Using @Value and EL
This article explains how to store and inject collection types such as List, Map, Set, and arrays from Spring configuration files using @Value, @ConfigurationProperties, and Spring Expression Language, while handling missing keys and reducing code‑configuration coupling.
In daily development, we often need to store collection types such as List or Map in configuration files. Spring natively supports these types, but using @Value directly can cause errors and tightly couple configuration with code.
By defining a simple configuration class annotated with @Configuration and @ConfigurationProperties("test") , we can map a List<String> property and inject it via @Autowired , eliminating the need for manual parsing. However, this still requires a dedicated class for each collection.
Using arrays offers a lightweight alternative: values can be defined as comma‑separated strings in .yml or .properties files and injected with @Value into String[] , int[] , or double[] fields. Adding a default value (e.g., "${test.array1:}" ) prevents errors when the key is missing, resulting in an empty array.
Arrays have clear advantages—no extra configuration class and concise syntax—but also drawbacks, such as the need to convert to List for typical operations like contains or foreach .
To combine the convenience of arrays with the flexibility of collections, we can leverage Spring Expression Language (EL). For a List , we can inject it with: @Value("#{'${test.list}'.split(',')}") private List<String> testList; and add a conditional default to handle missing keys: @Value("#{'${test.list:}'.empty ? null : '${test.list:}'.split(',')}") private List<String> testList;
Similar EL techniques apply to Set (using split and relying on deduplication) and Map . For maps, we can store JSON strings in the configuration and parse them with a custom decoder, for example: public class MapDecoder { public static Map decodeMap(String value) { try { return JSONObject.parseObject(value, new TypeReference >() {}); } catch (Exception e) { return null; } } } and inject with: @Value("#{T(com.github.jitwxs.demo.MapDecoder).decodeMap('${test.map1:}')}") private Map map1;
Note that @Value should not be used together with Lombok's @AllArgsConstructor , as this combination can cause bean creation errors.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
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.