diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConverters.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConverters.java index 2792bb81b8..2ca518f800 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConverters.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConverters.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; @@ -63,6 +65,15 @@ public class HttpMessageConverters implements Iterable> NON_REPLACING_CONVERTERS = Collections.unmodifiableList(nonReplacingConverters); } + private static final Map, Class> EQUIVALENT_CONVERTERS; + + static { + Map, Class> equivalentConverters = new HashMap<>(); + putIfExists(equivalentConverters, "org.springframework.http.converter.json.MappingJackson2HttpMessageConverter", + "org.springframework.http.converter.json.GsonHttpMessageConverter"); + EQUIVALENT_CONVERTERS = Collections.unmodifiableMap(equivalentConverters); + } + private final List> converters; /** @@ -132,7 +143,12 @@ public class HttpMessageConverters implements Iterable> return false; } } - return ClassUtils.isAssignableValue(defaultConverter.getClass(), candidate); + Class converterClass = defaultConverter.getClass(); + if (ClassUtils.isAssignableValue(converterClass, candidate)) { + return true; + } + Class equivalentClass = EQUIVALENT_CONVERTERS.get(converterClass); + return equivalentClass != null && ClassUtils.isAssignableValue(equivalentClass, candidate); } private void configurePartConverters(AllEncompassingFormHttpMessageConverter formConverter, @@ -220,4 +236,13 @@ public class HttpMessageConverters implements Iterable> } } + private static void putIfExists(Map, Class> map, String keyClassName, String valueClassName) { + try { + map.put(Class.forName(keyClassName), Class.forName(valueClassName)); + } + catch (ClassNotFoundException | NoClassDefFoundError ex) { + // Ignore + } + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersTests.java index fb557cfc97..06a0184a6e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.http; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; @@ -28,6 +29,7 @@ import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.ResourceRegionHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter; +import org.springframework.http.converter.json.GsonHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter; import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; @@ -80,6 +82,16 @@ class HttpMessageConvertersTests { assertThat(converters.getConverters().indexOf(converter1)).isNotEqualTo(0); } + @Test + void addBeforeExistingEquivalentConverter() { + GsonHttpMessageConverter converter1 = new GsonHttpMessageConverter(); + HttpMessageConverters converters = new HttpMessageConverters(converter1); + List> converterClasses = converters.getConverters().stream().map(HttpMessageConverter::getClass) + .collect(Collectors.toList()); + assertThat(converterClasses).containsSequence(GsonHttpMessageConverter.class, + MappingJackson2HttpMessageConverter.class); + } + @Test void addNewConverters() { HttpMessageConverter converter1 = mock(HttpMessageConverter.class);