From 1187c3e5b806fb2c49b341a82f86bd8cbab2faf4 Mon Sep 17 00:00:00 2001 From: Olga Maciaszek-Sharma Date: Fri, 14 May 2021 17:15:31 +0200 Subject: [PATCH] Use WebConverters for Hateoas. (#543) --- .../openfeign/FeignClientsConfiguration.java | 29 +++--- .../hateoas/FeignHalAutoConfiguration.java | 32 ++----- .../hateoas/WebConvertersCustomizer.java | 41 +++++++++ .../support/EmptyObjectProvider.java | 54 +++++++++++ .../HttpMessageConverterCustomizer.java | 33 +++++++ .../openfeign/support/SpringDecoder.java | 36 ++++++-- .../openfeign/support/SpringEncoder.java | 34 +++++-- ...FeignHalAutoConfigurationContextTests.java | 28 +++--- .../FeignHalAutoConfigurationTests.java | 90 ------------------- 9 files changed, 220 insertions(+), 157 deletions(-) create mode 100644 spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/WebConvertersCustomizer.java create mode 100644 spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/EmptyObjectProvider.java create mode 100644 spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/HttpMessageConverterCustomizer.java delete mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationTests.java diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java index eda8d607..c1e378a0 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java @@ -47,6 +47,7 @@ import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.openfeign.clientconfig.FeignClientConfigurer; import org.springframework.cloud.openfeign.support.AbstractFormWriter; import org.springframework.cloud.openfeign.support.FeignEncoderProperties; +import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; import org.springframework.cloud.openfeign.support.PageableSpringEncoder; import org.springframework.cloud.openfeign.support.PageableSpringQueryMapEncoder; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; @@ -97,22 +98,25 @@ public class FeignClientsConfiguration { @Bean @ConditionalOnMissingBean - public Decoder feignDecoder() { - return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))); + public Decoder feignDecoder(ObjectProvider customizers) { + return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers))); } @Bean @ConditionalOnMissingBean @ConditionalOnMissingClass("org.springframework.data.domain.Pageable") - public Encoder feignEncoder(ObjectProvider formWriterProvider) { - return springEncoder(formWriterProvider, encoderProperties); + public Encoder feignEncoder(ObjectProvider formWriterProvider, + ObjectProvider customizers) { + return springEncoder(formWriterProvider, encoderProperties, customizers); } @Bean @ConditionalOnClass(name = "org.springframework.data.domain.Pageable") @ConditionalOnMissingBean - public Encoder feignEncoderPageable(ObjectProvider formWriterProvider) { - PageableSpringEncoder encoder = new PageableSpringEncoder(springEncoder(formWriterProvider, encoderProperties)); + public Encoder feignEncoderPageable(ObjectProvider formWriterProvider, + ObjectProvider customizers) { + PageableSpringEncoder encoder = new PageableSpringEncoder( + springEncoder(formWriterProvider, encoderProperties, customizers)); if (springDataWebProperties != null) { encoder.setPageParameter(springDataWebProperties.getPageable().getPageParameter()); @@ -133,13 +137,13 @@ public class FeignClientsConfiguration { @ConditionalOnMissingBean public Contract feignContract(ConversionService feignConversionService) { boolean decodeSlash = feignClientProperties == null || feignClientProperties.isDecodeSlash(); - return new SpringMvcContract(this.parameterProcessors, feignConversionService, decodeSlash); + return new SpringMvcContract(parameterProcessors, feignConversionService, decodeSlash); } @Bean public FormattingConversionService feignConversionService() { FormattingConversionService conversionService = new DefaultFormattingConversionService(); - for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) { + for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) { feignFormatterRegistrar.registerFormatters(conversionService); } return conversionService; @@ -154,7 +158,7 @@ public class FeignClientsConfiguration { @Bean @ConditionalOnMissingBean(FeignLoggerFactory.class) public FeignLoggerFactory feignLoggerFactory() { - return new DefaultFeignLoggerFactory(this.logger); + return new DefaultFeignLoggerFactory(logger); } @Bean @@ -165,14 +169,15 @@ public class FeignClientsConfiguration { } private Encoder springEncoder(ObjectProvider formWriterProvider, - FeignEncoderProperties encoderProperties) { + FeignEncoderProperties encoderProperties, ObjectProvider customizers) { AbstractFormWriter formWriter = formWriterProvider.getIfAvailable(); if (formWriter != null) { - return new SpringEncoder(new SpringPojoFormEncoder(formWriter), this.messageConverters, encoderProperties); + return new SpringEncoder(new SpringPojoFormEncoder(formWriter), messageConverters, encoderProperties, + customizers); } else { - return new SpringEncoder(new SpringFormEncoder(), this.messageConverters, encoderProperties); + return new SpringEncoder(new SpringFormEncoder(), messageConverters, encoderProperties, customizers); } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfiguration.java index e20d1f43..1a67fe1d 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfiguration.java @@ -16,26 +16,18 @@ package org.springframework.cloud.openfeign.hateoas; -import java.util.Collections; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.hateoas.RepresentationModel; -import org.springframework.hateoas.mediatype.hal.HalMediaTypeConfiguration; -import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter; - -import static org.springframework.hateoas.MediaTypes.HAL_JSON; +import org.springframework.hateoas.config.HateoasConfiguration; +import org.springframework.hateoas.config.WebConverters; /** * @author Hector Espert @@ -43,23 +35,15 @@ import static org.springframework.hateoas.MediaTypes.HAL_JSON; */ @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication -@ConditionalOnClass(RepresentationModel.class) +@ConditionalOnClass(WebConverters.class) @AutoConfigureAfter({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, - RepositoryRestMvcAutoConfiguration.class }) + RepositoryRestMvcAutoConfiguration.class, HateoasConfiguration.class }) public class FeignHalAutoConfiguration { @Bean - @ConditionalOnBean(HalMediaTypeConfiguration.class) - @ConditionalOnMissingBean - public TypeConstrainedMappingJackson2HttpMessageConverter halJacksonHttpMessageConverter( - ObjectProvider objectMapper, HalMediaTypeConfiguration halConfiguration) { - ObjectMapper mapper = objectMapper.getIfAvailable(ObjectMapper::new).copy(); - halConfiguration.configureObjectMapper(mapper); - TypeConstrainedMappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter( - RepresentationModel.class); - converter.setSupportedMediaTypes(Collections.singletonList(HAL_JSON)); - converter.setObjectMapper(mapper); - return converter; + @ConditionalOnBean(WebConverters.class) + HttpMessageConverterCustomizer webConvertersCustomizer(WebConverters webConverters) { + return new WebConvertersCustomizer(webConverters); } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/WebConvertersCustomizer.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/WebConvertersCustomizer.java new file mode 100644 index 00000000..79909862 --- /dev/null +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/WebConvertersCustomizer.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.openfeign.hateoas; + +import java.util.List; + +import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; +import org.springframework.hateoas.config.WebConverters; +import org.springframework.http.converter.HttpMessageConverter; + +/** + * @author Olga Maciaszek-Sharma + */ +public class WebConvertersCustomizer implements HttpMessageConverterCustomizer { + + private final WebConverters webConverters; + + public WebConvertersCustomizer(WebConverters webConverters) { + this.webConverters = webConverters; + } + + @Override + public void accept(List> httpMessageConverters) { + webConverters.augmentClient(httpMessageConverters); + } + +} diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/EmptyObjectProvider.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/EmptyObjectProvider.java new file mode 100644 index 00000000..35b55726 --- /dev/null +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/EmptyObjectProvider.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013-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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.openfeign.support; + +import java.util.function.Consumer; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectProvider; + +/** + * @author Olga Maciaszek-Sharma + */ +class EmptyObjectProvider implements ObjectProvider { + + @Override + public T getObject(Object... args) throws BeansException { + return null; + } + + @Override + public T getIfAvailable() throws BeansException { + return null; + } + + @Override + public T getIfUnique() throws BeansException { + return null; + } + + @Override + public T getObject() throws BeansException { + return null; + } + + @Override + public void forEach(Consumer action) { + // do nothing + } + +} diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/HttpMessageConverterCustomizer.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/HttpMessageConverterCustomizer.java new file mode 100644 index 00000000..f204637e --- /dev/null +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/HttpMessageConverterCustomizer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2016-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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.openfeign.support; + +import java.util.List; +import java.util.function.Consumer; + +import org.springframework.http.converter.HttpMessageConverter; + +/** + * Allows customising {@link HttpMessageConverter} objects passed via {@link Consumer} + * parameter. + * + * @author Olga Maciaszek-Sharma + * @since 3.1.0 + */ +public interface HttpMessageConverterCustomizer extends Consumer>> { + +} diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringDecoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringDecoder.java index 41aa94b4..b4ecd810 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringDecoder.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringDecoder.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; +import java.util.List; import feign.FeignException; import feign.Response; @@ -28,31 +29,48 @@ import feign.codec.DecodeException; import feign.codec.Decoder; import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.client.HttpMessageConverterExtractor; import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHeaders; /** * @author Spencer Gibb + * @author Olga Maciaszek-Sharma */ public class SpringDecoder implements Decoder { - private ObjectFactory messageConverters; + private final ObjectFactory messageConverters; + private final ObjectProvider customizers; + + /** + * @deprecated in favour of + * {@link SpringDecoder#SpringDecoder(ObjectFactory, ObjectProvider)} + */ + @Deprecated public SpringDecoder(ObjectFactory messageConverters) { + this(messageConverters, new EmptyObjectProvider<>()); + } + + public SpringDecoder(ObjectFactory messageConverters, + ObjectProvider customizers) { this.messageConverters = messageConverters; + this.customizers = customizers; } @Override public Object decode(final Response response, Type type) throws IOException, FeignException { if (type instanceof Class || type instanceof ParameterizedType || type instanceof WildcardType) { + List> converters = messageConverters.getObject().getConverters(); + customizers.forEach(customizer -> customizer.accept(converters)); @SuppressWarnings({ "unchecked", "rawtypes" }) - HttpMessageConverterExtractor extractor = new HttpMessageConverterExtractor(type, - this.messageConverters.getObject().getConverters()); + HttpMessageConverterExtractor extractor = new HttpMessageConverterExtractor(type, converters); return extractor.extractData(new FeignResponseAdapter(response)); } @@ -70,23 +88,23 @@ public class SpringDecoder implements Decoder { @Override public HttpStatus getStatusCode() throws IOException { - return HttpStatus.valueOf(this.response.status()); + return HttpStatus.valueOf(response.status()); } @Override public int getRawStatusCode() throws IOException { - return this.response.status(); + return response.status(); } @Override public String getStatusText() throws IOException { - return this.response.reason(); + return response.reason(); } @Override public void close() { try { - this.response.body().close(); + response.body().close(); } catch (IOException ex) { // Ignore exception on close... @@ -95,12 +113,12 @@ public class SpringDecoder implements Decoder { @Override public InputStream getBody() throws IOException { - return this.response.body().asInputStream(); + return response.body().asInputStream(); } @Override public HttpHeaders getHeaders() { - return getHttpHeaders(this.response.headers()); + return getHttpHeaders(response.headers()); } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java index 5cfd6011..1eff6374 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java @@ -24,6 +24,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.stream.Stream; import feign.RequestTemplate; @@ -34,6 +35,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.encoding.HttpEncoding; import org.springframework.http.HttpHeaders; @@ -68,19 +70,37 @@ public class SpringEncoder implements Encoder { private final FeignEncoderProperties encoderProperties; + private final ObjectProvider customizers; + public SpringEncoder(ObjectFactory messageConverters) { this(new SpringFormEncoder(), messageConverters); } + /** + * @deprecated in favour of + * {@link SpringEncoder#SpringEncoder(SpringFormEncoder, ObjectFactory, FeignEncoderProperties, ObjectProvider)} + */ + @Deprecated public SpringEncoder(SpringFormEncoder springFormEncoder, ObjectFactory messageConverters) { this(springFormEncoder, messageConverters, new FeignEncoderProperties()); } + /** + * @deprecated in favour of + * {@link SpringEncoder#SpringEncoder(SpringFormEncoder, ObjectFactory, FeignEncoderProperties, ObjectProvider)} + */ + @Deprecated public SpringEncoder(SpringFormEncoder springFormEncoder, ObjectFactory messageConverters, FeignEncoderProperties encoderProperties) { + this(springFormEncoder, messageConverters, encoderProperties, new EmptyObjectProvider<>()); + } + + public SpringEncoder(SpringFormEncoder springFormEncoder, ObjectFactory messageConverters, + FeignEncoderProperties encoderProperties, ObjectProvider customizers) { this.springFormEncoder = springFormEncoder; this.messageConverters = messageConverters; this.encoderProperties = encoderProperties; + this.customizers = customizers; } @Override @@ -96,7 +116,7 @@ public class SpringEncoder implements Encoder { } if (isMultipartType(requestContentType)) { - this.springFormEncoder.encode(requestBody, bodyType, request); + springFormEncoder.encode(requestBody, bodyType, request); return; } else { @@ -111,7 +131,9 @@ public class SpringEncoder implements Encoder { private void encodeWithMessageConverter(Object requestBody, Type bodyType, RequestTemplate request, MediaType requestContentType) { - for (HttpMessageConverter messageConverter : this.messageConverters.getObject().getConverters()) { + List> converters = messageConverters.getObject().getConverters(); + customizers.forEach(customizer -> customizer.accept(converters)); + for (HttpMessageConverter messageConverter : converters) { FeignOutputMessage outputMessage; try { if (messageConverter instanceof GenericHttpMessageConverter) { @@ -227,21 +249,21 @@ public class SpringEncoder implements Encoder { private final HttpHeaders httpHeaders; private FeignOutputMessage(RequestTemplate request) { - this.httpHeaders = getHttpHeaders(request.headers()); + httpHeaders = getHttpHeaders(request.headers()); } @Override public OutputStream getBody() throws IOException { - return this.outputStream; + return outputStream; } @Override public HttpHeaders getHeaders() { - return this.httpHeaders; + return httpHeaders; } public ByteArrayOutputStream getOutputStream() { - return this.outputStream; + return outputStream; } } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationContextTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationContextTests.java index 570a96fd..5ecaa1ae 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationContextTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationContextTests.java @@ -16,8 +16,8 @@ package org.springframework.cloud.openfeign.hateoas; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; @@ -27,19 +27,20 @@ import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; -import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.config.WebConverters; import static org.assertj.core.api.Assertions.assertThat; /** * @author Hector Espert + * @author Olga Maciaszek-Sharma */ -public class FeignHalAutoConfigurationContextTests { +class FeignHalAutoConfigurationContextTests { private WebApplicationContextRunner contextRunner; - @Before - public void setUp() { + @BeforeEach + void setUp() { contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, HypermediaAutoConfiguration.class, @@ -48,23 +49,18 @@ public class FeignHalAutoConfigurationContextTests { } @Test - public void testHalJacksonHttpMessageConverterIsNotLoaded() { + void shouldNotLoadWebConvertersCustomizerWhenNotWebConvertersNotInClasspath() { FilteredClassLoader filteredClassLoader = new FilteredClassLoader(RepositoryRestMvcConfiguration.class, - RepresentationModel.class); + WebConverters.class); contextRunner.withClassLoader(filteredClassLoader) - .run(context -> assertThat(context).doesNotHaveBean("halJacksonHttpMessageConverter")); + .run(context -> assertThat(context).doesNotHaveBean("webConvertersCustomizer")); } @Test - public void testHalJacksonHttpMessageConverterIsLoaded() { + void shouldLoadWebConvertersCustomizer() { FilteredClassLoader filteredClassLoader = new FilteredClassLoader(RepositoryRestMvcConfiguration.class); contextRunner.withClassLoader(filteredClassLoader) - .run(context -> assertThat(context).hasBean("halJacksonHttpMessageConverter")); - } - - @Test - public void testHalJacksonHttpMessageConverterIsNotLoadedUseRestDataMessageConverterInstead() { - contextRunner.run(context -> assertThat(context).hasBean("halJacksonHttpMessageConverter")); + .run(context -> assertThat(context).hasBean("webConvertersCustomizer")); } } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationTests.java deleted file mode 100644 index b2757760..00000000 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationTests.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2016-2020 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.openfeign.hateoas; - -import java.util.Collections; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.hateoas.mediatype.MessageResolver; -import org.springframework.hateoas.mediatype.hal.CurieProvider; -import org.springframework.hateoas.mediatype.hal.HalConfiguration; -import org.springframework.hateoas.mediatype.hal.HalMediaTypeConfiguration; -import org.springframework.hateoas.mediatype.hal.Jackson2HalModule; -import org.springframework.hateoas.server.LinkRelationProvider; -import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.springframework.hateoas.MediaTypes.HAL_JSON; - -/** - * @author Hector Espert - * @author Olga Maciaszek-Sharma - */ -@RunWith(MockitoJUnitRunner.class) -public class FeignHalAutoConfigurationTests { - - @Mock - private ObjectProvider halConfiguration; - - @Mock - private ObjectProvider objectMapper; - - @Mock - private LinkRelationProvider relProvider; - - @Mock - private ObjectProvider curieProvider; - - @Mock - private MessageResolver messageResolver; - - @InjectMocks - private FeignHalAutoConfiguration feignHalAutoConfiguration; - - @Test - public void halJacksonHttpMessageConverter() { - ObjectMapper mapper = new ObjectMapper(); - when(objectMapper.getIfAvailable(any())).thenReturn(mapper); - - when(halConfiguration.getIfAvailable(any())).thenReturn(mock(HalConfiguration.class)); - when(curieProvider.getIfAvailable(any())).thenReturn(mock(CurieProvider.class)); - - HalMediaTypeConfiguration halMediaTypeConfiguration = new HalMediaTypeConfiguration(relProvider, curieProvider, - halConfiguration, messageResolver, new DefaultListableBeanFactory()); - - TypeConstrainedMappingJackson2HttpMessageConverter converter = feignHalAutoConfiguration - .halJacksonHttpMessageConverter(objectMapper, halMediaTypeConfiguration); - - assertThat(converter).isNotNull(); - assertThat(converter.getObjectMapper()).isNotNull(); - assertThat(converter.getSupportedMediaTypes()).isEqualTo(Collections.singletonList(HAL_JSON)); - - assertThat(Jackson2HalModule.isAlreadyRegisteredIn(converter.getObjectMapper())).isTrue(); - } - -}