我正在从Spring 3.2.3.RELEASE迁移到Spring 4.2.0.RELEASE。 我卡住了,因为现有的测试开始失败。我的代码看起来像(简化):
@WebAppConfiguration
@ContextConfiguration(classes = [TestConfig.class])
class MvcTest extends Specification {
@Autowired
WebApplicationContext context
MockMvc mockMvc
@Subject
MyController controller
def setup() {
controller = new MyController()
mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
}
def "should not allow to save an invalid entity"() {
when:
def result = mockMvc.perform(post("/people")
.content('''{
"name": "",
"age": 21,
"sex": 1
}''')
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
then:
result.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath('$.message').value("Name cannot be empty."))
}
}
MyController.java
@Controller
public class MyController {
@RequestMapping(method = RequestMethod.POST,
value = "/people",
produces = "application/json",
consumes = "application/json")
@ResponseBody
public Response create(@RequestBody @Valid Person person) {
//save person to repository. Debugger is not even entering this line...
}
}
Person.java:
public class Person {
private int age;
@NotEmpty(message = "Name cannot be empty.")
private String name;
@NotNull
@JsonSerialize(using = SexTypeSerializer.class)
@JsonDeserialize(using = SexTypeDeserializer.class)
private Sex sex;
//getters, setters, other methods
}
TestConfig.groovy
@EnableWebMvc
@Configuration
class TestConfig {
@Bean
@Primary
public ObjectMapper objectMapper() {
def objectMapper = new ObjectMapper()
def jacksonModule = new SimpleModule()
jacksonModule.addDeserializer(Sex.class, new SexTypeDeserializer())
jacksonModule.addSerializer(Sex.class, new SexTypeSerializer())
objectMapper.registerModule(jacksonModule)
objectMapper
}
}
堆栈跟踪:
java.lang.UnsupportedOperationException
at org.springframework.test.web.servlet.setup.StubWebApplicationContext$StubBeanFactory.createBean(StubWebApplicationContext.java:369)
at org.springframework.http.converter.json.SpringHandlerInstantiator.deserializerInstance(SpringHandlerInstantiator.java:68)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.deserializerInstance(DefaultDeserializationContext.java:111)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findDeserializerFromAnnotation(BasicDeserializerFactory.java:1436)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.constructSettableProperty(BeanDeserializerFactory.java:765)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:544)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:270)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:168)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:401)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:350)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:263)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:243)
at com.fasterxml.jackson.databind.deser.DeserializerCache.hasValueDeserializerFor(DeserializerCache.java:193)
at com.fasterxml.jackson.databind.DeserializationContext.hasValueDeserializerFor(DeserializationContext.java:344)
at com.fasterxml.jackson.databind.ObjectMapper.canDeserialize(ObjectMapper.java:2035)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canRead(AbstractJackson2HttpMessageConverter.java:151)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:187)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:148)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:125)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:688)
还提供了自定义序列化程序,并且与早期版本的spring一起正常工作。我认为配置有问题,因为这样的方法被调用:
StubWebApplicationContext.java
@Override
public <T> T createBean(Class<T> beanClass) {
throw new UnsupportedOperationException();
}
看起来应该使用createBean的其他一些实现。 任何想法问题在哪里?
答案 0 :(得分:3)
这是Spring Framework 4.1.3中引入的一个重大变化。
我创建了一个错误报告,以确保解决此问题:
https://jira.spring.io/browse/SPR-13375
感谢您注意这一点!
顺便说一句,当您使用MockMvcBuilders.standaloneSetup()
时,没有需要通过ApplicationContext
和@ContextConfiguration
加载@WebAppConfiguration
。如果您分析测试类,您会发现实际上甚至没有使用WebApplicationContext
进入测试的@Autowired
。因此,您可以安全地删除所有配置。
请注意,由于您使用TestConfig
直接测试控制器实例,MockMvc
中MockMvcBuilders.standaloneSetup()
<{1}}。换句话说,您的自定义SexTypeDeserializer
未在如此配置的测试中使用。如果您想继续使用独立设置,可以使用自定义配置MappingJackson2HttpMessageConverter
(以及自定义序列化程序等)配置ObjectMapper
并将其传递给StandaloneMockMvcBuilder
通过其setMessageConverters(...)
方法。
作为替代方案,您可以考虑使用MockMvcBuilders.webAppContextSetup(context)
以在测试中实际使用SexTypeDeserializer
以及其他生产的Spring MVC配置。