Fasterxml.jackson 2.6.3から2.7.0への移行後。これはpublic JavaType constructType(Type type, Class<?> contextType)
メソッドがSpringのAbstractJackson2HttpMessageConverter
除去された。これを修正する方法は? 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 4.3のサポートは、Spring 4.3で追加されます。 https://jira.spring.io/browse/SPR-1348 を参照してください。
現時点では、独自の統合クラスを提供せずに使用することはできません。
最高の互換バージョン
1)Spring 4.2.4は、fasterxml Jackson 2.7.2または2.8.4で動作します
2)Spring 4.3.5はfasterxml Jackson 2.7.0で動作します
すべてを機能させるためにMappingJackson2HttpMessageConverter
をオーバーライドする必要がありました(主にジェネリック)。実際、Spring MVC 4.3マスターから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;
}
}