From a9d8998747f864269fcda9e31f80ec99a0b4c342 Mon Sep 17 00:00:00 2001 From: Vitalij Berdinskih Date: Mon, 3 Jul 2023 22:15:34 +0300 Subject: [PATCH 1/5] Enrichment of a clone --- core/src/main/java/feign/AsyncFeign.java | 32 ++++++------ core/src/main/java/feign/BaseBuilder.java | 50 +++++++++++-------- core/src/main/java/feign/Feign.java | 22 +++++--- core/src/test/java/feign/BaseBuilderTest.java | 2 + .../java/feign/kotlin/CoroutineFeign.java | 33 ++++++------ 5 files changed, 79 insertions(+), 60 deletions(-) diff --git a/core/src/main/java/feign/AsyncFeign.java b/core/src/main/java/feign/AsyncFeign.java index 8907d0ee5..11f9c9aaa 100644 --- a/core/src/main/java/feign/AsyncFeign.java +++ b/core/src/main/java/feign/AsyncFeign.java @@ -186,30 +186,32 @@ public AsyncBuilder invocationHandlerFactory(InvocationHandlerFactory invocat } public AsyncFeign build() { - super.enrich(); + AsyncBuilder enrichedBuilder = super.enrich(); AsyncResponseHandler responseHandler = (AsyncResponseHandler) Capability.enrich( new AsyncResponseHandler( - logLevel, - logger, - decoder, - errorDecoder, - dismiss404, - closeAfterDecode, responseInterceptor), + enrichedBuilder.logLevel, + enrichedBuilder.logger, + enrichedBuilder.decoder, + enrichedBuilder.errorDecoder, + enrichedBuilder.dismiss404, + enrichedBuilder.closeAfterDecode, enrichedBuilder.responseInterceptor), AsyncResponseHandler.class, - capabilities); + enrichedBuilder.capabilities); final MethodHandler.Factory methodHandlerFactory = new AsynchronousMethodHandler.Factory<>( - client, retryer, requestInterceptors, - responseHandler, logger, logLevel, - propagationPolicy, methodInfoResolver, - new RequestTemplateFactoryResolver(encoder, queryMapEncoder), - options, decoder, errorDecoder); + enrichedBuilder.client, enrichedBuilder.retryer, enrichedBuilder.requestInterceptors, + responseHandler, enrichedBuilder.logger, enrichedBuilder.logLevel, + enrichedBuilder.propagationPolicy, enrichedBuilder.methodInfoResolver, + new RequestTemplateFactoryResolver(enrichedBuilder.encoder, + enrichedBuilder.queryMapEncoder), + enrichedBuilder.options, enrichedBuilder.decoder, enrichedBuilder.errorDecoder); final ReflectiveFeign feign = - new ReflectiveFeign<>(contract, methodHandlerFactory, invocationHandlerFactory, - defaultContextSupplier); + new ReflectiveFeign<>(enrichedBuilder.contract, methodHandlerFactory, + enrichedBuilder.invocationHandlerFactory, + enrichedBuilder.defaultContextSupplier); return new AsyncFeign<>(feign); } } diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index d05588b8d..e7d1baada 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -29,7 +29,7 @@ import java.util.Objects; import java.util.stream.Collectors; -public abstract class BaseBuilder> { +public abstract class BaseBuilder> implements Cloneable { private final B thisB; @@ -224,33 +224,41 @@ public B addCapability(Capability capability) { return thisB; } + @SuppressWarnings("unchecked") protected B enrich() { if (capabilities.isEmpty()) { return thisB; } - getFieldsToEnrich().forEach(field -> { - field.setAccessible(true); - try { - final Object originalValue = field.get(thisB); - final Object enriched; - if (originalValue instanceof List) { - Type ownerType = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; - enriched = ((List) originalValue).stream() - .map(value -> Capability.enrich(value, (Class) ownerType, capabilities)) - .collect(Collectors.toList()); - } else { - enriched = Capability.enrich(originalValue, field.getType(), capabilities); + try { + B clone = (B) thisB.clone(); + + getFieldsToEnrich().forEach(field -> { + field.setAccessible(true); + try { + final Object originalValue = field.get(clone); + final Object enriched; + if (originalValue instanceof List) { + Type ownerType = + ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + enriched = ((List) originalValue).stream() + .map(value -> Capability.enrich(value, (Class) ownerType, capabilities)) + .collect(Collectors.toList()); + } else { + enriched = Capability.enrich(originalValue, field.getType(), capabilities); + } + field.set(clone, enriched); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException("Unable to enrich field " + field, e); + } finally { + field.setAccessible(false); } - field.set(thisB, enriched); - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException("Unable to enrich field " + field, e); - } finally { - field.setAccessible(false); - } - }); + }); - return thisB; + return clone; + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); + } } List getFieldsToEnrich() { diff --git a/core/src/main/java/feign/Feign.java b/core/src/main/java/feign/Feign.java index 59f100bdc..fe984013b 100644 --- a/core/src/main/java/feign/Feign.java +++ b/core/src/main/java/feign/Feign.java @@ -197,17 +197,23 @@ public T target(Target target) { } public Feign build() { - super.enrich(); + Builder enrichedBuilder = super.enrich(); final ResponseHandler responseHandler = - new ResponseHandler(logLevel, logger, decoder, errorDecoder, - dismiss404, closeAfterDecode, responseInterceptor); + new ResponseHandler(enrichedBuilder.logLevel, enrichedBuilder.logger, + enrichedBuilder.decoder, enrichedBuilder.errorDecoder, + enrichedBuilder.dismiss404, enrichedBuilder.closeAfterDecode, + enrichedBuilder.responseInterceptor); MethodHandler.Factory methodHandlerFactory = - new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, - responseHandler, logger, logLevel, propagationPolicy, - new RequestTemplateFactoryResolver(encoder, queryMapEncoder), - options); - return new ReflectiveFeign<>(contract, methodHandlerFactory, invocationHandlerFactory, + new SynchronousMethodHandler.Factory(enrichedBuilder.client, enrichedBuilder.retryer, + enrichedBuilder.requestInterceptors, + responseHandler, enrichedBuilder.logger, enrichedBuilder.logLevel, + enrichedBuilder.propagationPolicy, + new RequestTemplateFactoryResolver(enrichedBuilder.encoder, + enrichedBuilder.queryMapEncoder), + enrichedBuilder.options); + return new ReflectiveFeign<>(enrichedBuilder.contract, methodHandlerFactory, + enrichedBuilder.invocationHandlerFactory, () -> null); } } diff --git a/core/src/test/java/feign/BaseBuilderTest.java b/core/src/test/java/feign/BaseBuilderTest.java index 8d6cf80c3..0efc343cb 100644 --- a/core/src/test/java/feign/BaseBuilderTest.java +++ b/core/src/test/java/feign/BaseBuilderTest.java @@ -14,6 +14,7 @@ package feign; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.RETURNS_MOCKS; import java.lang.reflect.Field; @@ -46,6 +47,7 @@ private void test(BaseBuilder builder, int expectedFieldsCount) } assertTrue("Field was not enriched " + field, Mockito.mockingDetails(mockedValue) .isMock()); + assertNotSame(builder, enriched); } } diff --git a/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java b/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java index 093d069aa..5f01cddcb 100644 --- a/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java +++ b/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java @@ -158,24 +158,25 @@ public T target(Target target, C context) { @SuppressWarnings("unchecked") public CoroutineFeign build() { - super.enrich(); + CoroutineBuilder enrichedBuilder = super.enrich(); AsyncFeign asyncFeign = (AsyncFeign) AsyncFeign.builder() - .logLevel(logLevel) - .client((AsyncClient) client) - .decoder(decoder) - .errorDecoder(errorDecoder) - .contract(contract) - .retryer(retryer) - .logger(logger) - .encoder(encoder) - .queryMapEncoder(queryMapEncoder) - .options(options) - .requestInterceptors(requestInterceptors) - .responseInterceptor(responseInterceptor) - .invocationHandlerFactory(invocationHandlerFactory) - .defaultContextSupplier((AsyncContextSupplier) defaultContextSupplier) - .methodInfoResolver(methodInfoResolver) + .logLevel(enrichedBuilder.logLevel) + .client((AsyncClient) enrichedBuilder.client) + .decoder(enrichedBuilder.decoder) + .errorDecoder(enrichedBuilder.errorDecoder) + .contract(enrichedBuilder.contract) + .retryer(enrichedBuilder.retryer) + .logger(enrichedBuilder.logger) + .encoder(enrichedBuilder.encoder) + .queryMapEncoder(enrichedBuilder.queryMapEncoder) + .options(enrichedBuilder.options) + .requestInterceptors(enrichedBuilder.requestInterceptors) + .responseInterceptor(enrichedBuilder.responseInterceptor) + .invocationHandlerFactory(enrichedBuilder.invocationHandlerFactory) + .defaultContextSupplier( + (AsyncContextSupplier) enrichedBuilder.defaultContextSupplier) + .methodInfoResolver(enrichedBuilder.methodInfoResolver) .build(); return new CoroutineFeign<>(asyncFeign); } From 1b6f78fd0d723f62cde40a1d8245cb82cd79e54c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:03:21 +1200 Subject: [PATCH 2/5] build(deps): bump io.sundr:sundr-maven-plugin from 0.100.2 to 0.100.3 (#2151) Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.100.2 to 0.100.3. - [Commits](https://github.com/sundrio/sundrio/commits) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 44139c400..1b83c5f16 100644 --- a/pom.xml +++ b/pom.xml @@ -107,7 +107,7 @@ 5.1.9 0.1.1 3.1.2 - 0.100.2 + 0.100.3 file://${project.basedir}/src/config/bom.xml 2.0.1 2.16.0 From 227be3e732f7f7ef385e4f36ce303f43acdf5bc0 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 21 Aug 2023 20:21:09 +1200 Subject: [PATCH 3/5] Alternative internal builder process --- hystrix/src/main/java/feign/hystrix/HystrixFeign.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hystrix/src/main/java/feign/hystrix/HystrixFeign.java b/hystrix/src/main/java/feign/hystrix/HystrixFeign.java index 36fd7bdf5..5f277dada 100644 --- a/hystrix/src/main/java/feign/hystrix/HystrixFeign.java +++ b/hystrix/src/main/java/feign/hystrix/HystrixFeign.java @@ -148,7 +148,7 @@ public InvocationHandler create(Target target, } }); super.contract(new HystrixDelegatingContract(contract)); - return super.build(); + return super.internalBuild(); } // Covariant overrides to support chaining to new fallback method. From 99812062a0804f3b4b7835df3c9d720134421f20 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 21 Aug 2023 20:42:29 +1200 Subject: [PATCH 4/5] Alternative internal builder process --- reactive/src/main/java/feign/reactive/ReactiveFeign.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reactive/src/main/java/feign/reactive/ReactiveFeign.java b/reactive/src/main/java/feign/reactive/ReactiveFeign.java index 910d7ec39..f8e8ef86e 100644 --- a/reactive/src/main/java/feign/reactive/ReactiveFeign.java +++ b/reactive/src/main/java/feign/reactive/ReactiveFeign.java @@ -42,13 +42,13 @@ public Builder contract(Contract contract) { * @return a new Feign Instance. */ @Override - public Feign build() { + public Feign internalBuild() { if (!(this.contract instanceof ReactiveDelegatingContract)) { super.contract(new ReactiveDelegatingContract(this.contract)); } else { super.contract(this.contract); } - return super.build(); + return super.internalBuild(); } @Override From 540370d4a426cea791289167853a413d6244d11e Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 21 Aug 2023 20:49:18 +1200 Subject: [PATCH 5/5] Alternative internal builder process --- .../src/main/java/feign/reactive/ReactorFeign.java | 12 ++++++------ .../src/main/java/feign/reactive/RxJavaFeign.java | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/reactive/src/main/java/feign/reactive/ReactorFeign.java b/reactive/src/main/java/feign/reactive/ReactorFeign.java index 5d40ffaad..13435d1b4 100644 --- a/reactive/src/main/java/feign/reactive/ReactorFeign.java +++ b/reactive/src/main/java/feign/reactive/ReactorFeign.java @@ -14,13 +14,13 @@ package feign.reactive; import feign.Feign; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; +import feign.InvocationHandlerFactory; +import feign.Target; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map; -import feign.InvocationHandlerFactory; -import feign.Target; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; public class ReactorFeign extends ReactiveFeign { @@ -41,9 +41,9 @@ public static class Builder extends ReactiveFeign.Builder { } @Override - public Feign build() { + public Feign internalBuild() { super.invocationHandlerFactory(new ReactorInvocationHandlerFactory(scheduler)); - return super.build(); + return super.internalBuild(); } @Override diff --git a/reactive/src/main/java/feign/reactive/RxJavaFeign.java b/reactive/src/main/java/feign/reactive/RxJavaFeign.java index b81ac41f9..955be3541 100644 --- a/reactive/src/main/java/feign/reactive/RxJavaFeign.java +++ b/reactive/src/main/java/feign/reactive/RxJavaFeign.java @@ -13,14 +13,14 @@ */ package feign.reactive; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.util.Map; import feign.Feign; import feign.InvocationHandlerFactory; import feign.Target; import io.reactivex.Scheduler; import io.reactivex.schedulers.Schedulers; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Map; public class RxJavaFeign extends ReactiveFeign { @@ -33,9 +33,9 @@ public static class Builder extends ReactiveFeign.Builder { private Scheduler scheduler = Schedulers.trampoline(); @Override - public Feign build() { + public Feign internalBuild() { super.invocationHandlerFactory(new RxJavaInvocationHandlerFactory(scheduler)); - return super.build(); + return super.internalBuild(); } @Override