web-dev-qa-db-ja.com

Spring 4.2.3とfasterxml Jackson 2.7.0には互換性がありません

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)
31
Marek Raszewski

Jackson 4.3のサポートは、Spring 4.3で追加されます。 https://jira.spring.io/browse/SPR-1348 を参照してください。

現時点では、独自の統合クラスを提供せずに使用することはできません。

36
M. Deinum

最高の互換バージョン

1)Spring 4.2.4は、fasterxml Jackson 2.7.2または2.8.4で動作します

2)Spring 4.3.5はfasterxml Jackson 2.7.0で動作します

3
Jagadish

すべてを機能させるために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;
    }

}
0
Ondrej Bozek