Я использую Spring Framework, версия 4.1.6, с веб-службами Spring и без Spring Boot. Чтобы узнать структуру, я пишу REST API и тестирую, чтобы убедиться, что ответ JSON, полученный от попадания в конечную точку, верен. В частности, я пытаюсь настроить ObjectMapper
PropertyNamingStrategy
, чтобы использовать стратегию именования "нижний регистр с подчеркиванием".
Я использую метод, подробно описанный в блоге Spring, чтобы создать новый ObjectMapper
и добавить его в список преобразователей. Это выглядит следующим образом:
package com.myproject.config;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = jacksonBuilder();
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
return builder;
}
}
Затем я запускаю следующий тест (используя JUnit, MockMvc и Mockito) для проверки моих изменений:
package com.myproject.controller;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
// Along with other application imports...
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebConfig.class}, loader = AnnotationConfigWebContextLoader.class)
public class MyControllerTest {
@Mock
private MyManager myManager;
@InjectMocks
private MyController myController;
private MockMvc mockMvc;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(this.myController).build();
}
@Test
public void testMyControllerWithNameParam() throws Exception {
MyEntity expected = new MyEntity();
String name = "expected";
String title = "expected title";
// Set up MyEntity with data.
expected.setId(1); // Random ID.
expected.setEntityName(name);
expected.setEntityTitle(title)
// When the MyManager instance is asked for the MyEntity with name parameter,
// return expected.
when(this.myManager.read(name)).thenReturn(expected);
// Assert the proper results.
MvcResult result = mockMvc.perform(
get("/v1/endpoint")
.param("name", name))
.andExpect(status().isOk())
.andExpect((content().contentType("application/json;charset=UTF-8")))
.andExpect(jsonPath("$.entity_name", is(name))))
.andExpect(jsonPath("$.entity_title", is(title)))
.andReturn();
System.out.println(result.getResponse().getContentAsString());
}
}
Однако это возвращает ответ:
{"id": 1, "entityName": "expected", "entityTitle": "expected title"}
Когда я получу:
{"id": 1, "entity_name": "expected", "entity_title": "expected title"}
У меня есть встроенный WebApplicationInitializer, который сканирует пакет:
package com.myproject.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.scan("com.myproject.config");
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
servletContext.addListener(new ContextLoaderListener(ctx));
}
}
Используя мой отладчик в IntelliJ, я вижу, что строитель создан и добавлен, но где-то по линии результирующий ObjectMapper
фактически не используется. Я должен что-то упустить, но все примеры, которые мне удалось найти, похоже, не говорят о том, что это такое! Я попытался исключить @EnableWebMvc
и реализовать WebMvcConfigurationSupport
, используя MappingJackson2HttpMessageConverter
как Bean и установить ObjectMapper
как Bean безрезультатно.
Любая помощь будет принята с благодарностью! Пожалуйста, дайте мне знать, если требуются другие файлы.
Спасибо!
РЕДАКТИРОВАТЬ: Проделал еще несколько операций по поиску и нашел этот. В ссылке автор добавляет setMessageConverters()
, прежде чем он построит MockMvc, и он работает для автора. Выполнение того же сработало и для меня; однако я не уверен, что все будет работать на производстве, поскольку хранилища еще не очищены. Когда я узнаю, я отправлю ответ.
ИЗМЕНИТЬ 2: См. ответ.