Spring 4.2.3和fasterxml Jackson 2.7.0是不兼容的

从fasterxml.jackson 2.6.3迁移到2.7.0之后。 这是因为在Spring的AbstractJackson2HttpMessageConverter使用的public JavaType constructType(Type type, Class<?> contextType)方法被删除了。 如何解决这个问题? 我正在使用Spring 4.2.3。

 /signin/facebook java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.type.TypeFactory.constructType(Ljava/lang/reflect/Type;Ljava/lang/Class;)Lcom/fasterxml/jackson/databind/JavaType; at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.getJavaType(AbstractJackson2HttpMessageConverter.java:314) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canRead(AbstractJackson2HttpMessageConverter.java:146) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canRead(AbstractJackson2HttpMessageConverter.java:141) at org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback.doWithRequest(RestTemplate.java:706) at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:770) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:594) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:357) at org.springframework.social.oauth2.OAuth2Template.postForAccessGrant(OAuth2Template.java:242) at org.springframework.social.oauth2.OAuth2Template.exchangeForAccess(OAuth2Template.java:144) at org.springframework.social.connect.web.ConnectSupport.completeConnection(ConnectSupport.java:160) at org.springframework.social.connect.web.ProviderSignInController.oauth2Callback(ProviderSignInController.java:228) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:44) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737) 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.doGet(FrameworkServlet.java:861) at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) 

支持Jackson 2.7将在Spring 4.3中添加。 请参阅https://jira.spring.io/browse/SPR-13483

现在,如果不提供自己的集成类,就无法使用它。

最好的兼容版本

1)Spring 4.2.4与更快的xml Jackson 2.7.2或2.8.4一起工作

2)Spring 4.3.5与更快的xml Jackson 2.7.0一起工作

我需要重写MappingJackson2HttpMessageConverter使一切工作(主要是generics)。 实际上它只是从Spring MVC 4.3 master抓取了MappingJackson2HttpMessageConverter

 public class MappingJackson27HttpMessageConverter extends MappingJackson2HttpMessageConverter { public MappingJackson27HttpMessageConverter() { } public MappingJackson27HttpMessageConverter(ObjectMapper objectMapper) { super(objectMapper); } @Override public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) { JavaType javaType = getJavaType(type, contextClass); if (!logger.isWarnEnabled()) { return (this.objectMapper.canDeserialize(javaType) && canRead(mediaType)); } AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>(); if (this.objectMapper.canDeserialize(javaType, causeRef) && canRead(mediaType)) { return true; } Throwable cause = causeRef.get(); if (cause != null) { String msg = "Failed to evaluate deserialization for type " + javaType; if (logger.isDebugEnabled()) { logger.warn(msg, cause); } else { logger.warn(msg + ": " + cause); } } return false; } @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { if (!logger.isWarnEnabled()) { return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType)); } AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>(); if (this.objectMapper.canSerialize(clazz, causeRef) && canWrite(mediaType)) { return true; } Throwable cause = causeRef.get(); if (cause != null) { String msg = "Failed to evaluate serialization for type [" + clazz + "]"; if (logger.isDebugEnabled()) { logger.warn(msg, cause); } else { logger.warn(msg + ": " + cause); } } return false; } @Override protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType()); JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding); try { writePrefix(generator, object); Class<?> serializationView = null; FilterProvider filters = null; Object value = object; JavaType javaType = null; if (object instanceof MappingJacksonValue) { MappingJacksonValue container = (MappingJacksonValue) object; value = container.getValue(); serializationView = container.getSerializationView(); filters = container.getFilters(); } if (type != null && value != null && TypeUtils.isAssignable(type, value.getClass())) { javaType = getJavaType(type, null); } ObjectWriter objectWriter; if (serializationView != null) { objectWriter = this.objectMapper.writerWithView(serializationView); } else if (filters != null) { objectWriter = this.objectMapper.writer(filters); } else { objectWriter = this.objectMapper.writer(); } if (javaType != null && javaType.isContainerType()) { objectWriter = objectWriter.forType(javaType); } objectWriter.writeValue(generator, value); writeSuffix(generator, object); generator.flush(); } catch (JsonProcessingException ex) { throw new HttpMessageNotWritableException("Could not write content: " + ex.getMessage(), ex); } } /** * Return the Jackson {@link JavaType} for the specified type and context * class. * <p> * The default implementation returns * {@code typeFactory.constructType(type, contextClass)}, but this can be * overridden in subclasses, to allow for custom generic collection * handling. For instance: * <pre class="code"> * protected JavaType getJavaType(Type type) { if (type instanceof Class && * List.class.isAssignableFrom((Class)type)) { return * TypeFactory.collectionType(ArrayList.class, MyBean.class); } else { * return super.getJavaType(type); } } * </pre> * * @param type the generic type to return the Jackson JavaType for * @param contextClass a context class for the target type, for example a * class in which the target type appears in a method signature (can be * {@code null}) * @return the Jackson JavaType */ @Override protected JavaType getJavaType(Type type, Class<?> contextClass) { TypeFactory typeFactory = this.objectMapper.getTypeFactory(); if (type instanceof TypeVariable && contextClass != null) { ResolvableType resolvedType = resolveVariable( (TypeVariable<?>) type, ResolvableType.forClass(contextClass)); if (resolvedType != ResolvableType.NONE) { return typeFactory.constructType(resolvedType.resolve()); } } return typeFactory.constructType(type); } private ResolvableType resolveVariable(TypeVariable<?> typeVariable, ResolvableType contextType) { ResolvableType resolvedType; if (contextType.hasGenerics()) { resolvedType = ResolvableType.forType(typeVariable, contextType); if (resolvedType.resolve() != null) { return resolvedType; } } resolvedType = resolveVariable(typeVariable, contextType.getSuperType()); if (resolvedType.resolve() != null) { return resolvedType; } for (ResolvableType ifc : contextType.getInterfaces()) { resolvedType = resolveVariable(typeVariable, ifc); if (resolvedType.resolve() != null) { return resolvedType; } } return ResolvableType.NONE; } }