We are migrating the Spring Boot application (mixture of Spring Data Rest with plain vanilla mvc) from version 2.5.12 to 3.4.0. The application heavily depends on the ObjectMapper configured with https://docs.spring.io/spring-data/rest/docs/current/api/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.html module.
The application uses ObjectMapper to deserialize JSON with nested sub-object links into entities during patch calls. After the upgrade, all patch calls fail on deserialization. Further investigation reveals the root cause. ObjectMapper.getRegisteredModuleIs() shows registered persistentEntityJackson2Module for the Spring Boot 2.15 and does not show this (or a similar) module in version 3.4.0
It appears that the older Spring Boot version automatically creates and configures this persistentEntityJackson2Module , while version 3.4.0 does not.
We tried to instantiate the class PersistentEntityJackson2Module. Unfortunately, this class has too many dependencies. Some of them require a lot of manual coding to implement. We made it partially with long convoluted code. Is there any simple way?
Does anyone know how to create and configure PersistentEntityJackson2Module in Spring Boot 3.4.0?
Idiomatic example:
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();
}
}
Saurabh Singh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1