我正在努力从 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 的其他实现。 有什么想法问题出在哪里吗?
最佳答案
这是 Spring Framework 4.1.3 中引入的一项重大更改。
我创建了一个错误报告以确保该问题得到解决:
https://jira.spring.io/browse/SPR-13375
感谢您让我们注意到这一点!
顺便说一句,当您使用MockMvcBuilders.standaloneSetup()
时,不需要需要通过@加载
和 ApplicationContext
ContextConfiguration@WebAppConfiguration
。如果您分析您的测试类,您会发现实际上您甚至没有在测试中使用 @Autowired
中的 WebApplicationContext
。因此,您可以安全地删除所有该配置。
另请注意,您的 TestConfig
在 MockMvc
中未使用,因为您使用的是 MockMvcBuilders.standaloneSetup()
直接测试 Controller 的实例。换句话说,您的自定义 SexTypeDeserializer
不会在这样配置的测试中使用。如果您想继续使用独立设置,您可以使用自定义配置的 ObjectMapper
(以及自定义序列化器等)配置 MappingJackson2HttpMessageConverter
并将其传递通过其 setMessageConverters(...)
方法到 StandaloneMockMvcBuilder
。
作为替代方案,您可以考虑使用 MockMvcBuilders.webAppContextSetup(context)
,以便在测试中实际使用 SexTypeDeserializer
以及生产 Spring MVC 的其余部分配置。
关于java - 升级到新的 Spring 版本后 Spring MockMvc UnsupportedOperationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32101611/