Spring Boot 3.4.0中如何配置PersistentEntityJackson2Module?
问题背景
我们正在将一个混合使用Spring Data Rest与普通MVC的Spring Boot应用从2.5.12版本迁移至3.4.0版本。该应用依赖配置了PersistentEntityJackson2Module的ObjectMapper,用于在Patch请求中将包含嵌套子对象链接的JSON反序列化为实体。升级后所有Patch请求均因反序列化失败报错,排查发现:Spring Boot 2.5.x会自动创建并配置persistentEntityJackson2Module,但3.4.0版本不再自动注册该模块。尝试手动实例化该类时,发现其依赖过多,手动实现需要大量代码,仅能通过冗长代码完成部分配置。
简便解决方案
Spring Data Rest内部依然维护着配置好PersistentEntityJackson2Module的ObjectMapper,无需手动从零构建,以下是几种可行的简便方案:
方案1:直接注入Spring Data Rest预配置的ObjectMapper
Spring Data Rest会单独创建一个带有PersistentEntityJackson2Module的ObjectMapper,可通过RepositoryRestConfiguration直接获取:
import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Component; @Component class PersistentEntityObjectMapperProvider { private final ObjectMapper restObjectMapper; // 构造注入RepositoryRestConfiguration,获取预配置的ObjectMapper public PersistentEntityObjectMapperProvider(RepositoryRestConfiguration restConfig) { this.restObjectMapper = restConfig.getObjectMapper(); } public ObjectMapper getObjectMapper() { return restObjectMapper; } }
此ObjectMapper已默认支持将子对象的URL链接反序列化为对应实体。
方案2:自定义全局ObjectMapper并注册模块
若需全局ObjectMapper具备该能力,可手动注册PersistentEntityJackson2Module,依赖Spring Data Rest的核心组件即可:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module; import org.springframework.data.rest.core.mapping.RepositoryMappings; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; @Configuration public class JacksonConfig { @Bean public ObjectMapper customObjectMapper(RepositoryRestConfiguration restConfig, RepositoryMappings repositoryMappings) { ObjectMapper objectMapper = new ObjectMapper(); // 创建并注册PersistentEntityJackson2Module PersistentEntityJackson2Module module = new PersistentEntityJackson2Module(restConfig, repositoryMappings); objectMapper.registerModule(module); // 可添加其他Jackson自定义配置 return objectMapper; } }
注意:此方案会替换全局ObjectMapper,需确保与普通MVC的Jackson配置兼容。
方案3:通过Spring Data Rest专属转换器获取
Spring Boot 3.x中,Spring Data Rest使用PersistentEntityJackson2HttpMessageConverter处理PersistentEntityResource,可直接过滤该类型转换器获取目标ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.stereotype.Component; import java.util.List; import java.util.Objects; @Component class PersistentEntityObjectMapperProvider { @Autowired private List<HttpMessageConverter<?>> defaultMessageConverters; public ObjectMapper getObjectMapper() { return defaultMessageConverters.stream() .filter(c -> c instanceof PersistentEntityJackson2HttpMessageConverter) .filter(Objects::nonNull) .map(c -> ((PersistentEntityJackson2HttpMessageConverter) c).getObjectMapper()) .findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find ObjectMapper")); } }
以上任一方案获取的ObjectMapper,均可在CarAssembler中正确反序列化类似{"engine": "http://localhost:8080/engines/123"}的JSON内容到实体对象。
内容的提问来源于stack exchange,提问作者AlexanderB

