如何将含嵌套对象的YAML映射为Java POJO并实现配置读取
问题场景与解决方案
一、实体类代码定义
// Product类 public class Product { private String name; private Long id; // 需添加构造方法、getter和setter } // Departament类 public class Departament { private String name; private Product product; // 需添加构造方法、getter和setter }
二、无法正常工作的YAML示例
这份YAML逻辑看似合理,但Spring的@ConfigurationProperties无法自动将部门配置中的产品名称转换为对应的Product对象,加载时会报错:
products: - name: "Laptop" id: 1 - name: "Phone" id: 2 departaments: - name: "Tech" product: "Laptop" # 直接写产品名称,Spring无法自动转为Product实例 - name: "Electronics" product: "Phone"
三、问题原因
Spring默认的配置属性绑定仅支持基础类型、简单嵌套对象的转换,无法自动根据字符串名称匹配已定义的Product对象,必须手动添加关联逻辑。
四、解决办法
方式一:配置类内手动关联
先加载所有产品与部门数据,再在配置类中完成对象匹配:
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Configuration @ConfigurationProperties(prefix = "") public class AppConfig { private List<Product> products; private List<Departament> departaments; // 属性加载完成后自动执行关联逻辑 @PostConstruct public void linkProductsToDepartments() { // 将产品转为「名称-对象」映射,方便快速查找 Map<String, Product> productMap = products.stream() .collect(Collectors.toMap(Product::getName, product -> product)); // 为每个部门匹配对应Product对象 departaments.forEach(dept -> { String productName = (String) dept.getProduct(); dept.setProduct(productMap.get(productName)); }); } // 必须添加getter、setter,Spring才能完成属性绑定 public List<Product> getProducts() { return products; } public void setProducts(List<Product> products) { this.products = products; } public List<Departament> getDepartaments() { return departaments; } public void setDepartaments(List<Departament> departaments) { this.departaments = departaments; } }
方式二:自定义类型转换器
编写转换器,让Spring知晓如何将字符串转换为Product对象:
import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Component public class StringToProductConverter implements Converter<String, Product> { private final Map<String, Product> productMap; // 构造注入所有产品,提前转为映射表 public StringToProductConverter(List<Product> products) { this.productMap = products.stream() .collect(Collectors.toMap(Product::getName, p -> p)); } @Override public Product convert(String productName) { return productMap.get(productName); } }
然后在Departament的product字段上添加转换注解:
import org.springframework.convert.converter.Converter; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Component public class StringToProductConverter implements Converter<String, Product> { private final Map<String, Product> productMap; // 构造注入所有产品,提前转为映射表 public StringToProductConverter(List<Product> products) { this.productMap = products.stream() .collect(Collectors.toMap(Product::getName, p -> p)); } @Override public Product convert(String productName) { return productMap.get(productName); } }
这种方式下原YAML无需修改,Spring会自动通过转换器完成名称到对象的映射。
五、验证
启动Spring应用后,注入AppConfig即可获取已关联对应Product对象的Departament列表。
内容的提问来源于stack exchange,提问作者roberto fernandez
相关产品推荐
相关产品推荐

