/* * Copyright 2013-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; import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.databind.Module; import feign.Contract; import feign.Feign; import feign.Logger; import feign.Retryer; import feign.codec.Decoder; import feign.codec.Encoder; import feign.form.MultipartFormContentProcessor; import feign.form.spring.SpringFormEncoder; import feign.optionals.OptionalDecoder; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.clientconfig.FeignClientConfigurer; import org.springframework.cloud.openfeign.support.AbstractFormWriter; import org.springframework.cloud.openfeign.support.PageJacksonModule; import org.springframework.cloud.openfeign.support.PageableSpringEncoder; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SortJacksonModule; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.core.convert.ConversionService; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; import static feign.form.ContentType.MULTIPART; /** * @author Dave Syer * @author Venil Noronha * @author Darren Foong */ @Configuration(proxyBeanMethods = false) public class FeignClientsConfiguration { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Autowired(required = false) private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>(); @Autowired(required = false) private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>(); @Autowired(required = false) private Logger logger; @Autowired(required = false) private SpringDataWebProperties springDataWebProperties; @Bean @ConditionalOnMissingBean public Decoder feignDecoder() { return new OptionalDecoder( new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))); } @Bean @ConditionalOnMissingBean @ConditionalOnMissingClass("org.springframework.data.domain.Pageable") public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) { return springEncoder(formWriterProvider); } @Bean @ConditionalOnClass(name = "org.springframework.data.domain.Pageable") @ConditionalOnMissingBean public Encoder feignEncoderPageable( ObjectProvider<AbstractFormWriter> formWriterProvider) { PageableSpringEncoder encoder = new PageableSpringEncoder( springEncoder(formWriterProvider)); if (springDataWebProperties != null) { encoder.setPageParameter( springDataWebProperties.getPageable().getPageParameter()); encoder.setSizeParameter( springDataWebProperties.getPageable().getSizeParameter()); encoder.setSortParameter( springDataWebProperties.getSort().getSortParameter()); } return encoder; } @Bean @ConditionalOnMissingBean public Contract feignContract(ConversionService feignConversionService) { return new SpringMvcContract(this.parameterProcessors, feignConversionService); } @Bean public FormattingConversionService feignConversionService() { FormattingConversionService conversionService = new DefaultFormattingConversionService(); for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) { feignFormatterRegistrar.registerFormatters(conversionService); } return conversionService; } @Bean @ConditionalOnMissingBean public Retryer feignRetryer() { return Retryer.NEVER_RETRY; } @Bean @Scope("prototype") @ConditionalOnMissingBean public Feign.Builder feignBuilder(Retryer retryer) { return Feign.builder().retryer(retryer); } @Bean @ConditionalOnMissingBean(FeignLoggerFactory.class) public FeignLoggerFactory feignLoggerFactory() { return new DefaultFeignLoggerFactory(this.logger); } @Bean @ConditionalOnClass(name = "org.springframework.data.domain.Page") public Module pageJacksonModule() { return new PageJacksonModule(); } @Bean @ConditionalOnClass(name = "org.springframework.data.domain.Page") public Module sortModule() { return new SortJacksonModule(); } @Bean @ConditionalOnMissingBean(FeignClientConfigurer.class) public FeignClientConfigurer feignClientConfigurer() { return new FeignClientConfigurer() { }; } private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) { AbstractFormWriter formWriter = formWriterProvider.getIfAvailable(); if (formWriter != null) { return new SpringEncoder(new SpringPojoFormEncoder(formWriter), this.messageConverters); } else { return new SpringEncoder(new SpringFormEncoder(), this.messageConverters); } } private class SpringPojoFormEncoder extends SpringFormEncoder { SpringPojoFormEncoder(AbstractFormWriter formWriter) { super(); MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor( MULTIPART); processor.addFirstWriter(formWriter); } } }