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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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