├── .editorconfig ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dco.yml ├── dependabot.yml └── workflows │ ├── deploy-docs.yml │ └── maven.yml ├── .gitignore ├── .java-version ├── .mvn ├── jvm.config ├── maven.config └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .sdkmanrc ├── .settings.xml ├── .springformat ├── Guardfile ├── LICENSE.txt ├── README.adoc ├── asciidoctor.css ├── codecov.yml ├── docs ├── antora-playbook.yml ├── antora.yml ├── modules │ └── ROOT │ │ ├── nav.adoc │ │ ├── pages │ │ ├── _attributes.adoc │ │ ├── appendix.adoc │ │ ├── configprops.adoc │ │ ├── index.adoc │ │ ├── intro.adoc │ │ └── spring-cloud-openfeign.adoc │ │ └── partials │ │ ├── _attributes.adoc │ │ ├── _configprops.adoc │ │ ├── _conventions.adoc │ │ ├── _metrics.adoc │ │ └── _spans.adoc ├── package.json ├── pom.xml └── src │ └── main │ ├── antora │ └── resources │ │ └── antora-resources │ │ └── antora.yml │ └── asciidoc │ ├── README.adoc │ ├── ghpages.sh │ ├── sagan-boot.adoc │ └── sagan-index.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml ├── spring-cloud-openfeign-core ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── cloud │ │ │ └── openfeign │ │ │ ├── AnnotatedParameterProcessor.java │ │ │ ├── CachingCapability.java │ │ │ ├── CircuitBreakerNameResolver.java │ │ │ ├── CollectionFormat.java │ │ │ ├── DefaultFeignLoggerFactory.java │ │ │ ├── DefaultTargeter.java │ │ │ ├── EnableFeignClients.java │ │ │ ├── FallbackFactory.java │ │ │ ├── FeignAutoConfiguration.java │ │ │ ├── FeignBuilderCustomizer.java │ │ │ ├── FeignCachingInvocationHandlerFactory.java │ │ │ ├── FeignCircuitBreaker.java │ │ │ ├── FeignCircuitBreakerDisabledConditions.java │ │ │ ├── FeignCircuitBreakerInvocationHandler.java │ │ │ ├── FeignCircuitBreakerTargeter.java │ │ │ ├── FeignClient.java │ │ │ ├── FeignClientBuilder.java │ │ │ ├── FeignClientFactory.java │ │ │ ├── FeignClientFactoryBean.java │ │ │ ├── FeignClientMicrometerEnabledCondition.java │ │ │ ├── FeignClientProperties.java │ │ │ ├── FeignClientSpecification.java │ │ │ ├── FeignClientsConfiguration.java │ │ │ ├── FeignClientsRegistrar.java │ │ │ ├── FeignErrorDecoderFactory.java │ │ │ ├── FeignFormatterRegistrar.java │ │ │ ├── FeignLoggerFactory.java │ │ │ ├── OptionsFactoryBean.java │ │ │ ├── PropertyBasedTarget.java │ │ │ ├── RefreshableHardCodedTarget.java │ │ │ ├── RefreshableUrl.java │ │ │ ├── RefreshableUrlFactoryBean.java │ │ │ ├── SpringQueryMap.java │ │ │ ├── Targeter.java │ │ │ ├── annotation │ │ │ ├── CookieValueParameterProcessor.java │ │ │ ├── MatrixVariableParameterProcessor.java │ │ │ ├── PathVariableParameterProcessor.java │ │ │ ├── QueryMapParameterProcessor.java │ │ │ ├── RequestHeaderParameterProcessor.java │ │ │ ├── RequestParamParameterProcessor.java │ │ │ └── RequestPartParameterProcessor.java │ │ │ ├── aot │ │ │ ├── FeignChildContextInitializer.java │ │ │ └── FeignClientBeanFactoryInitializationAotProcessor.java │ │ │ ├── clientconfig │ │ │ ├── FeignClientConfigurer.java │ │ │ ├── Http2ClientFeignConfiguration.java │ │ │ ├── HttpClient5FeignConfiguration.java │ │ │ └── http2client │ │ │ │ └── Http2ClientCustomizer.java │ │ │ ├── encoding │ │ │ ├── BaseRequestInterceptor.java │ │ │ ├── FeignAcceptGzipEncodingAutoConfiguration.java │ │ │ ├── FeignAcceptGzipEncodingInterceptor.java │ │ │ ├── FeignClientEncodingProperties.java │ │ │ ├── FeignContentGzipEncodingAutoConfiguration.java │ │ │ ├── FeignContentGzipEncodingInterceptor.java │ │ │ ├── HttpEncoding.java │ │ │ └── OkHttpFeignClientBeanMissingCondition.java │ │ │ ├── hateoas │ │ │ ├── FeignHalAutoConfiguration.java │ │ │ └── WebConvertersCustomizer.java │ │ │ ├── loadbalancer │ │ │ ├── DefaultFeignLoadBalancerConfiguration.java │ │ │ ├── FeignBlockingLoadBalancerClient.java │ │ │ ├── FeignLoadBalancerAutoConfiguration.java │ │ │ ├── Http2ClientFeignLoadBalancerConfiguration.java │ │ │ ├── HttpClient5FeignLoadBalancerConfiguration.java │ │ │ ├── LoadBalancerFeignRequestTransformer.java │ │ │ ├── LoadBalancerResponseStatusCodeException.java │ │ │ ├── LoadBalancerUtils.java │ │ │ ├── OkHttpFeignLoadBalancerConfiguration.java │ │ │ ├── OnRetryNotEnabledCondition.java │ │ │ ├── RetryableFeignBlockingLoadBalancerClient.java │ │ │ └── XForwardedHeadersTransformer.java │ │ │ ├── security │ │ │ └── OAuth2AccessTokenInterceptor.java │ │ │ └── support │ │ │ ├── AbstractFormWriter.java │ │ │ ├── EmptyObjectProvider.java │ │ │ ├── FeignEncoderProperties.java │ │ │ ├── FeignHttpClientProperties.java │ │ │ ├── FeignUtils.java │ │ │ ├── HttpMessageConverterCustomizer.java │ │ │ ├── JsonFormWriter.java │ │ │ ├── PageJacksonModule.java │ │ │ ├── PageableSpringEncoder.java │ │ │ ├── PageableSpringQueryMapEncoder.java │ │ │ ├── ResponseEntityDecoder.java │ │ │ ├── SortJacksonModule.java │ │ │ ├── SortJsonComponent.java │ │ │ ├── SpringDecoder.java │ │ │ ├── SpringEncoder.java │ │ │ └── SpringMvcContract.java │ └── resources │ │ └── META-INF │ │ ├── additional-spring-configuration-metadata.json │ │ └── spring │ │ ├── aot.factories │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── org │ │ └── springframework │ │ └── cloud │ │ └── openfeign │ │ ├── EagerInitFeignClientUsingConfigurerTests.java │ │ ├── EnableFeignClientsSpringDataTests.java │ │ ├── EnableFeignClientsTests.java │ │ ├── FeignAutoConfigurationTests.java │ │ ├── FeignBuilderCustomizerTests.java │ │ ├── FeignClientBuilderTests.java │ │ ├── FeignClientCacheTests.java │ │ ├── FeignClientConfigurationTests.java │ │ ├── FeignClientDisabledClientLevelFeaturesTests.java │ │ ├── FeignClientDisabledFeaturesTests.java │ │ ├── FeignClientErrorDecoderTests.java │ │ ├── FeignClientFactoryBeanIntegrationTests.java │ │ ├── FeignClientFactoryTest.java │ │ ├── FeignClientFactoryTests.java │ │ ├── FeignClientMicrometerEnabledConditionTests.java │ │ ├── FeignClientOverrideDefaultsTests.java │ │ ├── FeignClientPropertiesTests.java │ │ ├── FeignClientUsingPropertiesTests.java │ │ ├── FeignClientWithRefreshableOptionsTest.java │ │ ├── FeignClientsMicrometerAutoConfigurationTests.java │ │ ├── FeignClientsRegistrarIntegrationTests.java │ │ ├── FeignClientsRegistrarTests.java │ │ ├── FeignCompressionTests.java │ │ ├── FeignErrorDecoderFactoryTests.java │ │ ├── FeignHttp2ClientConfigurationTests.java │ │ ├── FeignHttpClient5ConfigurationTests.java │ │ ├── FeignHttpClientUrlTests.java │ │ ├── FeignHttpClientUrlWithRetryableLoadBalancerTests.java │ │ ├── FeignLoggerFactoryTests.java │ │ ├── FeignOkHttpConfigurationTests.java │ │ ├── GzipDecodingTests.java │ │ ├── LazyInitFeignClientUsingConfigurerTests.java │ │ ├── MicrometerPropertiesTests.java │ │ ├── NonRefreshableFeignClientUrlTests.java │ │ ├── OptionsTestClient.java │ │ ├── RefreshableFeignClientUrlTests.java │ │ ├── SpringDecoderIntegrationTests.java │ │ ├── SpringDecoderTests.java │ │ ├── UrlTestClient.java │ │ ├── aot │ │ ├── FeignAotTests.java │ │ └── FeignClientBeanFactoryInitializationAotProcessorTests.java │ │ ├── beans │ │ ├── BeansFeignClientTests.java │ │ ├── FeignClientMockBeanTests.java │ │ ├── TestClient.java │ │ └── extra │ │ │ └── TestClient.java │ │ ├── circuitbreaker │ │ ├── AsyncCircuitBreaker.java │ │ ├── AsyncCircuitBreakerTests.java │ │ ├── CircuitBreakerAutoConfigurationTests.java │ │ ├── CircuitBreakerTests.java │ │ ├── CircuitBreakerWithNoFallbackTests.java │ │ ├── FallbackSupportFactoryBeanTests.java │ │ ├── Hello.java │ │ └── MyCircuitBreaker.java │ │ ├── encoding │ │ ├── FeignAcceptEncodingTests.java │ │ ├── FeignContentEncodingTests.java │ │ ├── FeignContentGzipEncodingInterceptorTests.java │ │ ├── FeignPageableEncodingTests.java │ │ ├── Invoices.java │ │ ├── app │ │ │ ├── client │ │ │ │ └── InvoiceClient.java │ │ │ ├── domain │ │ │ │ └── Invoice.java │ │ │ └── resource │ │ │ │ └── InvoiceResource.java │ │ └── proto │ │ │ ├── ProtobufNotInClasspathTest.java │ │ │ ├── ProtobufSpringEncoderTests.java │ │ │ ├── ProtobufTest.java │ │ │ ├── Request.java │ │ │ └── RequestOrBuilder.java │ │ ├── feignclientsregistrar │ │ ├── TopLevelClient.java │ │ └── sub │ │ │ └── SubLevelClient.java │ │ ├── hateoas │ │ ├── FeignHalAutoConfigurationContextTests.java │ │ ├── FeignHalTests.java │ │ └── app │ │ │ ├── FeignHalApplication.java │ │ │ ├── FeignHalClient.java │ │ │ ├── FeignHalConfiguration.java │ │ │ ├── FeignHalController.java │ │ │ └── MarsRover.java │ │ ├── invalid │ │ └── FeignClientValidationTests.java │ │ ├── loadbalancer │ │ ├── FeignBlockingLoadBalancerClientTests.java │ │ ├── FeignLoadBalancerAutoConfigurationTests.java │ │ ├── RetryableFeignBlockingLoadBalancerClientTests.java │ │ └── XForwardedHeadersTransformerTests.java │ │ ├── protocol │ │ └── FeignOkHttpProtocolsTests.java │ │ ├── security │ │ └── OAuth2AccessTokenInterceptorTests.java │ │ ├── support │ │ ├── AbstractSpringMvcContractIntegrationTests.java │ │ ├── FeignHttpClientPropertiesTests.java │ │ ├── FormWriterTests.java │ │ ├── PageJacksonModuleTests.java │ │ ├── PageableEncoderTests.java │ │ ├── PageableEncoderWithSpringDataWebTests.java │ │ ├── PageableSpringQueryMapEncoderTests.java │ │ ├── PageableSpringQueryMapEncoderWithSpringDataWebTests.java │ │ ├── PageableSupportTest.java │ │ ├── SortJacksonModuleTests.java │ │ ├── SpringEncoderTests.java │ │ ├── SpringMvcContractIntegrationTests.java │ │ ├── SpringMvcContractSlashEncodingIntegrationTests.java │ │ └── SpringMvcContractTests.java │ │ ├── test │ │ ├── ApacheHttpClient5ConfigurationTests.java │ │ ├── EqualsAndHashCodeAssert.java │ │ ├── Http2ClientConfigurationTests.java │ │ ├── NoSecurityConfiguration.java │ │ └── OkHttpClientConfigurationTests.java │ │ ├── testclients │ │ └── TestClient.java │ │ └── valid │ │ ├── FeignClientNotPrimaryTests.java │ │ ├── FeignClientValidationTests.java │ │ ├── FeignHttp2ClientTests.java │ │ ├── FeignHttpClientTests.java │ │ ├── FeignOkHttpTests.java │ │ ├── IterableParameterTests.java │ │ ├── ValidFeignClientTests.java │ │ └── scanning │ │ ├── FeignClientEnvVarTests.java │ │ └── FeignClientScanningTests.java │ └── resources │ ├── application-defaultstest.yml │ ├── application.yml │ ├── dummy.pdf │ ├── feign-properties.properties │ ├── feign-refreshable-properties.properties │ ├── logback-test.xml │ ├── proto │ └── request.proto │ ├── withPage.json │ ├── withPageable.json │ └── withoutPageable.json ├── spring-cloud-openfeign-dependencies └── pom.xml ├── spring-cloud-starter-openfeign └── pom.xml └── src └── checkstyle └── checkstyle-suppressions.xml /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = tab 8 | indent_size = 4 9 | end_of_line = lf 10 | insert_final_newline = true 11 | 12 | [*.yml] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributing 3 | 4 | Spring Cloud is released under the non-restrictive Apache 2.0 license, 5 | and follows a very standard Github development process, using Github 6 | tracker for issues and merging pull requests into main. If you want 7 | to contribute even something trivial please do not hesitate, but 8 | follow the guidelines below. 9 | 10 | ## Sign the Contributor License Agreement 11 | Before we accept a non-trivial patch or pull request we will need you to sign the 12 | [Contributor License Agreement](https://cla.pivotal.io/sign/spring). 13 | Signing the contributor's agreement does not grant anyone commit rights to the main 14 | repository, but it does mean that we can accept your contributions, and you will get an 15 | author credit if we do. Active contributors might be asked to join the core team, and 16 | given the ability to merge pull requests. 17 | 18 | ## Code of Conduct 19 | This project adheres to the Contributor Covenant [code of 20 | conduct](https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/modules/ROOT/partials/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report 21 | unacceptable behavior to spring-code-of-conduct@pivotal.io. 22 | 23 | ## Code Conventions and Housekeeping 24 | None of these is essential for a pull request, but they will all help. They can also be 25 | added after the original pull request but before a merge. 26 | 27 | * Use the Spring Framework code format conventions. If you use Eclipse 28 | you can import formatter settings using the 29 | `eclipse-code-formatter.xml` file from the 30 | [Spring Cloud Build](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/spring-cloud-dependencies-parent/eclipse-code-formatter.xml) project. If using IntelliJ, you can use the 31 | [Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546) to import the same file. 32 | * Make sure all new `.java` files to have a simple Javadoc class comment with at least an 33 | `@author` tag identifying you, and preferably at least a paragraph on what the class is 34 | for. 35 | * Add the ASF license header comment to all new `.java` files (copy from existing files 36 | in the project) 37 | * Add yourself as an `@author` to the .java files that you modify substantially (more 38 | than cosmetic changes). 39 | * Add some Javadocs and, if you change the namespace, some XSD doc elements. 40 | * A few unit tests would help a lot as well -- someone has to do it. 41 | * If no-one else is using your branch, please rebase it against the current main (or 42 | other target branch in the main project). 43 | * When writing a commit message please follow [these conventions](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), 44 | if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit 45 | message (where XXXX is the issue number). 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | Please provide details of the problem, including the version of Spring Cloud that you 12 | are using. 13 | 14 | **Sample** 15 | If possible, please provide a test case or sample application that reproduces 16 | the problem. This makes it much easier for us to diagnose the problem and to verify that 17 | we have fixed it. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dco.yml: -------------------------------------------------------------------------------- 1 | require: 2 | members: false -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | target-branch: "4.1.x" # oldest OSS supported branch 6 | schedule: 7 | interval: "weekly" 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | target-branch: "4.2.x" 11 | schedule: 12 | interval: "weekly" 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | target-branch: "main" 16 | schedule: 17 | interval: "weekly" 18 | - package-ecosystem: maven 19 | directory: / 20 | schedule: 21 | interval: daily 22 | target-branch: 4.1.x 23 | ignore: 24 | # only upgrade patch versions for maintenance branch 25 | - dependency-name: "*" 26 | update-types: 27 | - version-update:semver-major 28 | - version-update:semver-minor 29 | - package-ecosystem: maven 30 | directory: / 31 | schedule: 32 | interval: daily 33 | target-branch: 4.2.x 34 | ignore: 35 | # only upgrade patch versions for maintenance branch 36 | - dependency-name: "*" 37 | update-types: 38 | - version-update:semver-major 39 | - version-update:semver-minor 40 | - package-ecosystem: maven 41 | directory: / 42 | schedule: 43 | interval: daily 44 | target-branch: main 45 | ignore: 46 | # only upgrade by minor or patch 47 | - dependency-name: "*" 48 | update-types: 49 | - version-update:semver-major 50 | - package-ecosystem: npm 51 | target-branch: docs-build 52 | directory: / 53 | schedule: 54 | interval: weekly 55 | - package-ecosystem: npm 56 | target-branch: main 57 | directory: /docs 58 | schedule: 59 | interval: weekly 60 | - package-ecosystem: npm 61 | target-branch: 4.1.x 62 | directory: /docs 63 | schedule: 64 | interval: weekly 65 | - package-ecosystem: npm 66 | target-branch: 4.2.x 67 | directory: /docs 68 | schedule: 69 | interval: weekly 70 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docs 2 | on: 3 | push: 4 | branches-ignore: [ gh-pages ] 5 | tags: '**' 6 | repository_dispatch: 7 | types: request-build-reference # legacy 8 | #schedule: 9 | #- cron: '0 10 * * *' # Once per day at 10am UTC 10 | workflow_dispatch: 11 | permissions: 12 | actions: write 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | # if: github.repository_owner == 'spring-cloud' 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | ref: docs-build 22 | fetch-depth: 1 23 | - name: Dispatch (partial build) 24 | if: github.ref_type == 'branch' 25 | env: 26 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }} 28 | - name: Dispatch (full build) 29 | if: github.ref_type == 'tag' 30 | env: 31 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) 33 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Build 5 | 6 | on: 7 | push: 8 | branches: [ main, 4.1.x, 4.2.x ] 9 | pull_request: 10 | branches: [ main, 4.1.x, 4.2.x ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | java: ["17"] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up JDK ${{ matrix.java }} 24 | uses: actions/setup-java@v4 25 | with: 26 | distribution: 'temurin' 27 | java-version: ${{ matrix.java }} 28 | cache: 'maven' 29 | - name: Build with Maven 30 | run: ./mvnw clean install -B -U -P sonar 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /application.yml 2 | /application.properties 3 | asciidoctor.css 4 | *~ 5 | #* 6 | *# 7 | .#* 8 | .classpath 9 | .project 10 | .settings/ 11 | .settings 12 | .springBeans 13 | target/ 14 | bin/ 15 | _site/ 16 | .idea 17 | *.iml 18 | *.ipr 19 | *.iws 20 | .factorypath 21 | *.log 22 | .shelf 23 | *.swp 24 | *.swo 25 | /spring-cloud-release-tools*.jar 26 | antrun 27 | .vscode/ 28 | .flattened-pom.xml 29 | node 30 | node_modules 31 | build 32 | _configprops.adoc 33 | _spans.adoc 34 | _metrics.adoc 35 | _conventions.adoc 36 | /package.json 37 | package-lock.json 38 | -------------------------------------------------------------------------------- /.java-version: -------------------------------------------------------------------------------- 1 | 17 2 | -------------------------------------------------------------------------------- /.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | -Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -DaltSnapshotDeploymentRepository=repo.spring.io::default::https://repo.spring.io/libs-snapshot-local 2 | -P spring 3 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/94b07a531e3f6fec05f066878955f1e99f0a2ba3/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | # Enable auto-env through the sdkman_auto_env config 2 | # Add key=value pairs of SDKs to use below 3 | java=17.0.1-tem 4 | -------------------------------------------------------------------------------- /.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | repo.spring.io 6 | ${env.CI_DEPLOY_USERNAME} 7 | ${env.CI_DEPLOY_PASSWORD} 8 | 9 | 10 | 11 | 12 | 18 | spring 19 | 20 | true 21 | 22 | 23 | 24 | spring-snapshots 25 | Spring Snapshots 26 | https://repo.spring.io/libs-snapshot-local 27 | 28 | true 29 | 30 | 31 | 32 | spring-milestones 33 | Spring Milestones 34 | https://repo.spring.io/libs-milestone-local 35 | 36 | false 37 | 38 | 39 | 40 | spring-releases 41 | Spring Releases 42 | https://repo.spring.io/release 43 | 44 | false 45 | 46 | 47 | 48 | 49 | 50 | spring-snapshots 51 | Spring Snapshots 52 | https://repo.spring.io/libs-snapshot-local 53 | 54 | true 55 | 56 | 57 | 58 | spring-milestones 59 | Spring Milestones 60 | https://repo.spring.io/libs-milestone-local 61 | 62 | false 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /.springformat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/94b07a531e3f6fec05f066878955f1e99f0a2ba3/.springformat -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | require 'asciidoctor' 2 | require 'erb' 3 | 4 | options = {:mkdirs => true, :safe => :unsafe, :attributes => ['linkcss', 'allow-uri-read']} 5 | 6 | guard 'shell' do 7 | watch(/^docs\/[A-Z-a-z][^#]*\.adoc$/) {|m| 8 | Asciidoctor.load_file('docs/src/main/asciidoc/README.adoc', :to_file => './README.adoc', safe: :safe, parse: false, attributes: 'allow-uri-read') 9 | Asciidoctor.render_file('docs/src/main/asciidoc/spring-cloud-netflix.adoc', options.merge(:to_dir => 'target/generated-docs')) 10 | } 11 | end 12 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "reach, diff, flags, files" 3 | behavior: default 4 | require_changes: false # if true: only post the comment if coverage changes 5 | require_base: no # [yes :: must have a base report to post] 6 | require_head: yes # [yes :: must have a head report to post] 7 | branches: null 8 | -------------------------------------------------------------------------------- /docs/antora-playbook.yml: -------------------------------------------------------------------------------- 1 | antora: 2 | extensions: 3 | - require: '@springio/antora-extensions' 4 | root_component_name: 'cloud-openfeign' 5 | site: 6 | title: Spring Cloud Openfeign 7 | url: https://docs.spring.io/spring-cloud-openfeign/reference/ 8 | content: 9 | sources: 10 | - url: ./.. 11 | branches: HEAD 12 | start_path: docs 13 | worktrees: true 14 | asciidoc: 15 | attributes: 16 | page-stackoverflow-url: https://stackoverflow.com/tags/spring-cloud 17 | page-pagination: '' 18 | hide-uri-scheme: '@' 19 | tabs-sync-option: '@' 20 | chomp: 'all' 21 | extensions: 22 | - '@asciidoctor/tabs' 23 | - '@springio/asciidoctor-extensions' 24 | sourcemap: true 25 | urls: 26 | latest_version_segment: '' 27 | runtime: 28 | log: 29 | failure_level: warn 30 | format: pretty 31 | ui: 32 | bundle: 33 | url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.15/ui-bundle.zip 34 | -------------------------------------------------------------------------------- /docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: cloud-openfeign 2 | version: true 3 | title: Spring Cloud OpenFeign 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | ext: 7 | collector: 8 | run: 9 | command: ./mvnw --no-transfer-progress -B process-resources -Pdocs -pl docs -Dantora-maven-plugin.phase=none -Dgenerate-docs.phase=none -Dgenerate-readme.phase=none -Dgenerate-cloud-resources.phase=none -Dmaven-dependency-plugin-for-docs.phase=none -Dmaven-dependency-plugin-for-docs-classes.phase=none -DskipTests -DdisableConfigurationProperties 10 | local: true 11 | scan: 12 | dir: ./target/classes/antora-resources/ 13 | -------------------------------------------------------------------------------- /docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Introduction] 2 | * xref:spring-cloud-openfeign.adoc[] 3 | * xref:appendix.adoc[] 4 | ** xref:configprops.adoc[] 5 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/_attributes.adoc: -------------------------------------------------------------------------------- 1 | :doctype: book 2 | :idprefix: 3 | :idseparator: - 4 | :tabsize: 4 5 | :numbered: 6 | :sectanchors: 7 | :sectnums: 8 | :icons: font 9 | :hide-uri-scheme: 10 | :docinfo: shared,private 11 | 12 | :sc-ext: java 13 | :project-full-name: Spring Cloud OpenFeign 14 | :all: {asterisk}{asterisk} 15 | 16 | :core_path: {project-root}/spring-cloud-openfeign-core 17 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/appendix.adoc: -------------------------------------------------------------------------------- 1 | :numbered!: 2 | [appendix] 3 | [[common-application-properties]] 4 | = Common application properties 5 | :page-section-summary-toc: 1 6 | 7 | 8 | Various properties can be specified inside your `application.properties` file, inside your `application.yml` file, or as command line switches. 9 | This appendix provides a list of common Spring Cloud OpenFeign properties and references to the underlying classes that consume them. 10 | 11 | NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list. 12 | Also, you can define your own properties. 13 | 14 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/configprops.adoc: -------------------------------------------------------------------------------- 1 | [[configuration-properties]] 2 | = Configuration Properties 3 | 4 | Below you can find a list of configuration properties. 5 | 6 | include::partial$_configprops.adoc[] 7 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | include::intro.adoc[] 2 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/intro.adoc: -------------------------------------------------------------------------------- 1 | [[introduction]] 2 | = Spring Cloud OpenFeign 3 | 4 | This project provides OpenFeign integrations for Spring Boot apps through autoconfiguration 5 | and binding to the Spring Environment and other Spring programming model idioms. 6 | 7 | WARNING: As announced in https://spring.io/blog/2022/12/16/spring-cloud-2022-0-0-codename-kilburn-has-been-released#spring-cloud-openfeign-feature-complete-announcement[Spring Cloud 2022.0.0 release blog entry], we're now treating the Spring Cloud OpenFeign project as feature-complete. We are only going to be adding bugfixes and possibly merging some small community feature PRs. We suggest migrating over to https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-http-interface[Spring Interface Clients] instead. 8 | 9 | -------------------------------------------------------------------------------- /docs/modules/ROOT/partials/_attributes.adoc: -------------------------------------------------------------------------------- 1 | :sc-ext: java 2 | :project-full-name: Spring Cloud OpenFeign 3 | :all: {asterisk}{asterisk} 4 | -------------------------------------------------------------------------------- /docs/modules/ROOT/partials/_conventions.adoc: -------------------------------------------------------------------------------- 1 | [[observability-conventions]] 2 | === Observability - Conventions 3 | 4 | Below you can find a list of all `GlobalObservationConvention` and `ObservationConvention` declared by this project. 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/modules/ROOT/partials/_metrics.adoc: -------------------------------------------------------------------------------- 1 | [[observability-metrics]] 2 | === Observability - Metrics 3 | 4 | Below you can find a list of all metrics declared by this project. 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/modules/ROOT/partials/_spans.adoc: -------------------------------------------------------------------------------- 1 | [[observability-spans]] 2 | === Observability - Spans 3 | 4 | Below you can find a list of all spans declared by this project. 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "antora": "3.2.0-alpha.8", 4 | "@antora/atlas-extension": "1.0.0-alpha.2", 5 | "@antora/collector-extension": "1.0.1", 6 | "@asciidoctor/tabs": "1.0.0-beta.6", 7 | "@springio/antora-extensions": "1.14.4", 8 | "@springio/asciidoctor-extensions": "1.0.0-alpha.17" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/main/antora/resources/antora-resources/antora.yml: -------------------------------------------------------------------------------- 1 | version: @antora-component.version@ 2 | prerelease: @antora-component.prerelease@ 3 | 4 | asciidoc: 5 | attributes: 6 | attribute-missing: 'warn' 7 | chomp: 'all' 8 | project-root: @maven.multiModuleProjectDirectory@ 9 | github-repo: @docs.main@ 10 | github-raw: https://raw.githubusercontent.com/spring-cloud/@docs.main@/@github-tag@ 11 | github-code: https://github.com/spring-cloud/@docs.main@/tree/@github-tag@ 12 | github-issues: https://github.com/spring-cloud/@docs.main@/issues/ 13 | github-wiki: https://github.com/spring-cloud/@docs.main@/wiki 14 | spring-cloud-version: @project.version@ 15 | github-tag: @github-tag@ 16 | version-type: @version-type@ 17 | docs-url: https://docs.spring.io/@docs.main@/docs/@project.version@ 18 | raw-docs-url: https://raw.githubusercontent.com/spring-cloud/@docs.main@/@github-tag@ 19 | project-version: @project.version@ 20 | project-name: @docs.main@ 21 | -------------------------------------------------------------------------------- /docs/src/main/asciidoc/README.adoc: -------------------------------------------------------------------------------- 1 | image::https://github.com/spring-cloud/spring-cloud-openfeign/actions/workflows/maven.yml/badge.svg?branch=main&style=svg[https://github.com/spring-cloud/spring-cloud-openfeign/actions/workflows/maven.yml/badge.svg?branch=main&style=svg[https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=main&style=svg]["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"] 2 | 3 | WARNING: As announced in https://spring.io/blog/2022/12/16/spring-cloud-2022-0-0-codename-kilburn-has-been-released#spring-cloud-openfeign-feature-complete-announcement[Spring Cloud 2022.0.0 release blog entry], we're now treating the Spring Cloud OpenFeign project as feature-complete. We are only going to be adding bugfixes and possibly merging some small community feature PRs. We suggest migrating over to https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-http-interface[Spring Interface Clients] instead. 4 | 5 | 6 | [[features]] 7 | == Features 8 | 9 | * Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations 10 | 11 | [[building]] 12 | == Building 13 | 14 | include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/building.adoc[] 15 | 16 | [[contributing]] 17 | == Contributing 18 | 19 | include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/contributing-docs.adoc[] 20 | 21 | [[license]] 22 | == License 23 | 24 | The project license file is available https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/main/LICENSE.txt[here]. 25 | -------------------------------------------------------------------------------- /docs/src/main/asciidoc/sagan-boot.adoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/94b07a531e3f6fec05f066878955f1e99f0a2ba3/docs/src/main/asciidoc/sagan-boot.adoc -------------------------------------------------------------------------------- /docs/src/main/asciidoc/sagan-index.adoc: -------------------------------------------------------------------------------- 1 | This project provides https://github.com/OpenFeign/feign[OpenFeign] integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. 2 | 3 | ## Features 4 | 5 | * Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations 6 | 7 | ## Getting Started 8 | 9 | 10 | ```java 11 | @SpringBootApplication 12 | @EnableFeignClients 13 | public class WebApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(WebApplication.class, args); 17 | } 18 | 19 | @FeignClient("name") 20 | static interface NameService { 21 | @RequestMapping("/") 22 | public String getName(); 23 | } 24 | } 25 | 26 | ``` 27 | 28 | ## Contributing 29 | 30 | We welcome contributions. You can read more on how to contribute to the project https://github.com/spring-cloud/spring-cloud-openfeign/blob/main/README.adoc#3-contributing[here]. 31 | 32 | ## Community Support 33 | 34 | * You can report issues through https://github.com/spring-cloud/spring-cloud-openfeign/issues[Github]. 35 | * We monitor https://stackoverflow.com/[StackOverflow] for questions with the `spring-cloud-feign` tag. 36 | * You can contact our team at https://gitter.im/spring-cloud/spring-cloud[Gitter]. 37 | 38 | ## Commercial Support 39 | 40 | Commercial Support is provided as part of the https://spring.io/support[VMware Spring Runtime] offering. 41 | 42 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/AnnotatedParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Collection; 22 | 23 | import feign.MethodMetadata; 24 | 25 | /** 26 | * Feign contract method parameter processor. 27 | * 28 | * @author Jakub Narloch 29 | * @author Abhijit Sarkar 30 | */ 31 | public interface AnnotatedParameterProcessor { 32 | 33 | /** 34 | * Retrieves the processor supported annotation type. 35 | * @return the annotation type 36 | */ 37 | Class getAnnotationType(); 38 | 39 | /** 40 | * Process the annotated parameter. 41 | * @param context the parameter context 42 | * @param annotation the annotation instance 43 | * @param method the method that contains the annotation 44 | * @return whether the parameter is http 45 | */ 46 | boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method); 47 | 48 | /** 49 | * Specifies the parameter context. 50 | * 51 | * @author Jakub Narloch 52 | */ 53 | interface AnnotatedParameterContext { 54 | 55 | /** 56 | * Retrieves the method metadata. 57 | * @return the method metadata 58 | */ 59 | MethodMetadata getMethodMetadata(); 60 | 61 | /** 62 | * Retrieves the index of the parameter. 63 | * @return the parameter index 64 | */ 65 | int getParameterIndex(); 66 | 67 | /** 68 | * Sets the parameter name. 69 | * @param name the name of the parameter 70 | */ 71 | void setParameterName(String name); 72 | 73 | /** 74 | * Sets the template parameter. 75 | * @param name the template parameter 76 | * @param rest the existing parameter values 77 | * @return parameters 78 | */ 79 | Collection setTemplateParameter(String name, Collection rest); 80 | 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/CachingCapability.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Capability; 20 | import feign.InvocationHandlerFactory; 21 | 22 | import org.springframework.cache.interceptor.CacheInterceptor; 23 | 24 | /** 25 | * Allows Spring's @Cache* annotations to be declared on the feign client's methods. 26 | * 27 | * @author Sam Kruglov 28 | */ 29 | public class CachingCapability implements Capability { 30 | 31 | private final CacheInterceptor cacheInterceptor; 32 | 33 | public CachingCapability(CacheInterceptor cacheInterceptor) { 34 | this.cacheInterceptor = cacheInterceptor; 35 | } 36 | 37 | @Override 38 | public InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) { 39 | return new FeignCachingInvocationHandlerFactory(invocationHandlerFactory, cacheInterceptor); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/CircuitBreakerNameResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.lang.reflect.Method; 20 | 21 | import feign.Target; 22 | 23 | /** 24 | * Used to resolve a circuitbreaker name which will be used in 25 | * {@link org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory}. 26 | * 27 | * @author Kwangyong Kim 28 | * @since 2020.0.4 29 | */ 30 | public interface CircuitBreakerNameResolver { 31 | 32 | String resolveCircuitBreakerName(String feignClientName, Target target, Method method); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/CollectionFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.lang.annotation.ElementType; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.RetentionPolicy; 22 | import java.lang.annotation.Target; 23 | 24 | /** 25 | * Indicates which collection format should be used while processing the annotated method. 26 | * 27 | * @author Olga Maciaszek-Sharma 28 | * @author Sam Kruglov 29 | * @see feign.CollectionFormat 30 | */ 31 | @Target({ ElementType.METHOD, ElementType.TYPE }) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface CollectionFormat { 34 | 35 | /** 36 | * Allows setting the {@link feign.CollectionFormat} to be used while processing the 37 | * annotated method. 38 | * @return the {@link feign.CollectionFormat} to be used 39 | */ 40 | feign.CollectionFormat value(); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/DefaultFeignLoggerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Logger; 20 | import feign.slf4j.Slf4jLogger; 21 | 22 | /** 23 | * @author Venil Noronha 24 | * @author Olga Maciaszek-Sharma 25 | */ 26 | public class DefaultFeignLoggerFactory implements FeignLoggerFactory { 27 | 28 | private final Logger logger; 29 | 30 | public DefaultFeignLoggerFactory(Logger logger) { 31 | this.logger = logger; 32 | } 33 | 34 | @Override 35 | public Logger create(Class type) { 36 | return this.logger != null ? this.logger : new Slf4jLogger(type); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/DefaultTargeter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Feign; 20 | import feign.Target; 21 | 22 | /** 23 | * @author Spencer Gibb 24 | */ 25 | class DefaultTargeter implements Targeter { 26 | 27 | @Override 28 | public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context, 29 | Target.HardCodedTarget target) { 30 | return feign.target(target); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FallbackFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | 22 | import static feign.Util.checkNotNull; 23 | 24 | /** 25 | * Used to control the fallback given its cause. 26 | * 27 | * Ex. 28 | * 29 | *
30 |  * {@code
31 |  * // This instance will be invoked if there are errors of any kind.
32 |  * FallbackFactory fallbackFactory = cause -> (owner, repo) -> {
33 |  *   if (cause instanceof FeignException && ((FeignException) cause).status() == 403) {
34 |  *     return Collections.emptyList();
35 |  *   } else {
36 |  *     return Arrays.asList("yogi");
37 |  *   }
38 |  * };
39 |  *
40 |  * GitHub github = FeignCircuitBreaker.builder()
41 |  *                             ...
42 |  *                             .target(GitHub.class, "https://api.github.com", fallbackFactory);
43 |  * }
44 |  * 
45 | * 46 | * @param the feign interface type 47 | */ 48 | public interface FallbackFactory { 49 | 50 | /** 51 | * Returns an instance of the fallback appropriate for the given cause. 52 | * @param cause cause of an exception. 53 | * @return fallback 54 | */ 55 | T create(Throwable cause); 56 | 57 | final class Default implements FallbackFactory { 58 | 59 | final Log logger; 60 | 61 | final T constant; 62 | 63 | public Default(T constant) { 64 | this(constant, LogFactory.getLog(Default.class)); 65 | } 66 | 67 | Default(T constant, Log logger) { 68 | this.constant = checkNotNull(constant, "fallback"); 69 | this.logger = checkNotNull(logger, "logger"); 70 | } 71 | 72 | @Override 73 | public T create(Throwable cause) { 74 | if (logger.isTraceEnabled()) { 75 | logger.trace("fallback due to: " + cause.getMessage(), cause); 76 | } 77 | return constant; 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | return constant.toString(); 83 | } 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignBuilderCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Feign; 20 | 21 | /** 22 | * Allows application to customize the Feign builder. 23 | * 24 | * @author Matt King 25 | */ 26 | @FunctionalInterface 27 | public interface FeignBuilderCustomizer { 28 | 29 | void customize(Feign.Builder builder); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignCachingInvocationHandlerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.lang.reflect.AccessibleObject; 20 | import java.lang.reflect.InvocationHandler; 21 | import java.lang.reflect.Method; 22 | import java.util.Map; 23 | import java.util.Optional; 24 | 25 | import feign.InvocationHandlerFactory; 26 | import feign.Target; 27 | import org.aopalliance.intercept.MethodInvocation; 28 | 29 | import org.springframework.cache.interceptor.CacheInterceptor; 30 | 31 | /** 32 | * Allows Spring's @Cache* annotations to be declared on the feign client's methods. 33 | * 34 | * @author Sam Kruglov 35 | */ 36 | public class FeignCachingInvocationHandlerFactory implements InvocationHandlerFactory { 37 | 38 | private final InvocationHandlerFactory delegateFactory; 39 | 40 | private final CacheInterceptor cacheInterceptor; 41 | 42 | public FeignCachingInvocationHandlerFactory(InvocationHandlerFactory delegateFactory, 43 | CacheInterceptor cacheInterceptor) { 44 | this.delegateFactory = delegateFactory; 45 | this.cacheInterceptor = cacheInterceptor; 46 | } 47 | 48 | @Override 49 | public InvocationHandler create(Target target, Map dispatch) { 50 | final InvocationHandler delegateHandler = delegateFactory.create(target, dispatch); 51 | return (proxy, method, argsNullable) -> { 52 | Object[] args = Optional.ofNullable(argsNullable).orElseGet(() -> new Object[0]); 53 | return cacheInterceptor.invoke(new MethodInvocation() { 54 | @Override 55 | public Method getMethod() { 56 | return method; 57 | } 58 | 59 | @Override 60 | public Object[] getArguments() { 61 | return args; 62 | } 63 | 64 | @Override 65 | public Object proceed() throws Throwable { 66 | return delegateHandler.invoke(proxy, method, args); 67 | } 68 | 69 | @Override 70 | public Object getThis() { 71 | return target; 72 | } 73 | 74 | @Override 75 | public AccessibleObject getStaticPart() { 76 | return method; 77 | } 78 | }); 79 | }; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignCircuitBreakerDisabledConditions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 22 | 23 | class FeignCircuitBreakerDisabledConditions extends AnyNestedCondition { 24 | 25 | FeignCircuitBreakerDisabledConditions() { 26 | super(ConfigurationPhase.PARSE_CONFIGURATION); 27 | } 28 | 29 | @ConditionalOnMissingClass("org.springframework.cloud.client.circuitbreaker.CircuitBreaker") 30 | static class CircuitBreakerClassMissing { 31 | 32 | } 33 | 34 | @ConditionalOnProperty(value = "spring.cloud.openfeign.circuitbreaker.enabled", havingValue = "false", 35 | matchIfMissing = true) 36 | static class CircuitBreakerDisabled { 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | import org.springframework.beans.BeansException; 23 | import org.springframework.beans.factory.BeanFactoryUtils; 24 | import org.springframework.cloud.context.named.NamedContextFactory; 25 | import org.springframework.context.ApplicationContextInitializer; 26 | import org.springframework.context.support.GenericApplicationContext; 27 | import org.springframework.lang.Nullable; 28 | 29 | /** 30 | * A factory that creates instances of feign classes. It creates a Spring 31 | * ApplicationContext per client name, and extracts the beans that it needs from there. 32 | * 33 | * @author Spencer Gibb 34 | * @author Dave Syer 35 | * @author Matt King 36 | * @author Jasbir Singh 37 | * @author Olga Maciaszek-Sharma 38 | */ 39 | public class FeignClientFactory extends NamedContextFactory { 40 | 41 | public FeignClientFactory() { 42 | this(new HashMap<>()); 43 | } 44 | 45 | public FeignClientFactory( 46 | Map> applicationContextInitializers) { 47 | super(FeignClientsConfiguration.class, "spring.cloud.openfeign", "spring.cloud.openfeign.client.name", 48 | applicationContextInitializers); 49 | } 50 | 51 | @Nullable 52 | public T getInstanceWithoutAncestors(String name, Class type) { 53 | try { 54 | return BeanFactoryUtils.beanOfType(getContext(name), type); 55 | } 56 | catch (BeansException ex) { 57 | return null; 58 | } 59 | } 60 | 61 | @Nullable 62 | public Map getInstancesWithoutAncestors(String name, Class type) { 63 | return getContext(name).getBeansOfType(type); 64 | } 65 | 66 | public T getInstance(String contextName, String beanName, Class type) { 67 | return getContext(contextName).getBean(beanName, type); 68 | } 69 | 70 | @SuppressWarnings("unchecked") 71 | public FeignClientFactory withApplicationContextInitializers(Map applicationContextInitializers) { 72 | Map> convertedInitializers = new HashMap<>(); 73 | applicationContextInitializers.keySet() 74 | .forEach(contextId -> convertedInitializers.put(contextId, 75 | (ApplicationContextInitializer) applicationContextInitializers 76 | .get(contextId))); 77 | return new FeignClientFactory(convertedInitializers); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientMicrometerEnabledCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.util.Map; 20 | 21 | import org.springframework.context.annotation.Condition; 22 | import org.springframework.context.annotation.ConditionContext; 23 | import org.springframework.core.type.AnnotatedTypeMetadata; 24 | 25 | /** 26 | * @author Jonatan Ivanov 27 | */ 28 | class FeignClientMicrometerEnabledCondition implements Condition { 29 | 30 | @Override 31 | public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 32 | FeignClientProperties feignClientProperties = context.getBeanFactory() 33 | .getBeanProvider(FeignClientProperties.class) 34 | .getIfAvailable(); 35 | if (feignClientProperties != null) { 36 | Map feignClientConfigMap = feignClientProperties 37 | .getConfig(); 38 | if (feignClientConfigMap != null) { 39 | FeignClientProperties.FeignClientConfiguration feignClientConfig = feignClientConfigMap 40 | .get(context.getEnvironment().getProperty("spring.cloud.openfeign.client.name")); 41 | if (feignClientConfig != null) { 42 | FeignClientProperties.MicrometerProperties micrometer = feignClientConfig.getMicrometer(); 43 | if (micrometer != null && micrometer.getEnabled() != null) { 44 | return micrometer.getEnabled(); 45 | } 46 | } 47 | } 48 | } 49 | 50 | return true; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientSpecification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.util.Arrays; 20 | import java.util.Objects; 21 | 22 | import org.springframework.cloud.context.named.NamedContextFactory; 23 | 24 | /** 25 | * @author Dave Syer 26 | * @author Gregor Zurowski 27 | * @author Olga Maciaszek-Sharma 28 | */ 29 | public class FeignClientSpecification implements NamedContextFactory.Specification { 30 | 31 | private String name; 32 | 33 | private String className; 34 | 35 | private Class[] configuration; 36 | 37 | public FeignClientSpecification() { 38 | } 39 | 40 | public FeignClientSpecification(String name, String className, Class[] configuration) { 41 | this.name = name; 42 | this.className = className; 43 | this.configuration = configuration; 44 | } 45 | 46 | public String getName() { 47 | return this.name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | public String getClassName() { 55 | return className; 56 | } 57 | 58 | public void setClassName(String className) { 59 | this.className = className; 60 | } 61 | 62 | public Class[] getConfiguration() { 63 | return this.configuration; 64 | } 65 | 66 | public void setConfiguration(Class[] configuration) { 67 | this.configuration = configuration; 68 | } 69 | 70 | @Override 71 | public boolean equals(Object o) { 72 | if (this == o) { 73 | return true; 74 | } 75 | if (!(o instanceof FeignClientSpecification that)) { 76 | return false; 77 | } 78 | return Objects.equals(name, that.name) && Objects.equals(className, that.className) 79 | && Arrays.equals(configuration, that.configuration); 80 | } 81 | 82 | @Override 83 | public int hashCode() { 84 | int result = Objects.hash(name, className); 85 | result = 31 * result + Arrays.hashCode(configuration); 86 | return result; 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "FeignClientSpecification{" + "name='" + name + "', " + "className='" + className + "', " 92 | + "configuration=" + Arrays.toString(configuration) + "}"; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignErrorDecoderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.codec.ErrorDecoder; 20 | 21 | /** 22 | * Allows an application to use a custom Feign {@link feign.codec.ErrorDecoder}. 23 | * 24 | * @author Michael Cramer 25 | */ 26 | public interface FeignErrorDecoderFactory { 27 | 28 | /** 29 | * Factory method to provide a {@link feign.codec.ErrorDecoder} for a given 30 | * {@link Class}. 31 | * @param type the {@link Class} for which a {@link feign.codec.ErrorDecoder} instance 32 | * is to be created 33 | * @return a {@link feign.codec.ErrorDecoder} instance 34 | */ 35 | ErrorDecoder create(Class type); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignFormatterRegistrar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import org.springframework.format.FormatterRegistrar; 20 | import org.springframework.format.support.FormattingConversionService; 21 | 22 | /** 23 | * Allows an application to customize the Feign {@link FormattingConversionService}. 24 | * 25 | * @author Matt Benson 26 | */ 27 | public interface FeignFormatterRegistrar extends FormatterRegistrar { 28 | 29 | } 30 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignLoggerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Logger; 20 | 21 | /** 22 | * Allows an application to use a custom Feign {@link Logger}. 23 | * 24 | * @author Venil Noronha 25 | */ 26 | public interface FeignLoggerFactory { 27 | 28 | /** 29 | * Factory method to provide a {@link Logger} for a given {@link Class}. 30 | * @param type the {@link Class} for which a {@link Logger} instance is to be created 31 | * @return a {@link Logger} instance 32 | */ 33 | Logger create(Class type); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/PropertyBasedTarget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Target; 20 | 21 | /** 22 | * A {@link HardCodedTarget} implementation that resolves url from properties when the 23 | * initial call is made. Using it allows specifying the url at runtime in an AOT-packaged 24 | * application or a native image by setting the value of the 25 | * `spring.cloud.openfeign.client.config.[clientId].url`. 26 | * 27 | * @author Olga Maciaszek-Sharma 28 | * @author Can Bezmen 29 | * @see FeignClientProperties.FeignClientConfiguration#getUrl() 30 | */ 31 | public class PropertyBasedTarget extends Target.HardCodedTarget { 32 | 33 | private String url; 34 | 35 | private final FeignClientProperties.FeignClientConfiguration config; 36 | 37 | private final String path; 38 | 39 | public PropertyBasedTarget(Class type, String name, FeignClientProperties.FeignClientConfiguration config, 40 | String path) { 41 | super(type, name, config.getUrl()); 42 | this.config = config; 43 | this.path = path; 44 | } 45 | 46 | public PropertyBasedTarget(Class type, String name, FeignClientProperties.FeignClientConfiguration config) { 47 | super(type, name, config.getUrl()); 48 | this.config = config; 49 | path = ""; 50 | } 51 | 52 | @Override 53 | public String url() { 54 | if (url == null) { 55 | url = config.getUrl() + path; 56 | } 57 | return url; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/RefreshableHardCodedTarget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Target; 20 | 21 | /** 22 | * This target provides url wrapped under {@link Target}. 23 | * 24 | * @author Jasbir Singh 25 | * @author Olga Maciaszek-Sharma 26 | * @since 4.0.0 27 | */ 28 | public class RefreshableHardCodedTarget extends Target.HardCodedTarget { 29 | 30 | private final RefreshableUrl refreshableUrl; 31 | 32 | private final String cleanPath; 33 | 34 | @SuppressWarnings("unchecked") 35 | public RefreshableHardCodedTarget(Class type, String name, RefreshableUrl refreshableUrl) { 36 | super(type, name, refreshableUrl.getUrl()); 37 | this.refreshableUrl = refreshableUrl; 38 | cleanPath = ""; 39 | } 40 | 41 | @SuppressWarnings("unchecked") 42 | public RefreshableHardCodedTarget(Class type, String name, RefreshableUrl refreshableUrl, String cleanPath) { 43 | super(type, name, refreshableUrl.getUrl()); 44 | this.refreshableUrl = refreshableUrl; 45 | this.cleanPath = cleanPath; 46 | } 47 | 48 | @Override 49 | public String url() { 50 | return refreshableUrl.getUrl() + cleanPath; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/RefreshableUrl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | /** 20 | * This class wraps url inside an object so that relevant proxy instance can be created 21 | * using {@link RefreshableUrlFactoryBean}. 22 | * 23 | * @author Jasbir Singh 24 | * @since 4.0.0 25 | */ 26 | public class RefreshableUrl { 27 | 28 | private final String url; 29 | 30 | public RefreshableUrl(String url) { 31 | this.url = url; 32 | } 33 | 34 | public String getUrl() { 35 | return url; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/RefreshableUrlFactoryBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.util.Objects; 20 | 21 | import org.springframework.beans.BeansException; 22 | import org.springframework.beans.factory.FactoryBean; 23 | import org.springframework.context.ApplicationContext; 24 | import org.springframework.context.ApplicationContextAware; 25 | import org.springframework.util.StringUtils; 26 | 27 | /** 28 | * This factory bean creates {@link RefreshableUrl} instance as per the applicable 29 | * configurations. 30 | * 31 | * @author Jasbir Singh 32 | * @since 4.0.0 33 | */ 34 | public class RefreshableUrlFactoryBean implements FactoryBean, ApplicationContextAware { 35 | 36 | private ApplicationContext applicationContext; 37 | 38 | private String contextId; 39 | 40 | private RefreshableUrl refreshableUrl; 41 | 42 | @Override 43 | public Class getObjectType() { 44 | return RefreshableUrl.class; 45 | } 46 | 47 | @Override 48 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 49 | this.applicationContext = applicationContext; 50 | } 51 | 52 | @Override 53 | public RefreshableUrl getObject() { 54 | if (refreshableUrl != null) { 55 | return refreshableUrl; 56 | } 57 | 58 | FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class); 59 | if (Objects.isNull(properties.getConfig())) { 60 | return new RefreshableUrl(null); 61 | } 62 | FeignClientProperties.FeignClientConfiguration configuration = properties.getConfig().get(contextId); 63 | if (Objects.isNull(configuration) || !StringUtils.hasText(configuration.getUrl())) { 64 | return new RefreshableUrl(null); 65 | } 66 | 67 | refreshableUrl = new RefreshableUrl(FeignClientsRegistrar.getUrl(configuration.getUrl())); 68 | return refreshableUrl; 69 | } 70 | 71 | public void setContextId(String contextId) { 72 | this.contextId = contextId; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/SpringQueryMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.lang.annotation.ElementType; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.RetentionPolicy; 22 | import java.lang.annotation.Target; 23 | 24 | /** 25 | * Spring MVC equivalent of OpenFeign's {@link feign.QueryMap} parameter annotation. 26 | * 27 | * @author Aram Peres 28 | * @see feign.QueryMap 29 | * @see feign.QueryMapEncoder 30 | * @see org.springframework.cloud.openfeign.FeignClientsConfiguration 31 | * @see org.springframework.cloud.openfeign.annotation.QueryMapParameterProcessor 32 | */ 33 | @Retention(RetentionPolicy.RUNTIME) 34 | @Target({ ElementType.PARAMETER }) 35 | public @interface SpringQueryMap { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/Targeter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Feign; 20 | import feign.Target; 21 | 22 | /** 23 | * @author Spencer Gibb 24 | */ 25 | public interface Targeter { 26 | 27 | T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context, 28 | Target.HardCodedTarget target); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/CookieValueParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Collections; 22 | 23 | import feign.MethodMetadata; 24 | 25 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 26 | import org.springframework.http.HttpHeaders; 27 | import org.springframework.web.bind.annotation.CookieValue; 28 | 29 | import static feign.Util.checkState; 30 | import static feign.Util.emptyToNull; 31 | 32 | /** 33 | * {@link CookieValue} annotation processor. 34 | * 35 | * @author Gong Yi 36 | * @author Olga Maciaszek-Sharma 37 | * 38 | */ 39 | public class CookieValueParameterProcessor implements AnnotatedParameterProcessor { 40 | 41 | private static final Class ANNOTATION = CookieValue.class; 42 | 43 | @Override 44 | public Class getAnnotationType() { 45 | return ANNOTATION; 46 | } 47 | 48 | @Override 49 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 50 | int parameterIndex = context.getParameterIndex(); 51 | MethodMetadata data = context.getMethodMetadata(); 52 | CookieValue cookie = ANNOTATION.cast(annotation); 53 | String name = cookie.value().trim(); 54 | checkState(emptyToNull(name) != null, "Cookie.name() was empty on parameter %s", parameterIndex); 55 | context.setParameterName(name); 56 | String cookieExpression = data.template() 57 | .headers() 58 | .getOrDefault(HttpHeaders.COOKIE, Collections.singletonList("")) 59 | .stream() 60 | .findFirst() 61 | .orElse(""); 62 | if (cookieExpression.length() == 0) { 63 | cookieExpression = String.format("%s={%s}", name, name); 64 | } 65 | else { 66 | cookieExpression += String.format("; %s={%s}", name, name); 67 | } 68 | data.template().removeHeader(HttpHeaders.COOKIE); 69 | data.template().header(HttpHeaders.COOKIE, cookieExpression); 70 | return true; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/MatrixVariableParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Map; 22 | import java.util.stream.Collectors; 23 | 24 | import feign.MethodMetadata; 25 | 26 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 27 | import org.springframework.web.bind.annotation.MatrixVariable; 28 | 29 | import static feign.Util.checkState; 30 | import static feign.Util.emptyToNull; 31 | 32 | /** 33 | * {@link MatrixVariable} annotation processor. 34 | * 35 | * Can expand maps or single objects. Values are assigned from the objects 36 | * {@code toString()} method. 37 | * 38 | * @author Matt King 39 | * @see AnnotatedParameterProcessor 40 | */ 41 | public class MatrixVariableParameterProcessor implements AnnotatedParameterProcessor { 42 | 43 | private static final Class ANNOTATION = MatrixVariable.class; 44 | 45 | @Override 46 | public Class getAnnotationType() { 47 | return ANNOTATION; 48 | } 49 | 50 | @Override 51 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 52 | int parameterIndex = context.getParameterIndex(); 53 | Class parameterType = method.getParameterTypes()[parameterIndex]; 54 | MethodMetadata data = context.getMethodMetadata(); 55 | String name = ANNOTATION.cast(annotation).value(); 56 | 57 | checkState(emptyToNull(name) != null, "MatrixVariable annotation was empty on param %s.", 58 | context.getParameterIndex()); 59 | 60 | context.setParameterName(name); 61 | 62 | if (Map.class.isAssignableFrom(parameterType)) { 63 | data.indexToExpander().put(parameterIndex, this::expandMap); 64 | } 65 | else { 66 | data.indexToExpander().put(parameterIndex, object -> ";" + name + "=" + object.toString()); 67 | } 68 | 69 | return true; 70 | } 71 | 72 | @SuppressWarnings("unchecked") 73 | private String expandMap(Object object) { 74 | Map paramMap = (Map) object; 75 | 76 | return paramMap.keySet() 77 | .stream() 78 | .filter(key -> paramMap.get(key) != null) 79 | .map(key -> ";" + key + "=" + paramMap.get(key).toString()) 80 | .collect(Collectors.joining()); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/PathVariableParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Collection; 22 | import java.util.Map; 23 | 24 | import feign.MethodMetadata; 25 | 26 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 27 | import org.springframework.web.bind.annotation.PathVariable; 28 | 29 | import static feign.Util.checkState; 30 | import static feign.Util.emptyToNull; 31 | 32 | /** 33 | * {@link PathVariable} parameter processor. 34 | * 35 | * @author Jakub Narloch 36 | * @author Abhijit Sarkar 37 | * @author Yanming Zhou 38 | * @see AnnotatedParameterProcessor 39 | */ 40 | public class PathVariableParameterProcessor implements AnnotatedParameterProcessor { 41 | 42 | private static final Class ANNOTATION = PathVariable.class; 43 | 44 | @Override 45 | public Class getAnnotationType() { 46 | return ANNOTATION; 47 | } 48 | 49 | @Override 50 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 51 | String name = ANNOTATION.cast(annotation).value(); 52 | checkState(emptyToNull(name) != null, "PathVariable annotation was empty on param %s.", 53 | context.getParameterIndex()); 54 | context.setParameterName(name); 55 | 56 | MethodMetadata data = context.getMethodMetadata(); 57 | String varName = '{' + name + '}'; 58 | String varNameRegex = ".*\\{" + name + "(:[^}]+)?\\}.*"; 59 | if (!data.template().url().matches(varNameRegex) && !containsMapValues(data.template().queries(), varName) 60 | && !containsMapValues(data.template().headers(), varName)) { 61 | data.formParams().add(name); 62 | } 63 | return true; 64 | } 65 | 66 | private boolean containsMapValues(Map> map, V search) { 67 | Collection> values = map.values(); 68 | if (values == null) { 69 | return false; 70 | } 71 | for (Collection entry : values) { 72 | if (entry.contains(search)) { 73 | return true; 74 | } 75 | } 76 | return false; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/QueryMapParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | 22 | import feign.MethodMetadata; 23 | 24 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 25 | import org.springframework.cloud.openfeign.SpringQueryMap; 26 | 27 | /** 28 | * {@link SpringQueryMap} parameter processor. 29 | * 30 | * @author Aram Peres 31 | * @author Olga Maciaszek-Sharma 32 | * @see AnnotatedParameterProcessor 33 | */ 34 | public class QueryMapParameterProcessor implements AnnotatedParameterProcessor { 35 | 36 | private static final Class ANNOTATION = SpringQueryMap.class; 37 | 38 | @Override 39 | public Class getAnnotationType() { 40 | return ANNOTATION; 41 | } 42 | 43 | @Override 44 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 45 | int paramIndex = context.getParameterIndex(); 46 | MethodMetadata metadata = context.getMethodMetadata(); 47 | if (metadata.queryMapIndex() == null) { 48 | metadata.queryMapIndex(paramIndex); 49 | } 50 | return true; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/RequestHeaderParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Collection; 22 | import java.util.Map; 23 | 24 | import feign.MethodMetadata; 25 | 26 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 27 | import org.springframework.web.bind.annotation.RequestHeader; 28 | 29 | import static feign.Util.checkState; 30 | import static feign.Util.emptyToNull; 31 | 32 | /** 33 | * {@link RequestHeader} parameter processor. 34 | * 35 | * @author Jakub Narloch 36 | * @author Abhijit Sarkar 37 | * @see AnnotatedParameterProcessor 38 | */ 39 | public class RequestHeaderParameterProcessor implements AnnotatedParameterProcessor { 40 | 41 | private static final Class ANNOTATION = RequestHeader.class; 42 | 43 | @Override 44 | public Class getAnnotationType() { 45 | return ANNOTATION; 46 | } 47 | 48 | @Override 49 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 50 | int parameterIndex = context.getParameterIndex(); 51 | Class parameterType = method.getParameterTypes()[parameterIndex]; 52 | MethodMetadata data = context.getMethodMetadata(); 53 | 54 | if (Map.class.isAssignableFrom(parameterType)) { 55 | checkState(data.headerMapIndex() == null, "Header map can only be present once."); 56 | data.headerMapIndex(parameterIndex); 57 | 58 | return true; 59 | } 60 | 61 | String name = ANNOTATION.cast(annotation).value(); 62 | checkState(emptyToNull(name) != null, "RequestHeader.value() was empty on parameter %s", parameterIndex); 63 | context.setParameterName(name); 64 | 65 | Collection header = context.setTemplateParameter(name, data.template().headers().get(name)); 66 | data.template().header(name, header); 67 | return true; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/RequestParamParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Collection; 22 | import java.util.Map; 23 | 24 | import feign.MethodMetadata; 25 | 26 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 27 | import org.springframework.web.bind.annotation.RequestParam; 28 | 29 | import static feign.Util.checkState; 30 | import static feign.Util.emptyToNull; 31 | 32 | /** 33 | * {@link RequestParam} parameter processor. 34 | * 35 | * @author Jakub Narloch 36 | * @author Abhijit Sarkar 37 | * @see AnnotatedParameterProcessor 38 | */ 39 | public class RequestParamParameterProcessor implements AnnotatedParameterProcessor { 40 | 41 | private static final Class ANNOTATION = RequestParam.class; 42 | 43 | @Override 44 | public Class getAnnotationType() { 45 | return ANNOTATION; 46 | } 47 | 48 | @Override 49 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 50 | int parameterIndex = context.getParameterIndex(); 51 | Class parameterType = method.getParameterTypes()[parameterIndex]; 52 | MethodMetadata data = context.getMethodMetadata(); 53 | 54 | if (Map.class.isAssignableFrom(parameterType)) { 55 | checkState(data.queryMapIndex() == null, "Query map can only be present once."); 56 | data.queryMapIndex(parameterIndex); 57 | 58 | return true; 59 | } 60 | 61 | RequestParam requestParam = ANNOTATION.cast(annotation); 62 | String name = requestParam.value(); 63 | checkState(emptyToNull(name) != null, "RequestParam.value() was empty on parameter %s of method %s", 64 | parameterIndex, method.getName()); 65 | context.setParameterName(name); 66 | 67 | Collection query = context.setTemplateParameter(name, data.template().queries().get(name)); 68 | data.template().query(name, query); 69 | return true; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/annotation/RequestPartParameterProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.annotation; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.util.Collection; 22 | 23 | import feign.MethodMetadata; 24 | 25 | import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; 26 | import org.springframework.web.bind.annotation.RequestPart; 27 | 28 | import static feign.Util.checkState; 29 | import static feign.Util.emptyToNull; 30 | 31 | /** 32 | * {@link RequestPart} parameter processor. 33 | * 34 | * @author Aaron Whiteside 35 | * @see AnnotatedParameterProcessor 36 | */ 37 | public class RequestPartParameterProcessor implements AnnotatedParameterProcessor { 38 | 39 | private static final Class ANNOTATION = RequestPart.class; 40 | 41 | @Override 42 | public Class getAnnotationType() { 43 | return ANNOTATION; 44 | } 45 | 46 | @Override 47 | public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { 48 | int parameterIndex = context.getParameterIndex(); 49 | MethodMetadata data = context.getMethodMetadata(); 50 | 51 | String name = ANNOTATION.cast(annotation).value(); 52 | checkState(emptyToNull(name) != null, "RequestPart.value() was empty on parameter %s", parameterIndex); 53 | context.setParameterName(name); 54 | 55 | data.formParams().add(name); 56 | Collection names = context.setTemplateParameter(name, data.indexToName().get(parameterIndex)); 57 | data.indexToName().put(parameterIndex, names); 58 | return true; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/FeignClientConfigurer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.clientconfig; 18 | 19 | /** 20 | * Additional Feign Client configuration that are not included in 21 | * {@link org.springframework.cloud.openfeign.FeignClient}. 22 | * 23 | * @author Matt King 24 | */ 25 | public interface FeignClientConfigurer { 26 | 27 | /** 28 | * @return whether to mark the feign proxy as a primary bean. Defaults to true. 29 | */ 30 | default boolean primary() { 31 | return true; 32 | } 33 | 34 | /** 35 | * FALSE will only apply configurations from classes listed in 36 | * configuration(). Will still use parent instance of 37 | * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, and 38 | * {@link feign.Contract} if none are provided. 39 | * @return weather to inherit parent context for client configuration. 40 | */ 41 | default boolean inheritParentConfiguration() { 42 | return true; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/Http2ClientFeignConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.clientconfig; 18 | 19 | import java.net.http.HttpClient; 20 | import java.time.Duration; 21 | import java.util.List; 22 | 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 24 | import org.springframework.cloud.openfeign.clientconfig.http2client.Http2ClientCustomizer; 25 | import org.springframework.cloud.openfeign.support.FeignHttpClientProperties; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.context.annotation.Configuration; 28 | 29 | /** 30 | * Default configuration for {@link HttpClient}. 31 | * 32 | * @author changjin wei(魏昌进) 33 | * @author Luis Duarte 34 | */ 35 | @Configuration(proxyBeanMethods = false) 36 | @ConditionalOnMissingBean(HttpClient.class) 37 | public class Http2ClientFeignConfiguration { 38 | 39 | @Bean 40 | @ConditionalOnMissingBean 41 | public HttpClient.Builder httpClientBuilder(FeignHttpClientProperties httpClientProperties) { 42 | return HttpClient.newBuilder() 43 | .followRedirects( 44 | httpClientProperties.isFollowRedirects() ? HttpClient.Redirect.ALWAYS : HttpClient.Redirect.NEVER) 45 | .version(HttpClient.Version.valueOf(httpClientProperties.getHttp2().getVersion())) 46 | .connectTimeout(Duration.ofMillis(httpClientProperties.getConnectionTimeout())); 47 | } 48 | 49 | @Bean 50 | public HttpClient httpClient(HttpClient.Builder httpClientBuilder, List customizers) { 51 | customizers.forEach(customizer -> customizer.customize(httpClientBuilder)); 52 | return httpClientBuilder.build(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/http2client/Http2ClientCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.clientconfig.http2client; 18 | 19 | import java.net.http.HttpClient; 20 | 21 | /** 22 | * Callback interface that can be implemented by beans wishing to further customize the 23 | * {@link HttpClient} through {@link HttpClient.Builder} retaining its default 24 | * auto-configuration. 25 | * 26 | * @author Luís Duarte 27 | * @since 4.1.1 28 | */ 29 | @FunctionalInterface 30 | public interface Http2ClientCustomizer { 31 | 32 | /** 33 | * Customize JDK's HttpClient. 34 | * @param builder the HttpClient.Builder to customize 35 | */ 36 | void customize(HttpClient.Builder builder); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/encoding/BaseRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | import feign.RequestInterceptor; 20 | import feign.RequestTemplate; 21 | 22 | import org.springframework.util.Assert; 23 | 24 | /** 25 | * The base request interceptor. 26 | * 27 | * @author Jakub Narloch 28 | */ 29 | public abstract class BaseRequestInterceptor implements RequestInterceptor { 30 | 31 | /** 32 | * The encoding properties. 33 | */ 34 | private final FeignClientEncodingProperties properties; 35 | 36 | /** 37 | * Creates new instance of {@link BaseRequestInterceptor}. 38 | * @param properties the encoding properties 39 | */ 40 | protected BaseRequestInterceptor(FeignClientEncodingProperties properties) { 41 | Assert.notNull(properties, "Properties can not be null"); 42 | this.properties = properties; 43 | } 44 | 45 | /** 46 | * Adds the header if it wasn't yet specified. 47 | * @param requestTemplate the request 48 | * @param name the header name 49 | * @param values the header values 50 | */ 51 | protected void addHeader(RequestTemplate requestTemplate, String name, String... values) { 52 | 53 | if (!requestTemplate.headers().containsKey(name)) { 54 | requestTemplate.header(name, values); 55 | } 56 | } 57 | 58 | protected FeignClientEncodingProperties getProperties() { 59 | return this.properties; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/encoding/FeignAcceptGzipEncodingAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | import feign.Client; 20 | import feign.Feign; 21 | 22 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 26 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 27 | import org.springframework.cloud.openfeign.FeignAutoConfiguration; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.context.annotation.Conditional; 30 | import org.springframework.context.annotation.Configuration; 31 | 32 | /** 33 | * Configures the Feign response compression. 34 | * 35 | * @author Jakub Narloch 36 | * @author Olga Maciaszek-Sharma 37 | * @see FeignAcceptGzipEncodingInterceptor 38 | */ 39 | @Configuration(proxyBeanMethods = false) 40 | @EnableConfigurationProperties(FeignClientEncodingProperties.class) 41 | @ConditionalOnClass(Feign.class) 42 | @ConditionalOnBean(Client.class) 43 | @ConditionalOnProperty("spring.cloud.openfeign.compression.response.enabled") 44 | // The OK HTTP client uses "transparent" compression. 45 | // If the accept-encoding header is present, it disables transparent compression. 46 | @Conditional(OkHttpFeignClientBeanMissingCondition.class) 47 | @AutoConfigureAfter(FeignAutoConfiguration.class) 48 | public class FeignAcceptGzipEncodingAutoConfiguration { 49 | 50 | @Bean 51 | public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor( 52 | FeignClientEncodingProperties properties) { 53 | return new FeignAcceptGzipEncodingInterceptor(properties); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/encoding/FeignAcceptGzipEncodingInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | import feign.RequestTemplate; 20 | 21 | /** 22 | * Enables the HTTP response payload compression by specifying the {@code Accept-Encoding} 23 | * headers. Although this does not yet mean that the requests will be compressed, it 24 | * requires the remote server to understand the header and be configured to compress 25 | * responses. Still no all responses might be compressed based on the media type matching 26 | * and other factors like the response content length. 27 | * 28 | * @author Jakub Narloch 29 | */ 30 | public class FeignAcceptGzipEncodingInterceptor extends BaseRequestInterceptor { 31 | 32 | /** 33 | * Creates new instance of {@link FeignAcceptGzipEncodingInterceptor}. 34 | * @param properties the encoding properties 35 | */ 36 | protected FeignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) { 37 | super(properties); 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | @Override 44 | public void apply(RequestTemplate template) { 45 | 46 | addHeader(template, HttpEncoding.ACCEPT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING, 47 | HttpEncoding.DEFLATE_ENCODING); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/encoding/FeignContentGzipEncodingAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | import feign.Feign; 20 | 21 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 24 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 25 | import org.springframework.cloud.openfeign.FeignAutoConfiguration; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.context.annotation.Conditional; 28 | import org.springframework.context.annotation.Configuration; 29 | 30 | /** 31 | * Configures the Feign request compression. 32 | * 33 | * @author Jakub Narloch 34 | * @author Olga Maciaszek-Sharma 35 | * @see FeignContentGzipEncodingInterceptor 36 | */ 37 | @Configuration(proxyBeanMethods = false) 38 | @EnableConfigurationProperties(FeignClientEncodingProperties.class) 39 | @ConditionalOnClass(Feign.class) 40 | // The OK HTTP client uses "transparent" compression. 41 | // If the content-encoding header is present, it disables transparent compression. 42 | @Conditional(OkHttpFeignClientBeanMissingCondition.class) 43 | @ConditionalOnProperty("spring.cloud.openfeign.compression.request.enabled") 44 | @AutoConfigureAfter(FeignAutoConfiguration.class) 45 | public class FeignContentGzipEncodingAutoConfiguration { 46 | 47 | @Bean 48 | public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor( 49 | FeignClientEncodingProperties properties) { 50 | return new FeignContentGzipEncodingInterceptor(properties); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/encoding/HttpEncoding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | /** 20 | * Lists all constants used by Feign encoders. 21 | * 22 | * @author Jakub Narloch 23 | */ 24 | public interface HttpEncoding { 25 | 26 | /** 27 | * The HTTP Content-Length header. 28 | */ 29 | String CONTENT_LENGTH = "Content-Length"; 30 | 31 | /** 32 | * The HTTP Content-Type header. 33 | */ 34 | String CONTENT_TYPE = "Content-Type"; 35 | 36 | /** 37 | * The HTTP Accept-Encoding header. 38 | */ 39 | String ACCEPT_ENCODING_HEADER = "Accept-Encoding"; 40 | 41 | /** 42 | * The HTTP Content-Encoding header. 43 | */ 44 | String CONTENT_ENCODING_HEADER = "Content-Encoding"; 45 | 46 | /** 47 | * The GZIP encoding. 48 | */ 49 | String GZIP_ENCODING = "gzip"; 50 | 51 | /** 52 | * The Deflate encoding. 53 | */ 54 | String DEFLATE_ENCODING = "deflate"; 55 | 56 | } 57 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/encoding/OkHttpFeignClientBeanMissingCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | import feign.Client; 20 | import feign.okhttp.OkHttpClient; 21 | 22 | import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 25 | import org.springframework.context.annotation.Condition; 26 | 27 | /** 28 | * A {@link Condition} that verifies whether the conditions for creating Feign 29 | * {@link Client} beans that either are of type {@link OkHttpClient} or have a delegate of 30 | * type {@link OkHttpClient} are not met. 31 | * 32 | * @author Olga Maciaszek-Sharma 33 | * @since 4.0.2 34 | */ 35 | public class OkHttpFeignClientBeanMissingCondition extends AnyNestedCondition { 36 | 37 | public OkHttpFeignClientBeanMissingCondition() { 38 | super(ConfigurationPhase.REGISTER_BEAN); 39 | } 40 | 41 | @ConditionalOnMissingClass("feign.okhttp.OkHttpClient") 42 | static class FeignOkHttpClientPresent { 43 | 44 | } 45 | 46 | @ConditionalOnProperty(value = "spring.cloud.openfeign.okhttp.enabled", havingValue = "false") 47 | static class FeignOkHttpClientEnabled { 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas; 18 | 19 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 23 | import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; 24 | import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; 25 | import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; 26 | import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | import org.springframework.hateoas.config.HateoasConfiguration; 30 | import org.springframework.hateoas.config.WebConverters; 31 | 32 | /** 33 | * @author Hector Espert 34 | * @author Olga Maciaszek-Sharma 35 | */ 36 | @Configuration(proxyBeanMethods = false) 37 | @ConditionalOnWebApplication 38 | @ConditionalOnClass(WebConverters.class) 39 | @AutoConfigureAfter({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, 40 | RepositoryRestMvcAutoConfiguration.class, HateoasConfiguration.class }) 41 | public class FeignHalAutoConfiguration { 42 | 43 | @Bean 44 | @ConditionalOnBean(WebConverters.class) 45 | HttpMessageConverterCustomizer webConvertersCustomizer(WebConverters webConverters) { 46 | return new WebConvertersCustomizer(webConverters); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/hateoas/WebConvertersCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas; 18 | 19 | import java.util.List; 20 | 21 | import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; 22 | import org.springframework.hateoas.config.WebConverters; 23 | import org.springframework.http.converter.HttpMessageConverter; 24 | 25 | /** 26 | * @author Olga Maciaszek-Sharma 27 | */ 28 | public class WebConvertersCustomizer implements HttpMessageConverterCustomizer { 29 | 30 | private final WebConverters webConverters; 31 | 32 | public WebConvertersCustomizer(WebConverters webConverters) { 33 | this.webConverters = webConverters; 34 | } 35 | 36 | @Override 37 | public void accept(List> httpMessageConverters) { 38 | webConverters.augmentClient(httpMessageConverters); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/LoadBalancerFeignRequestTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.loadbalancer; 18 | 19 | import feign.Request; 20 | 21 | import org.springframework.cloud.client.ServiceInstance; 22 | import org.springframework.core.annotation.Order; 23 | 24 | /** 25 | * Allows applications to transform the load-balanced {@link Request} given the chosen 26 | * {@link org.springframework.cloud.client.ServiceInstance}. 27 | * 28 | * @author changjin wei(魏昌进) 29 | */ 30 | @Order(LoadBalancerFeignRequestTransformer.DEFAULT_ORDER) 31 | public interface LoadBalancerFeignRequestTransformer { 32 | 33 | /** 34 | * Order for the {@link LoadBalancerFeignRequestTransformer}. 35 | */ 36 | int DEFAULT_ORDER = 0; 37 | 38 | /** 39 | * Allows transforming load-balanced requests based on the provided 40 | * {@link ServiceInstance}. 41 | * @param request Original request. 42 | * @param instance ServiceInstance returned from LoadBalancer. 43 | * @return New request or original request 44 | */ 45 | Request transformRequest(Request request, ServiceInstance instance); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/LoadBalancerResponseStatusCodeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.loadbalancer; 18 | 19 | import java.io.ByteArrayInputStream; 20 | import java.net.URI; 21 | 22 | import feign.Response; 23 | 24 | import org.springframework.cloud.client.loadbalancer.RetryableStatusCodeException; 25 | 26 | /** 27 | * A {@link RetryableStatusCodeException} for {@link Response}s. 28 | * 29 | * @author Ryan Baxter 30 | */ 31 | public class LoadBalancerResponseStatusCodeException extends RetryableStatusCodeException { 32 | 33 | private final Response response; 34 | 35 | public LoadBalancerResponseStatusCodeException(String serviceId, Response response, byte[] body, URI uri) { 36 | super(serviceId, response.status(), response, uri); 37 | this.response = Response.builder() 38 | .body(new ByteArrayInputStream(body), body.length) 39 | .headers(response.headers()) 40 | .reason(response.reason()) 41 | .status(response.status()) 42 | .request(response.request()) 43 | .build(); 44 | } 45 | 46 | @Override 47 | public Response getResponse() { 48 | return this.response; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/OnRetryNotEnabledCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.loadbalancer; 18 | 19 | import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 23 | import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory; 24 | import org.springframework.retry.support.RetryTemplate; 25 | 26 | /** 27 | * A condition that verifies that {@link RetryTemplate} is on the classpath, a 28 | * {@link LoadBalancedRetryFactory} bean is present and 29 | * spring.cloud.loadbalancer.retry.enabled is not set to false. 30 | * 31 | * @author Olga Maciaszek-Sharma 32 | * @since 2.2.6 33 | */ 34 | public class OnRetryNotEnabledCondition extends AnyNestedCondition { 35 | 36 | public OnRetryNotEnabledCondition() { 37 | super(ConfigurationPhase.REGISTER_BEAN); 38 | } 39 | 40 | @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate") 41 | static class OnNoRetryTemplateCondition { 42 | 43 | } 44 | 45 | @ConditionalOnMissingBean(LoadBalancedRetryFactory.class) 46 | static class OnRetryFactoryCondition { 47 | 48 | } 49 | 50 | @ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "false") 51 | static class OnLoadBalancerRetryEnabledCondition { 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/XForwardedHeadersTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.loadbalancer; 18 | 19 | import java.net.URI; 20 | import java.util.Collection; 21 | import java.util.Collections; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | import feign.Request; 26 | 27 | import org.springframework.cloud.client.ServiceInstance; 28 | import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties; 29 | import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer; 30 | 31 | /** 32 | * To add X-Forwarded-Host and X-Forwarded-Proto Headers. 33 | * 34 | * @author changjin wei(魏昌进) 35 | */ 36 | public class XForwardedHeadersTransformer implements LoadBalancerFeignRequestTransformer { 37 | 38 | private final ReactiveLoadBalancer.Factory factory; 39 | 40 | public XForwardedHeadersTransformer(ReactiveLoadBalancer.Factory factory) { 41 | this.factory = factory; 42 | } 43 | 44 | @Override 45 | public Request transformRequest(Request request, ServiceInstance instance) { 46 | if (instance == null) { 47 | return request; 48 | } 49 | LoadBalancerProperties.XForwarded xForwarded = factory.getProperties(instance.getServiceId()).getXForwarded(); 50 | if (xForwarded.isEnabled()) { 51 | Map> headers = new HashMap<>(request.headers()); 52 | URI uri = URI.create(request.url()); 53 | String xForwardedHost = uri.getHost(); 54 | String xForwardedProto = uri.getScheme(); 55 | headers.put("X-Forwarded-Host", Collections.singleton(xForwardedHost)); 56 | headers.put("X-Forwarded-Proto", Collections.singleton(xForwardedProto)); 57 | request = Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(), 58 | request.requestTemplate()); 59 | } 60 | return request; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/AbstractFormWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import java.io.IOException; 20 | import java.lang.reflect.Array; 21 | import java.util.Iterator; 22 | import java.util.function.Predicate; 23 | 24 | import feign.codec.EncodeException; 25 | import feign.form.multipart.AbstractWriter; 26 | import feign.form.multipart.Output; 27 | import feign.form.util.PojoUtil; 28 | 29 | import org.springframework.http.MediaType; 30 | import org.springframework.web.multipart.MultipartFile; 31 | 32 | import static feign.form.ContentProcessor.CRLF; 33 | 34 | /** 35 | * @author Darren Foong 36 | * @author Wu Daifu 37 | */ 38 | public abstract class AbstractFormWriter extends AbstractWriter { 39 | 40 | @Override 41 | public boolean isApplicable(Object object) { 42 | return !isTypeOrCollection(object, o -> o instanceof MultipartFile) 43 | && isTypeOrCollection(object, PojoUtil::isUserPojo); 44 | } 45 | 46 | @Override 47 | public void write(Output output, String key, Object object) throws EncodeException { 48 | try { 49 | String string = new StringBuilder().append("Content-Disposition: form-data; name=\"") 50 | .append(key) 51 | .append('"') 52 | .append(CRLF) 53 | .append("Content-Type: ") 54 | .append(getContentType()) 55 | .append("; charset=") 56 | .append(output.getCharset().name()) 57 | .append(CRLF) 58 | .append(CRLF) 59 | .append(writeAsString(object)) 60 | .toString(); 61 | 62 | output.write(string); 63 | } 64 | catch (IOException e) { 65 | throw new EncodeException(e.getMessage()); 66 | } 67 | } 68 | 69 | protected abstract MediaType getContentType(); 70 | 71 | protected abstract String writeAsString(Object object) throws IOException; 72 | 73 | private boolean isTypeOrCollection(Object object, Predicate isType) { 74 | if (object == null) { 75 | return false; 76 | } 77 | if (object.getClass().isArray()) { 78 | int len = Array.getLength(object); 79 | if (len > 0) { 80 | Object one = Array.get(object, 0); 81 | return len > 1 && one != null && isType.test(one); 82 | } 83 | return false; 84 | } 85 | else if (object instanceof Iterable iterable) { 86 | Iterator iterator = iterable.iterator(); 87 | 88 | return iterator.hasNext() && isType.test(iterator.next()); 89 | } 90 | else { 91 | return isType.test(object); 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/EmptyObjectProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import java.util.function.Consumer; 20 | 21 | import org.springframework.beans.BeansException; 22 | import org.springframework.beans.factory.ObjectProvider; 23 | 24 | /** 25 | * @author Olga Maciaszek-Sharma 26 | */ 27 | class EmptyObjectProvider implements ObjectProvider { 28 | 29 | @Override 30 | public T getObject(Object... args) throws BeansException { 31 | return null; 32 | } 33 | 34 | @Override 35 | public T getIfAvailable() throws BeansException { 36 | return null; 37 | } 38 | 39 | @Override 40 | public T getIfUnique() throws BeansException { 41 | return null; 42 | } 43 | 44 | @Override 45 | public T getObject() throws BeansException { 46 | return null; 47 | } 48 | 49 | @Override 50 | public void forEach(Consumer action) { 51 | // do nothing 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/FeignEncoderProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import org.springframework.boot.context.properties.ConfigurationProperties; 20 | 21 | /** 22 | * Properties for {@link SpringEncoder}. 23 | * 24 | * @author Olga Maciaszek-Sharma 25 | * @since 2.2.8 26 | */ 27 | @ConfigurationProperties("spring.cloud.openfeign.encoder") 28 | public class FeignEncoderProperties { 29 | 30 | /** 31 | * Indicates whether the charset should be derived from the {@code Content-Type} 32 | * header. 33 | */ 34 | private boolean charsetFromContentType = false; 35 | 36 | public boolean isCharsetFromContentType() { 37 | return charsetFromContentType; 38 | } 39 | 40 | public void setCharsetFromContentType(boolean charsetFromContentType) { 41 | this.charsetFromContentType = charsetFromContentType; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/FeignUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.Map; 22 | 23 | import org.springframework.http.HttpHeaders; 24 | 25 | import static java.util.Optional.ofNullable; 26 | 27 | /** 28 | * @author Spencer Gibb 29 | * @author Olga Maciaszek-Sharma 30 | */ 31 | public final class FeignUtils { 32 | 33 | private FeignUtils() { 34 | throw new IllegalStateException("Can't instantiate a utility class"); 35 | } 36 | 37 | static HttpHeaders getHttpHeaders(Map> headers) { 38 | HttpHeaders httpHeaders = new HttpHeaders(); 39 | for (Map.Entry> entry : headers.entrySet()) { 40 | httpHeaders.put(entry.getKey(), new ArrayList<>(entry.getValue())); 41 | } 42 | return httpHeaders; 43 | } 44 | 45 | static Collection addTemplateParameter(Collection possiblyNull, String paramName) { 46 | Collection params = ofNullable(possiblyNull).map(ArrayList::new).orElse(new ArrayList<>()); 47 | params.add(String.format("{%s}", paramName)); 48 | return params; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/HttpMessageConverterCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import java.util.List; 20 | import java.util.function.Consumer; 21 | 22 | import org.springframework.http.converter.HttpMessageConverter; 23 | 24 | /** 25 | * Allows customising {@link HttpMessageConverter} objects passed via {@link Consumer} 26 | * parameter. 27 | * 28 | * @author Olga Maciaszek-Sharma 29 | * @since 3.1.0 30 | */ 31 | public interface HttpMessageConverterCustomizer extends Consumer>> { 32 | 33 | } 34 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/JsonFormWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import java.io.IOException; 20 | 21 | import com.fasterxml.jackson.databind.ObjectMapper; 22 | 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.http.MediaType; 25 | import org.springframework.stereotype.Component; 26 | 27 | /** 28 | * @author Darren Foong 29 | */ 30 | @Component 31 | public class JsonFormWriter extends AbstractFormWriter { 32 | 33 | @Autowired 34 | private ObjectMapper objectMapper; 35 | 36 | @Override 37 | protected MediaType getContentType() { 38 | return MediaType.APPLICATION_JSON; 39 | } 40 | 41 | @Override 42 | protected String writeAsString(Object object) throws IOException { 43 | return objectMapper.writeValueAsString(object); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/ResponseEntityDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import java.io.IOException; 20 | import java.lang.reflect.ParameterizedType; 21 | import java.lang.reflect.Type; 22 | import java.util.LinkedList; 23 | 24 | import feign.FeignException; 25 | import feign.Response; 26 | import feign.codec.Decoder; 27 | 28 | import org.springframework.http.HttpEntity; 29 | import org.springframework.http.HttpHeaders; 30 | import org.springframework.http.HttpStatusCode; 31 | import org.springframework.http.ResponseEntity; 32 | 33 | /** 34 | * Decoder adds compatibility for Spring MVC's ResponseEntity to any other decoder via 35 | * composition. 36 | * 37 | * @author chad jaros 38 | * @author Olga Maciaszek-Sharma 39 | * @author Maksym Pasichenko 40 | */ 41 | public class ResponseEntityDecoder implements Decoder { 42 | 43 | private final Decoder decoder; 44 | 45 | public ResponseEntityDecoder(Decoder decoder) { 46 | this.decoder = decoder; 47 | } 48 | 49 | @Override 50 | public Object decode(final Response response, Type type) throws IOException, FeignException { 51 | 52 | if (isParameterizeHttpEntity(type)) { 53 | type = ((ParameterizedType) type).getActualTypeArguments()[0]; 54 | Object decodedObject = this.decoder.decode(response, type); 55 | 56 | return createResponse(decodedObject, response); 57 | } 58 | else if (isHttpEntity(type)) { 59 | return createResponse(null, response); 60 | } 61 | else { 62 | return this.decoder.decode(response, type); 63 | } 64 | } 65 | 66 | private boolean isParameterizeHttpEntity(Type type) { 67 | if (type instanceof ParameterizedType) { 68 | return isHttpEntity(((ParameterizedType) type).getRawType()); 69 | } 70 | return false; 71 | } 72 | 73 | private boolean isHttpEntity(Type type) { 74 | if (type instanceof Class c) { 75 | return HttpEntity.class.isAssignableFrom(c); 76 | } 77 | return false; 78 | } 79 | 80 | @SuppressWarnings("unchecked") 81 | private ResponseEntity createResponse(Object instance, Response response) { 82 | 83 | HttpHeaders headers = new HttpHeaders(); 84 | for (String key : response.headers().keySet()) { 85 | headers.put(key, new LinkedList<>(response.headers().get(key))); 86 | } 87 | 88 | return new ResponseEntity<>((T) instance, headers, HttpStatusCode.valueOf(response.status())); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SortJacksonModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import com.fasterxml.jackson.core.Version; 20 | import com.fasterxml.jackson.databind.Module; 21 | import com.fasterxml.jackson.databind.module.SimpleDeserializers; 22 | import com.fasterxml.jackson.databind.module.SimpleSerializers; 23 | 24 | import org.springframework.data.domain.Sort; 25 | 26 | /** 27 | * This Jackson module provides support for serializing and deserializing for Spring 28 | * {@link Sort} object. 29 | * 30 | * @author Can Bezmen 31 | */ 32 | public class SortJacksonModule extends Module { 33 | 34 | @Override 35 | public String getModuleName() { 36 | return "SortModule"; 37 | } 38 | 39 | @Override 40 | public Version version() { 41 | return new Version(0, 1, 0, "", null, null); 42 | } 43 | 44 | @Override 45 | public void setupModule(SetupContext context) { 46 | SimpleSerializers serializers = new SimpleSerializers(); 47 | serializers.addSerializer(Sort.class, new SortJsonComponent.SortSerializer()); 48 | context.addSerializers(serializers); 49 | 50 | SimpleDeserializers deserializers = new SimpleDeserializers(); 51 | deserializers.addDeserializer(Sort.class, new SortJsonComponent.SortDeserializer()); 52 | context.addDeserializers(deserializers); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/resources/META-INF/spring/aot.factories: -------------------------------------------------------------------------------- 1 | org.springframework.aot.hint.RuntimeHintsRegistrar=\ 2 | org.springframework.cloud.openfeign.FeignHints 3 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration 2 | org.springframework.cloud.openfeign.FeignAutoConfiguration 3 | org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration 4 | org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration 5 | org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration 6 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.codec.Encoder; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 24 | import org.springframework.boot.test.context.SpringBootTest; 25 | import org.springframework.cloud.openfeign.support.PageableSpringEncoder; 26 | import org.springframework.context.annotation.Configuration; 27 | import org.springframework.test.annotation.DirtiesContext; 28 | 29 | /** 30 | * @author Spencer Gibb 31 | */ 32 | @SpringBootTest(classes = EnableFeignClientsSpringDataTests.PlainConfiguration.class) 33 | @DirtiesContext 34 | class EnableFeignClientsSpringDataTests { 35 | 36 | @Autowired 37 | private FeignClientFactory feignClientFactory; 38 | 39 | @Test 40 | void encoderDefaultCorrect() { 41 | PageableSpringEncoder.class.cast(this.feignClientFactory.getInstance("foo", Encoder.class)); 42 | } 43 | 44 | @Configuration(proxyBeanMethods = false) 45 | @EnableAutoConfiguration 46 | protected static class PlainConfiguration { 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Contract; 20 | import feign.Feign; 21 | import feign.Logger; 22 | import feign.codec.Decoder; 23 | import feign.codec.Encoder; 24 | import feign.optionals.OptionalDecoder; 25 | import feign.slf4j.Slf4jLogger; 26 | import org.junit.jupiter.api.AfterEach; 27 | import org.junit.jupiter.api.BeforeEach; 28 | import org.junit.jupiter.api.Test; 29 | 30 | import org.springframework.boot.WebApplicationType; 31 | import org.springframework.boot.builder.SpringApplicationBuilder; 32 | import org.springframework.cloud.openfeign.support.SpringEncoder; 33 | import org.springframework.cloud.openfeign.support.SpringMvcContract; 34 | import org.springframework.cloud.test.ClassPathExclusions; 35 | import org.springframework.context.ConfigurableApplicationContext; 36 | import org.springframework.context.annotation.Configuration; 37 | import org.springframework.context.annotation.Import; 38 | 39 | /** 40 | * @author Spencer Gibb 41 | */ 42 | @ClassPathExclusions({ "spring-data-commons-*.jar" }) 43 | class EnableFeignClientsTests { 44 | 45 | private ConfigurableApplicationContext context; 46 | 47 | @BeforeEach 48 | void setUp() { 49 | context = new SpringApplicationBuilder().web(WebApplicationType.NONE) 50 | .properties("debug=true", "spring.cloud.openfeign.httpclient.hc5.enabled=false") 51 | .sources(EnableFeignClientsTests.PlainConfiguration.class) 52 | .run(); 53 | } 54 | 55 | @AfterEach 56 | void tearDown() { 57 | if (context != null) { 58 | context.close(); 59 | } 60 | } 61 | 62 | @Test 63 | void decoderDefaultCorrect() { 64 | OptionalDecoder.class.cast(this.context.getBeansOfType(Decoder.class).get(0)); 65 | } 66 | 67 | @Test 68 | void encoderDefaultCorrect() { 69 | SpringEncoder.class.cast(this.context.getBeansOfType(Encoder.class).get(0)); 70 | } 71 | 72 | @Test 73 | void loggerDefaultCorrect() { 74 | Slf4jLogger.class.cast(this.context.getBeansOfType(Logger.class).get(0)); 75 | } 76 | 77 | @Test 78 | void contractDefaultCorrect() { 79 | SpringMvcContract.class.cast(this.context.getBeansOfType(Contract.class).get(0)); 80 | } 81 | 82 | @Test 83 | void builderDefaultCorrect() { 84 | Feign.Builder.class.cast(this.context.getBeansOfType(Feign.Builder.class).get(0)); 85 | } 86 | 87 | @Configuration(proxyBeanMethods = false) 88 | @Import({ FeignAutoConfiguration.class }) 89 | protected static class PlainConfiguration { 90 | 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignHttp2ClientConfigurationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.net.http.HttpClient; 20 | import java.time.Duration; 21 | import java.util.Optional; 22 | 23 | import org.junit.jupiter.api.AfterEach; 24 | import org.junit.jupiter.api.BeforeEach; 25 | import org.junit.jupiter.api.Test; 26 | 27 | import org.springframework.boot.WebApplicationType; 28 | import org.springframework.boot.builder.SpringApplicationBuilder; 29 | import org.springframework.context.ConfigurableApplicationContext; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | 33 | /** 34 | * @author changjin wei(魏昌进) 35 | * @author Luis Duarte 36 | */ 37 | class FeignHttp2ClientConfigurationTests { 38 | 39 | private ConfigurableApplicationContext context; 40 | 41 | @BeforeEach 42 | void setUp() { 43 | context = new SpringApplicationBuilder() 44 | .properties("debug=true", "spring.cloud.openfeign.http2client.enabled=true", 45 | "spring.cloud.openfeign.httpclient.http2.version=HTTP_1_1", 46 | "spring.cloud.openfeign.httpclient.connectionTimeout=15") 47 | .web(WebApplicationType.NONE) 48 | .sources(FeignAutoConfiguration.class) 49 | .run(); 50 | } 51 | 52 | @AfterEach 53 | void tearDown() { 54 | if (context != null) { 55 | context.close(); 56 | } 57 | } 58 | 59 | @Test 60 | void shouldConfigureConnectTimeout() { 61 | HttpClient httpClient = context.getBean(HttpClient.class); 62 | 63 | assertThat(httpClient.connectTimeout()).isEqualTo(Optional.ofNullable(Duration.ofMillis(15))); 64 | } 65 | 66 | @Test 67 | void shouldResolveVersionFromProperties() { 68 | HttpClient httpClient = context.getBean(HttpClient.class); 69 | 70 | assertThat(httpClient.version()).isEqualTo(HttpClient.Version.HTTP_1_1); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/OptionsTestClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import java.util.Collection; 20 | import java.util.Collections; 21 | import java.util.LinkedHashMap; 22 | import java.util.Map; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import com.fasterxml.jackson.core.JsonProcessingException; 26 | import com.fasterxml.jackson.databind.DeserializationFeature; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 29 | import feign.Client; 30 | import feign.Request; 31 | import feign.Response; 32 | 33 | /** 34 | * @author Jasbir Singh 35 | */ 36 | public class OptionsTestClient implements Client { 37 | 38 | private final static ObjectMapper mapper; 39 | 40 | static { 41 | mapper = new ObjectMapper(); 42 | mapper.registerModule(new JavaTimeModule()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 43 | } 44 | 45 | @Override 46 | public Response execute(Request request, Request.Options options) { 47 | return Response.builder() 48 | .status(200) 49 | .request(request) 50 | .headers(headers()) 51 | .body(prepareResponse(options)) 52 | .build(); 53 | } 54 | 55 | private Map> headers() { 56 | Map> headers = new LinkedHashMap<>(); 57 | headers.put("Content-Type", Collections.singletonList("application/json")); 58 | return headers; 59 | } 60 | 61 | private byte[] prepareResponse(Request.Options options) { 62 | try { 63 | 64 | OptionsResponseForTests response = new OptionsResponseForTests(options.connectTimeoutMillis(), 65 | TimeUnit.MILLISECONDS, options.readTimeoutMillis(), TimeUnit.MILLISECONDS); 66 | return mapper.writeValueAsString(response).getBytes(); 67 | } 68 | catch (JsonProcessingException e) { 69 | throw new RuntimeException(e); 70 | } 71 | } 72 | 73 | record OptionsResponseForTests(long connectTimeout, TimeUnit connectTimeoutUnit, long readTimeout, 74 | TimeUnit readTimeoutUnit) { 75 | 76 | @Override 77 | public String toString() { 78 | return "OptionsResponseForTests{" + "connectTimeout=" + connectTimeout + ", connectTimeoutUnit=" 79 | + connectTimeoutUnit + ", readTimeout=" + readTimeout + ", readTimeoutUnit=" + readTimeoutUnit 80 | + '}'; 81 | } 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/SpringDecoderTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign; 18 | 19 | import feign.Request; 20 | import feign.Response; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import org.springframework.beans.factory.ObjectFactory; 25 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters; 26 | import org.springframework.cloud.openfeign.support.SpringDecoder; 27 | 28 | import static org.assertj.core.api.Assertions.assertThatCode; 29 | import static org.mockito.Mockito.mock; 30 | import static org.mockito.Mockito.when; 31 | 32 | /** 33 | * Tests for {@link SpringDecoder}. 34 | * 35 | * @author Olga Maciaszek-Sharma 36 | */ 37 | class SpringDecoderTests { 38 | 39 | SpringDecoder decoder; 40 | 41 | @BeforeEach 42 | void setUp() { 43 | ObjectFactory factory = mock(); 44 | when(factory.getObject()).thenReturn(new HttpMessageConverters()); 45 | decoder = new SpringDecoder(factory); 46 | } 47 | 48 | // Issue: https://github.com/spring-cloud/spring-cloud-openfeign/issues/972 49 | @Test 50 | void shouldNotThrownNPEWhenNoContent() { 51 | assertThatCode( 52 | () -> decoder.decode(Response.builder().request(mock(Request.class)).status(200).build(), String.class)) 53 | .doesNotThrowAnyException(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/beans/FeignClientMockBeanTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.beans; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.test.context.SpringBootTest; 23 | import org.springframework.boot.test.mock.mockito.MockBean; 24 | import org.springframework.cloud.openfeign.FeignClient; 25 | import org.springframework.context.annotation.Bean; 26 | import org.springframework.context.annotation.Configuration; 27 | import org.springframework.web.bind.annotation.GetMapping; 28 | 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | import static org.mockito.Mockito.when; 31 | 32 | /** 33 | * @author Olga Maciaszek-Sharma 34 | */ 35 | @SpringBootTest(classes = FeignClientMockBeanTests.Config.class) 36 | public class FeignClientMockBeanTests { 37 | 38 | @MockBean 39 | private RandomClient randomClient; 40 | 41 | @Autowired 42 | private TestService testService; 43 | 44 | @Test 45 | public void randomClientShouldBeMocked() { 46 | String mockMessage = "Mocked Feign Client"; 47 | when(randomClient.getRandomString()).thenReturn(mockMessage); 48 | 49 | String returnedMessage = testService.testMethod(); 50 | 51 | assertThat(returnedMessage).isEqualTo(mockMessage); 52 | } 53 | 54 | @FeignClient("random-test") 55 | protected interface RandomClient { 56 | 57 | @GetMapping("/random-test") 58 | String getRandomString(); 59 | 60 | } 61 | 62 | @Configuration 63 | protected static class Config { 64 | 65 | @Bean 66 | TestService testService() { 67 | return new TestService(); 68 | } 69 | 70 | } 71 | 72 | } 73 | 74 | class TestService { 75 | 76 | @Autowired 77 | private FeignClientMockBeanTests.RandomClient randomClient; 78 | 79 | public String testMethod() { 80 | return randomClient.getRandomString(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/beans/TestClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.beans; 18 | 19 | import org.springframework.cloud.openfeign.FeignClient; 20 | import org.springframework.cloud.openfeign.beans.BeansFeignClientTests.Hello; 21 | import org.springframework.context.annotation.Primary; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | 24 | @Primary 25 | @FeignClient("localapp") 26 | public interface TestClient { 27 | 28 | @GetMapping("/hello") 29 | Hello getHello(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/beans/extra/TestClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.beans.extra; 18 | 19 | import org.springframework.cloud.openfeign.FeignClient; 20 | import org.springframework.cloud.openfeign.beans.BeansFeignClientTests.Hello; 21 | import org.springframework.web.bind.annotation.GetMapping; 22 | 23 | @FeignClient(value = "otherapp", qualifiers = { "uniquequalifier" }) 24 | public interface TestClient { 25 | 26 | @GetMapping("/hello") 27 | Hello getHello(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/circuitbreaker/AsyncCircuitBreaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.circuitbreaker; 18 | 19 | import java.time.Duration; 20 | import java.util.concurrent.ExecutorService; 21 | import java.util.concurrent.Executors; 22 | import java.util.concurrent.Future; 23 | import java.util.concurrent.TimeUnit; 24 | import java.util.function.Function; 25 | import java.util.function.Supplier; 26 | 27 | import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; 28 | 29 | /** 30 | * Asynchronous circuit breaker. 31 | * 32 | * @author John Niang 33 | */ 34 | class AsyncCircuitBreaker implements CircuitBreaker { 35 | 36 | final Duration timeout; 37 | 38 | final ExecutorService executorService; 39 | 40 | AsyncCircuitBreaker(Duration timeout) { 41 | this(timeout, Executors.newCachedThreadPool()); 42 | } 43 | 44 | AsyncCircuitBreaker(Duration timeout, ExecutorService executorService) { 45 | this.timeout = timeout; 46 | this.executorService = executorService; 47 | } 48 | 49 | @Override 50 | public T run(Supplier toRun, Function fallback) { 51 | Future future = executorService.submit(toRun::get); 52 | try { 53 | return future.get(timeout.toMillis(), TimeUnit.MILLISECONDS); 54 | } 55 | catch (Throwable t) { 56 | return fallback.apply(t); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/circuitbreaker/Hello.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.circuitbreaker; 18 | 19 | import java.util.Objects; 20 | 21 | /** 22 | * @author Marcin Grzejszczak 23 | */ 24 | class Hello { 25 | 26 | private String message; 27 | 28 | public Hello() { 29 | } 30 | 31 | public Hello(String message) { 32 | this.message = message; 33 | } 34 | 35 | public String getMessage() { 36 | return this.message; 37 | } 38 | 39 | public void setMessage(String message) { 40 | this.message = message; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) { 46 | return true; 47 | } 48 | if (o == null || getClass() != o.getClass()) { 49 | return false; 50 | } 51 | Hello that = (Hello) o; 52 | return Objects.equals(this.message, that.message); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return Objects.hash(this.message); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/circuitbreaker/MyCircuitBreaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.circuitbreaker; 18 | 19 | import java.util.concurrent.atomic.AtomicBoolean; 20 | import java.util.function.Function; 21 | import java.util.function.Supplier; 22 | 23 | import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; 24 | import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException; 25 | 26 | /** 27 | * @author Marcin Grzejszczak 28 | * @author Olga Maciaszek-Sharma 29 | */ 30 | class MyCircuitBreaker implements CircuitBreaker { 31 | 32 | AtomicBoolean runWasCalled = new AtomicBoolean(); 33 | 34 | @Override 35 | public T run(Supplier toRun) { 36 | try { 37 | this.runWasCalled.set(true); 38 | return toRun.get(); 39 | } 40 | catch (Throwable throwable) { 41 | throw new NoFallbackAvailableException("No fallback available.", throwable); 42 | } 43 | } 44 | 45 | @Override 46 | public T run(Supplier toRun, Function fallback) { 47 | try { 48 | return run(toRun); 49 | } 50 | catch (Throwable throwable) { 51 | return fallback.apply(throwable); 52 | } 53 | } 54 | 55 | public void clear() { 56 | this.runWasCalled.set(false); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/Invoices.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding; 18 | 19 | import java.math.BigDecimal; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Locale; 23 | 24 | import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; 25 | 26 | /** 27 | * Utility class used for testing. 28 | * 29 | * @author Jakub Narloch 30 | * @author Olga Maciaszek-Sharma 31 | */ 32 | final class Invoices { 33 | 34 | private Invoices() { 35 | throw new IllegalStateException("Can't instantiate a utility class"); 36 | } 37 | 38 | public static List createInvoiceList(int count) { 39 | final List invoices = new ArrayList<>(); 40 | for (int ind = 0; ind < count; ind++) { 41 | final Invoice invoice = new Invoice(); 42 | invoice.setTitle("Invoice " + (ind + 1)); 43 | invoice.setAmount(new BigDecimal(String.format(Locale.US, "%.2f", Math.random() * 1000))); 44 | invoices.add(invoice); 45 | } 46 | return invoices; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding.app.client; 18 | 19 | import java.util.List; 20 | 21 | import org.springframework.cloud.openfeign.FeignClient; 22 | import org.springframework.cloud.openfeign.SpringQueryMap; 23 | import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; 24 | import org.springframework.data.domain.Page; 25 | import org.springframework.http.MediaType; 26 | import org.springframework.http.ResponseEntity; 27 | import org.springframework.web.bind.annotation.GetMapping; 28 | import org.springframework.web.bind.annotation.PostMapping; 29 | import org.springframework.web.bind.annotation.RequestBody; 30 | 31 | /** 32 | * Simple Feign client for retrieving the invoice list. 33 | * 34 | * @author Jakub Narloch 35 | * @author Hyeonmin Park 36 | */ 37 | @FeignClient("local") 38 | public interface InvoiceClient { 39 | 40 | @GetMapping(value = "invoicesPaged", produces = MediaType.APPLICATION_JSON_VALUE) 41 | ResponseEntity> getInvoicesPaged(org.springframework.data.domain.Pageable pageable); 42 | 43 | @PostMapping(value = "invoicesPagedWithBody", consumes = MediaType.APPLICATION_JSON_VALUE, 44 | produces = MediaType.APPLICATION_JSON_VALUE) 45 | ResponseEntity> getInvoicesPagedWithBody( 46 | @SpringQueryMap org.springframework.data.domain.Pageable pageable, @RequestBody String titlePrefix); 47 | 48 | @PostMapping(value = "invoicesSortedWithBody", consumes = MediaType.APPLICATION_JSON_VALUE, 49 | produces = MediaType.APPLICATION_JSON_VALUE) 50 | ResponseEntity> getInvoicesSortedWithBody(@SpringQueryMap org.springframework.data.domain.Sort sort, 51 | @RequestBody String titlePrefix); 52 | 53 | @GetMapping(value = "invoices", produces = MediaType.APPLICATION_JSON_VALUE) 54 | ResponseEntity> getInvoices(); 55 | 56 | @PostMapping(value = "invoices", consumes = MediaType.APPLICATION_JSON_VALUE, 57 | produces = MediaType.APPLICATION_JSON_VALUE) 58 | ResponseEntity> saveInvoices(List invoices); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/domain/Invoice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding.app.domain; 18 | 19 | import java.math.BigDecimal; 20 | 21 | /** 22 | * An Invoice model - used for testing. 23 | * 24 | * @author Jakub Narloch 25 | */ 26 | public class Invoice { 27 | 28 | private String title; 29 | 30 | private BigDecimal amount; 31 | 32 | public String getTitle() { 33 | return this.title; 34 | } 35 | 36 | public void setTitle(String title) { 37 | this.title = title; 38 | } 39 | 40 | public BigDecimal getAmount() { 41 | return this.amount; 42 | } 43 | 44 | public void setAmount(BigDecimal amount) { 45 | this.amount = amount; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/proto/ProtobufNotInClasspathTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.encoding.proto; 18 | 19 | import feign.RequestTemplate; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import org.springframework.beans.factory.ObjectFactory; 23 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters; 24 | import org.springframework.cloud.openfeign.support.SpringEncoder; 25 | import org.springframework.cloud.test.ClassPathExclusions; 26 | import org.springframework.http.converter.StringHttpMessageConverter; 27 | 28 | import static feign.Request.HttpMethod.POST; 29 | 30 | /** 31 | * Test {@link SpringEncoder} when protobuf is not in classpath 32 | * 33 | * @author ScienJus 34 | */ 35 | @ClassPathExclusions("protobuf-*.jar") 36 | class ProtobufNotInClasspathTest { 37 | 38 | @Test 39 | void testEncodeWhenProtobufNotInClasspath() { 40 | ObjectFactory converters = () -> new HttpMessageConverters( 41 | new StringHttpMessageConverter()); 42 | RequestTemplate requestTemplate = new RequestTemplate(); 43 | requestTemplate.method(POST); 44 | new SpringEncoder(converters).encode("a=b", String.class, requestTemplate); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/proto/ProtobufTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Generated by the protocol buffer compiler. DO NOT EDIT! 18 | // source: request.proto 19 | 20 | package org.springframework.cloud.openfeign.encoding.proto; 21 | 22 | public final class ProtobufTest { 23 | 24 | private ProtobufTest() { 25 | } 26 | 27 | public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) { 28 | } 29 | 30 | public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) { 31 | registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry); 32 | } 33 | 34 | static final com.google.protobuf.Descriptors.Descriptor internal_static_org_springframework_cloud_openfeign_encoding_proto_Request_descriptor; 35 | static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_org_springframework_cloud_openfeign_encoding_proto_Request_fieldAccessorTable; 36 | 37 | public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { 38 | return descriptor; 39 | } 40 | 41 | private static com.google.protobuf.Descriptors.FileDescriptor descriptor; 42 | 43 | static { 44 | String[] descriptorData = { 45 | "\n\rrequest.proto\0222org.springframework.clo" + "ud.openfeign.encoding.proto\"\"\n\007Request\022\n" 46 | + "\n\002id\030\001 \001(\005\022\013\n\003msg\030\002 \001(\tBD\n2org.springfra" 47 | + "mework.cloud.openfeign.encoding.protoB\014P" + "rotobufTestP\001b\006proto3" }; 48 | descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(descriptorData, 49 | new com.google.protobuf.Descriptors.FileDescriptor[] {}); 50 | internal_static_org_springframework_cloud_openfeign_encoding_proto_Request_descriptor = getDescriptor() 51 | .getMessageTypes() 52 | .get(0); 53 | internal_static_org_springframework_cloud_openfeign_encoding_proto_Request_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 54 | internal_static_org_springframework_cloud_openfeign_encoding_proto_Request_descriptor, 55 | new String[] { "Id", "Msg", }); 56 | } 57 | 58 | // @@protoc_insertion_point(outer_class_scope) 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/proto/RequestOrBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Generated by the protocol buffer compiler. DO NOT EDIT! 18 | // source: request.proto 19 | 20 | package org.springframework.cloud.openfeign.encoding.proto; 21 | 22 | public interface RequestOrBuilder extends 23 | // @@protoc_insertion_point(interface_extends:org.springframework.cloud.openfeign.encoding.proto.Request) 24 | com.google.protobuf.MessageOrBuilder { 25 | 26 | /** 27 | * int32 id = 1; 28 | * @return The id. 29 | */ 30 | int getId(); 31 | 32 | /** 33 | * string msg = 2; 34 | * @return The msg. 35 | */ 36 | String getMsg(); 37 | 38 | /** 39 | * string msg = 2; 40 | * @return The bytes for msg. 41 | */ 42 | com.google.protobuf.ByteString getMsgBytes(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/feignclientsregistrar/TopLevelClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.feignclientsregistrar; 18 | 19 | import org.springframework.cloud.openfeign.FeignClient; 20 | 21 | /** 22 | * @author Michal Domagala 23 | */ 24 | 25 | @FeignClient("top-level") 26 | public interface TopLevelClient { 27 | 28 | } 29 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/feignclientsregistrar/sub/SubLevelClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.feignclientsregistrar.sub; 18 | 19 | import org.springframework.cloud.openfeign.FeignClient; 20 | 21 | /** 22 | * @author Michal Domagala 23 | */ 24 | 25 | @FeignClient("sub-level") 26 | public interface SubLevelClient { 27 | 28 | } 29 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/FeignHalAutoConfigurationContextTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas; 18 | 19 | import org.junit.jupiter.api.BeforeEach; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import org.springframework.boot.autoconfigure.AutoConfigurations; 23 | import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; 24 | import org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration; 25 | import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; 26 | import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; 27 | import org.springframework.boot.test.context.FilteredClassLoader; 28 | import org.springframework.boot.test.context.runner.WebApplicationContextRunner; 29 | import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; 30 | import org.springframework.hateoas.config.WebConverters; 31 | 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | 34 | /** 35 | * @author Hector Espert 36 | * @author Olga Maciaszek-Sharma 37 | */ 38 | class FeignHalAutoConfigurationContextTests { 39 | 40 | private WebApplicationContextRunner contextRunner; 41 | 42 | @BeforeEach 43 | void setUp() { 44 | contextRunner = new WebApplicationContextRunner() 45 | .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, 46 | HttpMessageConvertersAutoConfiguration.class, HypermediaAutoConfiguration.class, 47 | RepositoryRestMvcAutoConfiguration.class, FeignHalAutoConfiguration.class)) 48 | .withPropertyValues("debug=true"); 49 | } 50 | 51 | @Test 52 | void shouldNotLoadWebConvertersCustomizerWhenNotWebConvertersNotInClasspath() { 53 | FilteredClassLoader filteredClassLoader = new FilteredClassLoader(RepositoryRestMvcConfiguration.class, 54 | WebConverters.class); 55 | contextRunner.withClassLoader(filteredClassLoader) 56 | .run(context -> assertThat(context).doesNotHaveBean("webConvertersCustomizer")); 57 | } 58 | 59 | @Test 60 | void shouldLoadWebConvertersCustomizer() { 61 | FilteredClassLoader filteredClassLoader = new FilteredClassLoader(RepositoryRestMvcConfiguration.class); 62 | contextRunner.withClassLoader(filteredClassLoader) 63 | .run(context -> assertThat(context).hasBean("webConvertersCustomizer")); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/app/FeignHalApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas.app; 18 | 19 | import org.springframework.boot.autoconfigure.SpringBootApplication; 20 | import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; 21 | import org.springframework.boot.test.web.server.LocalServerPort; 22 | import org.springframework.cloud.client.DefaultServiceInstance; 23 | import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; 24 | import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; 25 | import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSuppliers; 26 | import org.springframework.cloud.openfeign.EnableFeignClients; 27 | import org.springframework.cloud.openfeign.test.NoSecurityConfiguration; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.context.annotation.Import; 30 | 31 | /** 32 | * Test HATEOAS application. 33 | * 34 | * @author Hector Espert 35 | */ 36 | @EnableFeignClients(clients = FeignHalClient.class) 37 | @SpringBootApplication(scanBasePackages = "org.springframework.cloud.openfeign.hateoas.app", 38 | exclude = RepositoryRestMvcAutoConfiguration.class) 39 | @LoadBalancerClient(name = "local", configuration = LocalHalClientConfiguration.class) 40 | @Import(NoSecurityConfiguration.class) 41 | public class FeignHalApplication { 42 | 43 | // Load balancer with fixed server list for "local" pointing to localhost 44 | 45 | } 46 | 47 | class LocalHalClientConfiguration { 48 | 49 | @LocalServerPort 50 | private int port = 0; 51 | 52 | @Bean 53 | public ServiceInstanceListSupplier staticServiceInstanceListSupplier() { 54 | return ServiceInstanceListSuppliers.from("local", 55 | new DefaultServiceInstance("local-1", "local", "localhost", port, false)); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/app/FeignHalClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas.app; 18 | 19 | import org.springframework.cloud.openfeign.FeignClient; 20 | import org.springframework.hateoas.CollectionModel; 21 | import org.springframework.hateoas.EntityModel; 22 | import org.springframework.hateoas.PagedModel; 23 | import org.springframework.web.bind.annotation.GetMapping; 24 | 25 | /** 26 | * @author Hector Espert 27 | */ 28 | @FeignClient("local") 29 | public interface FeignHalClient { 30 | 31 | @GetMapping("entity") 32 | EntityModel entity(); 33 | 34 | @GetMapping("collection") 35 | CollectionModel collection(); 36 | 37 | @GetMapping("paged") 38 | PagedModel paged(); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/app/FeignHalConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas.app; 18 | 19 | import org.springframework.beans.factory.annotation.Value; 20 | 21 | /** 22 | * @author Hector Espert 23 | */ 24 | public class FeignHalConfiguration { 25 | 26 | @Value("${local.server.port}") 27 | private int serverPort = 0; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/app/FeignHalController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas.app; 18 | 19 | import java.util.Collections; 20 | 21 | import org.springframework.hateoas.CollectionModel; 22 | import org.springframework.hateoas.EntityModel; 23 | import org.springframework.hateoas.Link; 24 | import org.springframework.hateoas.PagedModel; 25 | import org.springframework.web.bind.annotation.GetMapping; 26 | import org.springframework.web.bind.annotation.RestController; 27 | 28 | /** 29 | * @author Hector Espert 30 | */ 31 | @RestController 32 | public class FeignHalController { 33 | 34 | @GetMapping("/entity") 35 | public EntityModel getEntity() { 36 | MarsRover marsRover = new MarsRover(); 37 | marsRover.setName("Sojourner"); 38 | Link link = Link.of("/entity", "self"); 39 | return EntityModel.of(marsRover, link); 40 | } 41 | 42 | @GetMapping("/collection") 43 | public CollectionModel getCollection() { 44 | MarsRover marsRover = new MarsRover(); 45 | marsRover.setName("Opportunity"); 46 | Link link = Link.of("/collection", "self"); 47 | return CollectionModel.of(Collections.singleton(marsRover), link); 48 | } 49 | 50 | @GetMapping("/paged") 51 | public CollectionModel getPaged() { 52 | MarsRover marsRover = new MarsRover(); 53 | marsRover.setName("Curiosity"); 54 | Link link = Link.of("/paged", "self"); 55 | PagedModel.PageMetadata metadata = new PagedModel.PageMetadata(1, 1, 1); 56 | return PagedModel.of(Collections.singleton(marsRover), metadata, link); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/hateoas/app/MarsRover.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.hateoas.app; 18 | 19 | /** 20 | * @author Hector Espert 21 | */ 22 | public class MarsRover { 23 | 24 | private String name; 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/FormWriterTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import org.springframework.http.MediaType; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | 25 | /** 26 | * @author Wu Daifu 27 | * @author Olga Maciaszek-Sharma 28 | */ 29 | class FormWriterTests { 30 | 31 | @Test 32 | void shouldCorrectlyResolveIfApplicableForCollection() { 33 | MockFormWriter formWriter = new MockFormWriter(); 34 | Object object = new Object(); 35 | assertThat(formWriter.isApplicable(object)).isFalse(); 36 | object = new Object[] { new Object(), new Object() }; 37 | assertThat(formWriter.isApplicable(object)).isFalse(); 38 | object = new UserPojo(); 39 | assertThat(formWriter.isApplicable(object)).isTrue(); 40 | object = new UserPojo[] { new UserPojo(), new UserPojo() }; 41 | assertThat(formWriter.isApplicable(object)).isTrue(); 42 | object = new byte[] { '1', '2' }; 43 | assertThat(formWriter.isApplicable(object)).isFalse(); 44 | } 45 | 46 | static class MockFormWriter extends AbstractFormWriter { 47 | 48 | @Override 49 | protected MediaType getContentType() { 50 | return null; 51 | } 52 | 53 | @Override 54 | protected String writeAsString(Object object) { 55 | return null; 56 | } 57 | 58 | } 59 | 60 | static class UserPojo { 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderWithSpringDataWebTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties; 20 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; 24 | 25 | /** 26 | * Tests the pagination encoding and sorting. 27 | * 28 | * @author Yanming Zhou 29 | */ 30 | @EnableConfigurationProperties(SpringDataWebProperties.class) 31 | @SpringBootTest(classes = SpringEncoderTests.Application.class, webEnvironment = RANDOM_PORT, 32 | value = { "spring.application.name=springencodertest", "spring.jmx.enabled=false", 33 | "spring.data.web.pageable.pageParameter=pageNo", "spring.data.web.pageable.sizeParameter=pageSize", 34 | "spring.data.web.sort.sortParameter=orderBy" }) 35 | public class PageableEncoderWithSpringDataWebTests extends PageableEncoderTests { 36 | 37 | @Override 38 | protected String getPageParameter() { 39 | return "pageNo"; 40 | } 41 | 42 | @Override 43 | protected String getSizeParameter() { 44 | return "pageSize"; 45 | } 46 | 47 | @Override 48 | protected String getSortParameter() { 49 | return "orderBy"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableSpringQueryMapEncoderWithSpringDataWebTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties; 20 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; 24 | 25 | /** 26 | * Tests the pagination encoding and sorting. 27 | * 28 | * @author Yanming Zhou 29 | */ 30 | @EnableConfigurationProperties(SpringDataWebProperties.class) 31 | @SpringBootTest(classes = SpringEncoderTests.Application.class, webEnvironment = RANDOM_PORT, 32 | value = { "spring.application.name=springencodertest", "spring.jmx.enabled=false", 33 | "spring.data.web.pageable.pageParameter=pageNo", "spring.data.web.pageable.sizeParameter=pageSize", 34 | "spring.data.web.sort.sortParameter=orderBy" }) 35 | public class PageableSpringQueryMapEncoderWithSpringDataWebTests extends PageableSpringQueryMapEncoderTests { 36 | 37 | @Override 38 | protected String getPageParameter() { 39 | return "pageNo"; 40 | } 41 | 42 | @Override 43 | protected String getSizeParameter() { 44 | return "pageSize"; 45 | } 46 | 47 | @Override 48 | protected String getSortParameter() { 49 | return "orderBy"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import feign.Response; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | import static org.assertj.core.api.Assertions.assertThatCode; 27 | 28 | /** 29 | * Integration tests for {@link SpringMvcContract}. 30 | * 31 | * @author Olga Maciaszek-Sharma 32 | * @author Ram Anaswara 33 | */ 34 | @SpringBootTest(classes = AbstractSpringMvcContractIntegrationTests.Config.class, 35 | webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) 36 | public class SpringMvcContractIntegrationTests extends AbstractSpringMvcContractIntegrationTests { 37 | 38 | @Autowired 39 | private TestClient client; 40 | 41 | @Test 42 | public void shouldNotThrowInvalidMediaTypeExceptionWhenContentTypeTemplateUsed() { 43 | assertThatCode(() -> client.sendMessage("test", "text/markdown")).doesNotThrowAnyException(); 44 | } 45 | 46 | @Test 47 | public void feignClientShouldPreserveSlash() { 48 | Response response = (Response) client.getMessage("https://www.google.com"); 49 | 50 | String urlQueryParam = getUrlQueryParam(response); 51 | assertThat(urlQueryParam).isEqualTo("https%3A//www.google.com"); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractSlashEncodingIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.support; 18 | 19 | import feign.Response; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | /** 28 | * Integration tests for {@link SpringMvcContract}. 29 | * 30 | * @author Ram Anaswara 31 | */ 32 | @SpringBootTest(classes = SpringMvcContractSlashEncodingIntegrationTests.Config.class, 33 | webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, 34 | properties = { "spring.cloud.openfeign.client.decodeSlash=false" }) 35 | public class SpringMvcContractSlashEncodingIntegrationTests extends AbstractSpringMvcContractIntegrationTests { 36 | 37 | @Autowired 38 | private TestClient client; 39 | 40 | @Test 41 | public void feignClientShouldNotDecodeEncodedSlash() { 42 | Response response = (Response) client.getMessage("https://www.google.com"); 43 | 44 | String urlQueryParam = getUrlQueryParam(response); 45 | assertThat(urlQueryParam).isEqualTo("https%3A%2F%2Fwww.google.com"); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/test/NoSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.test; 18 | 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.context.annotation.Configuration; 21 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 22 | import org.springframework.security.web.SecurityFilterChain; 23 | 24 | @Configuration(proxyBeanMethods = false) 25 | public class NoSecurityConfiguration { 26 | 27 | @Bean 28 | SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 29 | http.authorizeRequests().anyRequest().permitAll().and().csrf().disable(); 30 | return http.build(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/test/OkHttpClientConfigurationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.test; 18 | 19 | import feign.Client; 20 | import okhttp3.OkHttpClient; 21 | import org.junit.jupiter.api.Test; 22 | import org.mockito.MockingDetails; 23 | 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.boot.SpringBootConfiguration; 26 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 27 | import org.springframework.boot.test.context.SpringBootTest; 28 | import org.springframework.cloud.openfeign.FeignClient; 29 | import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient; 30 | import org.springframework.context.annotation.Bean; 31 | import org.springframework.test.annotation.DirtiesContext; 32 | import org.springframework.test.util.ReflectionTestUtils; 33 | 34 | import static org.assertj.core.api.Assertions.assertThat; 35 | import static org.mockito.Mockito.mock; 36 | import static org.mockito.Mockito.mockingDetails; 37 | 38 | /** 39 | * @author Ryan Baxter 40 | * @author Olga Maciaszek-Sharma 41 | */ 42 | @SpringBootTest(properties = { "spring.cloud.openfeign.okhttp.enabled: true", 43 | "spring.cloud.httpclientfactories.ok.enabled: true", "spring.cloud.openfeign.okhttp.enabled: true", 44 | "spring.cloud.openfeign.httpclient.hc5.enabled: false", "spring.cloud.loadbalancer.retry.enabled=false" }) 45 | @DirtiesContext 46 | class OkHttpClientConfigurationTests { 47 | 48 | @Autowired 49 | FeignBlockingLoadBalancerClient feignClient; 50 | 51 | @Test 52 | void testHttpClientWithFeign() { 53 | Client delegate = feignClient.getDelegate(); 54 | assertThat(delegate instanceof feign.okhttp.OkHttpClient).isTrue(); 55 | feign.okhttp.OkHttpClient okHttpClient = (feign.okhttp.OkHttpClient) delegate; 56 | OkHttpClient httpClient = getField(okHttpClient, "delegate"); 57 | MockingDetails httpClientDetails = mockingDetails(httpClient); 58 | assertThat(httpClientDetails.isMock()).isTrue(); 59 | } 60 | 61 | @SuppressWarnings("unchecked") 62 | protected T getField(Object target, String name) { 63 | Object value = ReflectionTestUtils.getField(target, target.getClass(), name); 64 | return (T) value; 65 | } 66 | 67 | @FeignClient(name = "foo") 68 | interface FooClient { 69 | 70 | } 71 | 72 | @SpringBootConfiguration 73 | @EnableAutoConfiguration 74 | static class TestConfig { 75 | 76 | @Bean 77 | public OkHttpClient client() { 78 | return mock(OkHttpClient.class); 79 | } 80 | 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/testclients/TestClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2022 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.openfeign.testclients; 18 | 19 | import org.springframework.cloud.openfeign.FeignClient; 20 | import org.springframework.web.bind.annotation.GetMapping; 21 | 22 | /** 23 | * @author Ryan Baxter 24 | */ 25 | @FeignClient(name = "localapp") 26 | public interface TestClient { 27 | 28 | @GetMapping("/hello") 29 | String getHello(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/application-defaultstest.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | openfeign: 4 | client: 5 | config: 6 | default: 7 | logger-level: FULL 8 | dismiss404: true 9 | default-request-headers: 10 | x-custom-header: 11 | - "default" 12 | x-custom-header-2: 13 | - "2 from default" 14 | default-query-parameters: 15 | customParam1: 16 | - "default" 17 | customParam2: 18 | - "2 from default" 19 | testClientA: 20 | dismiss404: false 21 | default-request-headers: 22 | x-custom-header: 23 | - "from client A" 24 | default-query-parameters: 25 | customParam1: 26 | - "from client A" 27 | testClientB: 28 | default-request-headers: 29 | x-custom-header: 30 | - "from client B" 31 | default-query-parameters: 32 | customParam1: 33 | - "from client B" 34 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9999 3 | compression: 4 | enabled: true 5 | min-response-size: 1024 6 | mime-types: application/xml,application/json 7 | spring: 8 | application: 9 | name: testclient 10 | eureka: 11 | server: 12 | enabled: false 13 | client: 14 | registerWithEureka: false 15 | fetchRegistry: false 16 | endpoints: 17 | health: 18 | sensitive: false 19 | feignClient: 20 | localappName: localapp 21 | methodLevelRequestMappingPath: /hello2 22 | myPlaceholderHeader: myPlaceholderHeaderValue 23 | management.endpoints.web.expose: '*' 24 | 25 | --- 26 | spring.config.activate.on-profile: no-micrometer 27 | spring.cloud.openfeign.micrometer.enabled: false 28 | 29 | --- 30 | spring.config.activate.on-profile: no-foo-micrometer 31 | spring.cloud.openfeign.client.config.foo.micrometer.enabled: false 32 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/dummy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/94b07a531e3f6fec05f066878955f1e99f0a2ba3/spring-cloud-openfeign-core/src/test/resources/dummy.pdf -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/feign-properties.properties: -------------------------------------------------------------------------------- 1 | # This configuration used by test class FeignClientUsingPropertiesTests 2 | logging.level.org.springframework.cloud.openfeign=debug 3 | spring.cloud.openfeign.client.default-to-properties=true 4 | spring.cloud.openfeign.client.default-config=default 5 | spring.cloud.openfeign.client.config.default.connectTimeout=5000 6 | spring.cloud.openfeign.client.config.default.readTimeout=5000 7 | spring.cloud.openfeign.client.config.default.loggerLevel=full 8 | spring.cloud.openfeign.client.config.default.errorDecoder=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.DefaultErrorDecoder 9 | spring.cloud.openfeign.client.config.default.retryer=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.NoRetryer 10 | spring.cloud.openfeign.client.config.default.dismiss404=true 11 | spring.cloud.openfeign.client.config.default.capabilities=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.NoOpCapability 12 | spring.cloud.openfeign.client.config.default.queryMapEncoder=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.NoOpQueryMapEncoder 13 | spring.cloud.openfeign.client.config.foo.requestInterceptors[0]=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.FooRequestInterceptor 14 | spring.cloud.openfeign.client.config.foo.requestInterceptors[1]=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.BarRequestInterceptor 15 | spring.cloud.openfeign.client.config.baz.responseInterceptor=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.BazResponseInterceptor 16 | spring.cloud.openfeign.client.config.singleValue.defaultRequestHeaders[singleValueHeaders]=header 17 | spring.cloud.openfeign.client.config.singleValue.defaultQueryParameters[singleValueParameters]=parameter 18 | spring.cloud.openfeign.client.config.multipleValue.defaultRequestHeaders[multipleValueHeaders]=header1,header2 19 | spring.cloud.openfeign.client.config.multipleValue.defaultQueryParameters[multipleValueParameters]=parameter1,parameter2 20 | spring.cloud.openfeign.client.config.bar.connectTimeout=1000 21 | spring.cloud.openfeign.client.config.bar.readTimeout=1000 22 | spring.cloud.openfeign.client.config.form.encoder=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.FormEncoder 23 | spring.cloud.openfeign.client.config.unwrap.connectTimeout=1000 24 | spring.cloud.openfeign.client.config.unwrap.readTimeout=1000 25 | spring.cloud.openfeign.client.config.unwrap.exceptionPropagationPolicy=unwrap 26 | spring.cloud.openfeign.client.config.readTimeout.readTimeout=1000 27 | spring.cloud.openfeign.client.config.connectTimeout.connectTimeout=1000 28 | spring.cloud.openfeign.client.config.default.followRedirects=false 29 | spring.cloud.openfeign.client.config.feignClientWithFixUrl.url=http://localhost:8888 30 | spring.cloud.openfeign.client.config.configBasedClient.url=http://localhost:9999 31 | spring.cloud.openfeign.client.config.withPathAndUrlFromConfigClient.url=http://localhost:7777 32 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/feign-refreshable-properties.properties: -------------------------------------------------------------------------------- 1 | # This configuration used by test class FeignClientWithRefreshableOptionsTest 2 | logging.level.org.springframework.cloud.openfeign=debug 3 | spring.cloud.openfeign.client.default-to-properties=true 4 | spring.cloud.openfeign.client.default-config=default 5 | spring.cloud.openfeign.client.refresh-enabled=true 6 | spring.cloud.openfeign.client.config.default.connectTimeout=5000 7 | spring.cloud.openfeign.client.config.default.readTimeout=5000 8 | spring.cloud.openfeign.client.config.default.loggerLevel=full 9 | spring.cloud.openfeign.client.config.connectTimeout.connectTimeout=2000 10 | spring.cloud.openfeign.client.config.readTimeout.readTimeout=2000 11 | spring.cloud.openfeign.client.config.refreshableClient.url=http://localhost:8082 12 | spring.cloud.openfeign.client.config.refreshableClientWithFixUrl.url=http://localhost:8888 13 | spring.cloud.openfeign.client.config.refreshableClientForContextRefreshCase.url=http://localhost:8080 14 | spring.cloud.openfeign.client.config.refreshableClientForContextRefreshCaseWithPath.url=http://localhost:8080 15 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/proto/request.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package org.springframework.cloud.openfeign.encoding.proto; 4 | 5 | option java_package = "org.springframework.cloud.openfeign.encoding.proto"; 6 | option java_outer_classname = "ProtobufTest"; 7 | option java_multiple_files = true; 8 | 9 | message Request { 10 | int32 id = 1; 11 | string msg = 2; 12 | } 13 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/withPage.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": [ 3 | { 4 | "id": 3, 5 | "lastName": "Williams", 6 | "firstName": "Thomas", 7 | "email": "w.t@my.domain.com" 8 | }, 9 | { 10 | "id": 1, 11 | "lastName": "Smith", 12 | "firstName": "James", 13 | "email": "s.j@my.domain.com" 14 | }, 15 | { 16 | "id": 11, 17 | "lastName": "Scott", 18 | "firstName": "Steven", 19 | "email": "s.s@my.domain.com" 20 | }, 21 | { 22 | "id": 8, 23 | "lastName": "Rodriguez", 24 | "firstName": "Daniel", 25 | "email": "r.d@my.domain.com" 26 | }, 27 | { 28 | "id": 9, 29 | "lastName": "Martinez", 30 | "firstName": "Robert", 31 | "email": "m.r@my.domain.com" 32 | }, 33 | { 34 | "id": 5, 35 | "lastName": "Jones", 36 | "firstName": "James", 37 | "email": "j.j@my.domain.com" 38 | }, 39 | { 40 | "id": 2, 41 | "lastName": "Johnson", 42 | "firstName": "Robert", 43 | "email": "j.r@my.domain.com" 44 | }, 45 | { 46 | "id": 6, 47 | "lastName": "Garcia", 48 | "firstName": "William", 49 | "email": "g.w@my.domain.com" 50 | }, 51 | { 52 | "id": 7, 53 | "lastName": "Davis", 54 | "firstName": "Richard", 55 | "email": "d.r@my.domain.com" 56 | }, 57 | { 58 | "id": 4, 59 | "lastName": "Brown", 60 | "firstName": "Paul", 61 | "email": "b.p@my.domain.com" 62 | } 63 | ], 64 | "page": { 65 | "number": 0, 66 | "size": 2, 67 | "totalElements": 11, 68 | "totalPages": 6 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/withPageable.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": [ 3 | { 4 | "id": 3, 5 | "lastName": "Williams", 6 | "firstName": "Thomas", 7 | "email": "w.t@my.domain.com" 8 | }, 9 | { 10 | "id": 1, 11 | "lastName": "Smith", 12 | "firstName": "James", 13 | "email": "s.j@my.domain.com" 14 | }, 15 | { 16 | "id": 11, 17 | "lastName": "Scott", 18 | "firstName": "Steven", 19 | "email": "s.s@my.domain.com" 20 | }, 21 | { 22 | "id": 8, 23 | "lastName": "Rodriguez", 24 | "firstName": "Daniel", 25 | "email": "r.d@my.domain.com" 26 | }, 27 | { 28 | "id": 9, 29 | "lastName": "Martinez", 30 | "firstName": "Robert", 31 | "email": "m.r@my.domain.com" 32 | }, 33 | { 34 | "id": 5, 35 | "lastName": "Jones", 36 | "firstName": "James", 37 | "email": "j.j@my.domain.com" 38 | }, 39 | { 40 | "id": 2, 41 | "lastName": "Johnson", 42 | "firstName": "Robert", 43 | "email": "j.r@my.domain.com" 44 | }, 45 | { 46 | "id": 6, 47 | "lastName": "Garcia", 48 | "firstName": "William", 49 | "email": "g.w@my.domain.com" 50 | }, 51 | { 52 | "id": 7, 53 | "lastName": "Davis", 54 | "firstName": "Richard", 55 | "email": "d.r@my.domain.com" 56 | }, 57 | { 58 | "id": 4, 59 | "lastName": "Brown", 60 | "firstName": "Paul", 61 | "email": "b.p@my.domain.com" 62 | } 63 | ], 64 | 65 | "pageable": { 66 | "pageNumber": 0, 67 | "pageSize": 10, 68 | "sort": { 69 | "orders": [ 70 | { 71 | "direction": "DESC", 72 | "property": "lastName", 73 | "ignoreCase": false, 74 | "nullHandling": "NATIVE", 75 | "ascending": false, 76 | "descending": true 77 | } 78 | ], 79 | "sorted": true, 80 | "empty": false, 81 | "unsorted": false 82 | }, 83 | "paged": true, 84 | "unpaged": false 85 | }, 86 | "total": 11, 87 | "last": false, 88 | "first": true, 89 | "empty": false 90 | } 91 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-core/src/test/resources/withoutPageable.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": [ 3 | { 4 | "id": 3, 5 | "lastName": "Williams", 6 | "firstName": "Thomas", 7 | "email": "w.t@my.domain.com" 8 | }, 9 | { 10 | "id": 1, 11 | "lastName": "Smith", 12 | "firstName": "James", 13 | "email": "s.j@my.domain.com" 14 | }, 15 | { 16 | "id": 11, 17 | "lastName": "Scott", 18 | "firstName": "Steven", 19 | "email": "s.s@my.domain.com" 20 | }, 21 | { 22 | "id": 8, 23 | "lastName": "Rodriguez", 24 | "firstName": "Daniel", 25 | "email": "r.d@my.domain.com" 26 | }, 27 | { 28 | "id": 9, 29 | "lastName": "Martinez", 30 | "firstName": "Robert", 31 | "email": "m.r@my.domain.com" 32 | }, 33 | { 34 | "id": 5, 35 | "lastName": "Jones", 36 | "firstName": "James", 37 | "email": "j.j@my.domain.com" 38 | }, 39 | { 40 | "id": 2, 41 | "lastName": "Johnson", 42 | "firstName": "Robert", 43 | "email": "j.r@my.domain.com" 44 | }, 45 | { 46 | "id": 6, 47 | "lastName": "Garcia", 48 | "firstName": "William", 49 | "email": "g.w@my.domain.com" 50 | }, 51 | { 52 | "id": 7, 53 | "lastName": "Davis", 54 | "firstName": "Richard", 55 | "email": "d.r@my.domain.com" 56 | }, 57 | { 58 | "id": 4, 59 | "lastName": "Brown", 60 | "firstName": "Paul", 61 | "email": "b.p@my.domain.com" 62 | } 63 | ], 64 | "sort": { 65 | "orders": [ 66 | { 67 | "direction": "DESC", 68 | "property": "lastName", 69 | "ignoreCase": false, 70 | "nullHandling": "NATIVE", 71 | "ascending": false, 72 | "descending": true 73 | } 74 | ], 75 | "sorted": true, 76 | "empty": false, 77 | "unsorted": false 78 | }, 79 | "size": 2, 80 | "total": 11, 81 | "last": false, 82 | "first": true, 83 | "empty": false 84 | } 85 | -------------------------------------------------------------------------------- /spring-cloud-openfeign-dependencies/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-cloud-dependencies-parent 8 | org.springframework.cloud 9 | 4.3.1-SNAPSHOT 10 | 11 | 12 | spring-cloud-openfeign-dependencies 13 | 4.3.1-SNAPSHOT 14 | pom 15 | spring-cloud-openfeign-dependencies 16 | Spring Cloud OpenFeign Dependencies 17 | 18 | 13.6 19 | 20 | 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-openfeign-core 25 | ${project.version} 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-openfeign 30 | ${project.version} 31 | 32 | 33 | io.github.openfeign 34 | feign-bom 35 | ${feign.version} 36 | pom 37 | import 38 | 39 | 40 | 41 | 42 | 43 | spring 44 | 45 | 46 | spring-snapshots 47 | Spring Snapshots 48 | https://repo.spring.io/snapshot 49 | 50 | true 51 | 52 | 53 | false 54 | 55 | 56 | 57 | spring-milestones 58 | Spring Milestones 59 | https://repo.spring.io/milestone 60 | 61 | false 62 | 63 | 64 | 65 | spring-releases 66 | Spring Releases 67 | https://repo.spring.io/release 68 | 69 | false 70 | 71 | 72 | 73 | 74 | 75 | spring-snapshots 76 | Spring Snapshots 77 | https://repo.spring.io/snapshot 78 | 79 | true 80 | 81 | 82 | false 83 | 84 | 85 | 86 | spring-milestones 87 | Spring Milestones 88 | https://repo.spring.io/milestone 89 | 90 | false 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /spring-cloud-starter-openfeign/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | org.springframework.cloud 7 | spring-cloud-openfeign 8 | 4.3.1-SNAPSHOT 9 | .. 10 | 11 | 12 | https://github.com/spring-cloud/spring-cloud-openfeign 13 | 14 | spring-cloud-starter-openfeign 15 | Spring Cloud Starter OpenFeign 16 | Spring Cloud Starter OpenFeign 17 | https://projects.spring.io/spring-cloud 18 | 19 | Pivotal Software, Inc. 20 | https://www.spring.io 21 | 22 | 23 | ${basedir}/../.. 24 | 25 | 26 | 27 | org.springframework.cloud 28 | spring-cloud-starter 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-openfeign-core 33 | 34 | 35 | org.springframework 36 | spring-web 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-commons 41 | 42 | 43 | io.github.openfeign 44 | feign-core 45 | 46 | 47 | io.github.openfeign 48 | feign-slf4j 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-starter-loadbalancer 53 | true 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/checkstyle/checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------