我们正在将 Spring Boot 应用程序(Spring Data Rest 与普通 mvc 的混合)从版本 2.5.12 迁移到 3.4.0。该应用程序很大程度上依赖于使用 https://docs.spring.io/spring-data/rest/docs/current/api/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.html 模块配置的 ObjectMapper。
应用程序使用 ObjectMapper 在补丁调用期间将带有嵌套子对象链接的 JSON 反序列化为实体。升级后,所有补丁调用在反序列化时都会失败。进一步的调查揭示了根本原因。 ObjectMapper.getRegisteredModuleIs() 显示为 Spring Boot 2.15 注册的 persistentEntityJackson2Module,并且在版本 3.4.0 中不显示此(或类似)模块
较旧的 Spring Boot 版本似乎会自动创建并配置此 persistentEntityJackson2Module ,而 3.4.0 版本则不会。
我们尝试实例化 PersistentEntityJackson2Module 类。不幸的是,这个类有太多的依赖项。其中一些需要大量的手动编码才能实现。我们用长而复杂的代码部分地完成了它。有什么简单的方法吗
有谁知道如何在 Spring Boot 3.4.0 中创建和配置 PersistentEntityJackson2Module 吗?
惯用示例:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
@Component
class PersistentEntityObjectMapperProvider {
@Autowired
private List<HttpMessageConverter<?>> defaultMessageConverters;
public ObjectMapper getObjectMapper() {
return defaultMessageConverters.stream()
//Able to find with Spring Boot 2.15 and unable with 3.4.0
.filter(c -> c.canRead(PersistentEntityResource.class, MediaType.APPLICATION_JSON))
.filter(c -> c instanceof MappingJackson2HttpMessageConverter).filter(Objects::nonNull)
.map(c -> ((MappingJackson2HttpMessageConverter) c).getObjectMapper())
.findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find ObjectMapper"));
//Tried multiple different ways to find object mappers. None of them contains PersistentEntityJackson2Module in spring boot version 3.4.0
}
}
@Data
@Entity
class Engine {
@Id
private Long id;
// other fields
}
@Data
@Entity
class Car {
@Id
private Long id;
private String model;
private int year;
@OneToOne(...)
private Engine engine;
//other fields
}
@Service
class CarAssembler {
@Autowired
PersistentEntityObjectMapperProvider provider;
/**
* Add parts to the car assembly
*
* @param car
* @param partsAsJsonString, e.g.: {"engine": "http://loclahost:8080/engines/123"}
* @throws IOException
*/
public void addParts(Car car, String partsAsJsonString) throws IOException {
ObjectMapper mapper = provider.getObjectMapper();
ObjectNode requestBodyObjectNode = (ObjectNode) mapper.readTree(partsAsJsonString);
var objectReader = mapper.readerForUpdating(car);
var updatedCar = objectReader.readValue(partsAsJsonString, Car.class);
//save updatedCar
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.webmvc.json.
PersistentEntityJackson2Module;
@Configuration
public class JacksonConfig {
@Bean
public PersistentEntityJackson2Module persistentEntityJackson2Module() {
return new PersistentEntityJackson2Module();
}
}