Не отключается автоконфигурация ObjectMapper'а в тестах
Не отключается автоконфигурация ObjectMapper'а в тестах
Пытаюсь написать тесты для REST API с использованием кастомного (и в тестах, и в основной логике) ObjectMapper'а с включенной настройкой ACCEPT_SINGLE_VALUE_AS_ARRAY
. В основной логике все работает, а в тестах - нет. Насколько я понял, где-то включается автоконфигурация, хотя я ее вроде отключаю по крайней мере в аннотации @SpringBootTest
и @TestPropertySource
.
Тестовый класс:
@SpringBootTest(classes = {TaskManagerApplication.class, MvcConfig.class}, properties = {"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"
+ ",spring.main.allow-bean-definition-overriding=true"
+ ",spring.jackson.deserialization.ACCEPT_SINGLE_VALUE_AS_ARRAY=true"
+ ",org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration"})
@TestPropertySource(properties = {"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"
, "spring.main.allow-bean-definition-overriding=true"
, "spring.jackson.deserialization.ACCEPT_SINGLE_VALUE_AS_ARRAY=true"
, "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration"})
public class TaskManagerIntegrationTests {
@Autowired
private MappingJackson2HttpMessageConverter jackson2HttpMessageConverter;
@Autowired
@Qualifier("myObjectMapper")
private ObjectMapper objectMapper;
@Autowired
private PersonDetailsService personDetailsService;
@Autowired
private TaskService taskService;
@Autowired
private TaskRestController taskRestController;
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private List<Task> controlTasks;
@BeforeEach
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new TaskRestController())
.setMessageConverters(this.jackson2HttpMessageConverter)
.build();
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
fillTasksList();
}
@BeforeEach
public void fillTasksList() {
controlTasks = new ArrayList<>();
Person person = personDetailsService.findById(3L);
Task task1 = new Task();
task1.setTitle("IntegrationTestTask-1");
task1.setDescription("Task №1 for integration tests description");
task1.setPriority(Task.Priority.LOW);
task1.setStatus(Task.Status.AWAITING);
task1.setAuthor(person);
task1.setExecutor(person);
task1 = taskService.save(task1);
controlTasks.add(task1);
Task task2 = new Task();
task2.setTitle("Random Title");
task2.setDescription("Random Description");
task2.setAuthor(person);
task2.setExecutor(person);
task2.setPriority(Task.Priority.MEDIUM);
task2.setStatus(Task.Status.PROCESSING);
task2 = taskService.save(task2);
controlTasks.add(task2);
}
@AfterEach
public void clean() {
taskService.deleteById(controlTasks.get(0).getId());
taskService.deleteById(controlTasks.get(1).getId());
}
@Test
public void correctRequestOfSingleExistingTaskMustSucces() throws JsonProcessingException, Exception {
// здесь выводится true
System.out.println("ACCEPT_SINGLE_VALUE_AS_ARRAY is enabled: " + objectMapper.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
Map<String, String> request = new HashMap<>();
long id = controlTasks.get(0).getId();
request.put("id", String.valueOf(id));
mockMvc.perform(MockMvcRequestBuilders.get("/rest/tasks")
.contentType(MediaType.APPLICATION_JSON_VALUE).accept(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request)))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].id", Matchers.equalTo(id)));
}
}
При этом в первой строчке теста выводится true
, то есть строка:
ACCEPT_SINGLE_VALUE_AS_ARRAY is enabled: true
Но по факту эта настройка не используется. Пробовал некоторые варианты решения проблемы, все не перечислю.
Конфигурация:
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("").setViewName("index");
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jackson2HttpMessageConverter());
}
@Bean
public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(myObjectMapper());
return converter;
}
@Bean
HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new HiddenHttpMethodFilter();
}
@Bean
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
return new HandlerMappingIntrospector();
}
@Bean("myObjectMapper")
//@Primary
public ObjectMapper myObjectMapper() {
final ObjectMapper objectMapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
.addModule(new Hibernate6Module())
.addModule(new SimpleModule())
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
.configure(SerializationFeature.INDENT_OUTPUT, true)
.build();
return objectMapper;
}
@Bean
public Module datatypeHibernateModule() {
return new Hibernate6Module();
}
}
application-test.properties (практически идентично с application.properties):
spring.application.name=TaskManager
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/effective_mobile_test
spring.datasource.username=postgres
spring.datasource.password=postgres
jakarta.persistence.jdbc.url=jdbc:postgresql://localhost:5432/effective_mobile_test
spring.jackson.deserialization.ACCEPT_SINGLE_VALUE_AS_ARRAY=true
spring.jackson.serialization.fail-on-empty-beans=false
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
server.port=8080
spring.jpa.show-sql=true
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.thymeleaf.extras.springsecurity5.enabled=true
spring.mvc.hiddenmethod.filter.enabled=true
logging.level.org.hibernate.type.descriptor.sql=trace
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace
spring.mvc.format.date=dd-MM-yyyy
spring.mvc.format.date-time=dd-MM-yyyy HH:mm
spring.mvc.format.time=HH:mm:ss
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jackson.serialization.indent_output=true
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ru.terentyev</groupId>
<artifactId>TaskManager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>TaskManager</name>
<description>Web + REST Task Manager</description>
<properties>
<java.version>20</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate6</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Скажите, если надо добавить что-то еще из кода.