From 642d3e69611568d3ba9295e97607d6db26d41158 Mon Sep 17 00:00:00 2001 From: charliemordant Date: Sat, 29 Dec 2018 15:10:38 +0100 Subject: [PATCH 1/5] Spring data pageable support --- spring-cloud-openfeign-core/pom.xml | 35 +++++ .../openfeign/FeignAutoConfiguration.java | 8 + .../openfeign/FeignClientsConfiguration.java | 11 ++ .../openfeign/support/PageJacksonModule.java | 148 ++++++++++++++++++ .../support/PageableSpringEncoder.java | 72 +++++++++ .../EnableFeignClientsSpringDataTests.java | 56 +++++++ .../openfeign/EnableFeignClientsTests.java | 3 + .../FeignClientOverrideDefaultsTests.java | 4 +- .../cloud/openfeign/NonSpringDataTest.java | 4 + .../encoding/FeignContentEncodingTests.java | 8 + .../encoding/FeignPageableEncodingTests.java | 107 +++++++++++++ .../encoding/app/client/InvoiceClient.java | 4 + .../app/resource/InvoiceResource.java | 8 + .../support/PageableEncoderTests.java | 106 +++++++++++++ .../openfeign/support/SpringEncoderTests.java | 9 +- 15 files changed, 577 insertions(+), 6 deletions(-) create mode 100644 spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java create mode 100644 spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java create mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java create mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java create mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java create mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java diff --git a/spring-cloud-openfeign-core/pom.xml b/spring-cloud-openfeign-core/pom.xml index 3a7128b3..f78f2560 100644 --- a/spring-cloud-openfeign-core/pom.xml +++ b/spring-cloud-openfeign-core/pom.xml @@ -187,6 +187,11 @@ spring-cloud-test-support test + + org.springframework.data + spring-data-commons + true + io.projectreactor reactor-test @@ -215,6 +220,36 @@ test + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + org.springframework.cloud.openfeign.NonSpringDataTest + + + + Non-Spring-Data + + org.springframework.cloud.openfeign.NonSpringDataTest + + org.springframework.data:spring-data-commons + + + + + + + + java8plus diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java index 8b510e95..cdf6b06c 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java @@ -22,6 +22,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.TimeUnit; +import com.fasterxml.jackson.databind.Module; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.RegistryBuilder; @@ -39,8 +40,10 @@ import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory; import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory; import org.springframework.cloud.commons.httpclient.OkHttpClientFactory; import org.springframework.cloud.openfeign.support.FeignHttpClientProperties; +import org.springframework.cloud.openfeign.support.PageJacksonModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.Page; import feign.Client; import feign.Feign; @@ -207,4 +210,9 @@ public class FeignAutoConfiguration { } } + @Bean + @ConditionalOnClass(Page.class) + public Module pageJacksonModule(){ + return new PageJacksonModule(); + } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java index 090bf3f4..c7118d2e 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java @@ -24,8 +24,10 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.cloud.openfeign.support.PageableSpringEncoder; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.cloud.openfeign.support.SpringEncoder; @@ -34,6 +36,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Pageable; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; @@ -75,10 +78,18 @@ public class FeignClientsConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnMissingClass("org.springframework.data.domain.Pageable") public Encoder feignEncoder() { return new SpringEncoder(this.messageConverters); } + @Bean + @ConditionalOnClass(Pageable.class) + @ConditionalOnMissingBean + public Encoder feignEncoderPageable() { + return new PageableSpringEncoder(new SpringEncoder(this.messageConverters)); + } + @Bean @ConditionalOnMissingBean public Contract feignContract(ConversionService feignConversionService) { diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java new file mode 100644 index 00000000..1d3a2fe9 --- /dev/null +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java @@ -0,0 +1,148 @@ +package org.springframework.cloud.openfeign.support; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.springframework.data.domain.*; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + +/** + * This jackson module provides support to deserialize spring {Page} + * objects. + * + * @author Pascal Büttiker + */ +public class PageJacksonModule extends Module { + + @Override + public String getModuleName() { + return "PageJacksonModule"; + } + + @Override + public Version version() { + return new Version(0,1,0, "", null,null); + } + + @Override + public void setupModule(SetupContext context) { + context.setMixInAnnotations(Page.class, PageMixIn.class); + } + + @JsonDeserialize(as = SimplePageImpl.class) + private interface PageMixIn{ } + + + static class SimplePageImpl implements Page { + + private final Page delegate; + + public SimplePageImpl( + @JsonProperty("content") List content, + @JsonProperty("page")int number, + @JsonProperty("size") int size, + @JsonProperty("totalElements") long totalElements){ + delegate = new PageImpl<>(content, PageRequest.of(number, size), totalElements); + } + + + @JsonProperty + @Override + public int getTotalPages() { + return delegate.getTotalPages(); + } + + @JsonProperty + @Override + public long getTotalElements() { + return delegate.getTotalElements(); + } + + @JsonProperty("page") + @Override + public int getNumber() { + return delegate.getNumber(); + } + + @JsonProperty + @Override + public int getSize() { + return delegate.getSize(); + } + + @JsonProperty + @Override + public int getNumberOfElements() { + return delegate.getNumberOfElements(); + } + + @JsonProperty + @Override + public List getContent() { + return delegate.getContent(); + } + + @JsonProperty + @Override + public boolean hasContent() { + return delegate.hasContent(); + } + + @JsonIgnore + @Override + public Sort getSort() { + return delegate.getSort(); + } + + @JsonProperty + @Override + public boolean isFirst() { + return delegate.isFirst(); + } + + @JsonProperty + @Override + public boolean isLast() { + return delegate.isLast(); + } + + @JsonIgnore + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @JsonIgnore + @Override + public boolean hasPrevious() { + return delegate.hasPrevious(); + } + + @JsonIgnore + @Override + public Pageable nextPageable() { + return delegate.nextPageable(); + } + @JsonIgnore + @Override + public Pageable previousPageable() { + return delegate.previousPageable(); + } + @JsonIgnore + @Override + public Page map(Function converter) { + return delegate.map(converter); + } + + @JsonIgnore + @Override + public Iterator iterator() { + return delegate.iterator(); + } + } +} \ No newline at end of file diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java new file mode 100644 index 00000000..f2ab8a7f --- /dev/null +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java @@ -0,0 +1,72 @@ +package org.springframework.cloud.openfeign.support; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +import feign.RequestTemplate; +import feign.codec.EncodeException; +import feign.codec.Encoder; + +/** + * Provides support for encoding spring Pageable via composition. + * + * @author Pascal Büttiker + */ +public class PageableSpringEncoder implements Encoder { + + private final Encoder delegate; + + /** + * Creates a new PageableSpringEncoder with the given delegate for fallback. + * If no delegate is provided and this encoder cant handle the request, + * an EncodeException is thrown. + * @param delegate The optional delegate. + */ + public PageableSpringEncoder(Encoder delegate){ + this.delegate = delegate; + } + + @Override + public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { + + if (supports(object)) { + if (object instanceof Pageable) { + Pageable pageable = (Pageable) object; + template.query("page", pageable.getPageNumber() + ""); + template.query("size", pageable.getPageSize() + ""); + if (pageable.getSort() != null) { + applySort(template, pageable.getSort()); + } + } else if (object instanceof Sort) { + Sort sort = (Sort)object; + applySort(template, sort); + } + } else { + if (delegate != null) { + delegate.encode(object, bodyType, template); + } else { + throw new EncodeException("PageableSpringEncoder does not support the given object " + object.getClass() + " and no delegate was provided for fallback!"); + } + } + } + + private void applySort(RequestTemplate template, Sort sort) { + Collection existingSorts = template.queries().get("sort"); + List sortQueries = existingSorts != null ? new ArrayList<>(existingSorts) : new ArrayList<>(); + for (Sort.Order order : sort) { + sortQueries.add(order.getProperty() + "," + order.getDirection()); + } + if(!sortQueries.isEmpty()) { + template.query("sort", sortQueries); + } + } + + protected boolean supports(Object object) { + return object instanceof Pageable || object instanceof Sort; + } +} \ No newline at end of file diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java new file mode 100644 index 00000000..e408c15f --- /dev/null +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.openfeign; + +import feign.codec.Encoder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; +import org.springframework.cloud.openfeign.support.PageableSpringEncoder; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Spencer Gibb + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = EnableFeignClientsSpringDataTests.PlainConfiguration.class) +@DirtiesContext +public class EnableFeignClientsSpringDataTests { + + @Autowired + private FeignContext feignContext; + + @Test + public void encoderDefaultCorrect() { + + PageableSpringEncoder.class.cast(this.feignContext.getInstance("foo", Encoder.class)); + } + + @Configuration + @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, + FeignAutoConfiguration.class }) + protected static class PlainConfiguration { + } + +} diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java index 75cfeee3..af6b9a51 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java @@ -18,6 +18,7 @@ package org.springframework.cloud.openfeign; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -44,6 +45,7 @@ import feign.slf4j.Slf4jLogger; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = EnableFeignClientsTests.PlainConfiguration.class) @DirtiesContext +@Category({NonSpringDataTest.class}) public class EnableFeignClientsTests { @Autowired @@ -57,6 +59,7 @@ public class EnableFeignClientsTests { @Test public void encoderDefaultCorrect() { + SpringEncoder.class.cast(this.feignContext.getInstance("foo", Encoder.class)); } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java index 844bda57..83b2c8e5 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientOverrideDefaultsTests.java @@ -23,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; -import org.springframework.cloud.openfeign.support.SpringEncoder; +import org.springframework.cloud.openfeign.support.PageableSpringEncoder; import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -85,7 +85,7 @@ public class FeignClientOverrideDefaultsTests { @Test public void overrideEncoder() { Encoder.Default.class.cast(this.context.getInstance("foo", Encoder.class)); - SpringEncoder.class.cast(this.context.getInstance("bar", Encoder.class)); + PageableSpringEncoder.class.cast(this.context.getInstance("bar", Encoder.class)); } @Test diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java new file mode 100644 index 00000000..b2af3bfb --- /dev/null +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java @@ -0,0 +1,4 @@ +package org.springframework.cloud.openfeign; + +public interface NonSpringDataTest { +} diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java index 748b0e6e..c85fad45 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -30,6 +31,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.NonSpringDataTest; import org.springframework.cloud.openfeign.encoding.app.client.InvoiceClient; import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; import org.springframework.cloud.netflix.ribbon.RibbonClient; @@ -37,6 +39,11 @@ import org.springframework.cloud.openfeign.test.NoSecurityConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -55,6 +62,7 @@ import com.netflix.loadbalancer.Server; "hystrix.command.default.execution.isolation.strategy=SEMAPHORE", "ribbon.OkToRetryOnAllOperations=false" }) @RunWith(SpringJUnit4ClassRunner.class) +@Category({NonSpringDataTest.class}) public class FeignContentEncodingTests { @Autowired diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java new file mode 100644 index 00000000..c5dbffcc --- /dev/null +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java @@ -0,0 +1,107 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.openfeign.encoding; + +import com.netflix.loadbalancer.BaseLoadBalancer; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.netflix.ribbon.RibbonClient; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.encoding.app.client.InvoiceClient; +import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; +import org.springframework.cloud.openfeign.test.NoSecurityConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.config.EnableSpringDataWebSupport; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Tests the pagination encoding. + * + * @author Charlie Mordant. + */ +@SpringBootTest(classes = FeignPageableEncodingTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = { + "feign.compression.request.enabled=true", + "hystrix.command.default.execution.isolation.strategy=SEMAPHORE", + "ribbon.OkToRetryOnAllOperations=false" }) +@RunWith(SpringJUnit4ClassRunner.class) +public class FeignPageableEncodingTests { + + @Autowired + private InvoiceClient invoiceClient; + + @Test + public void testPageable() { + + // given + Pageable pageable = PageRequest.of(0,10, Sort.Direction.ASC, "sortProperty"); + + // when + final ResponseEntity> response = this.invoiceClient + .getInvoicesPaged(pageable); + + // then + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(pageable.getPageSize(), response.getBody().getSize()); + + } + + @EnableFeignClients(clients = InvoiceClient.class) + @RibbonClient(name = "local", configuration = LocalRibbonClientConfiguration.class) + @SpringBootApplication(scanBasePackages = "org.springframework.cloud.openfeign.encoding.app") + @EnableSpringDataWebSupport + @Import(NoSecurityConfiguration.class) + public static class Application { + } + + @Configuration + static class LocalRibbonClientConfiguration { + + @Value("${local.server.port}") + private int port = 0; + + @Bean + public ILoadBalancer ribbonLoadBalancer() { + BaseLoadBalancer balancer = new BaseLoadBalancer(); + balancer.setServersList( + Collections.singletonList(new Server("localhost", this.port))); + return balancer; + } + } + +} \ No newline at end of file diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java index 466d2669..2357edfa 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java @@ -20,6 +20,7 @@ import java.util.List; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; +import org.springframework.data.domain.Page; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -33,6 +34,9 @@ import org.springframework.web.bind.annotation.RequestMethod; @FeignClient("local") public interface InvoiceClient { + @RequestMapping(value = "invoicesPaged", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + ResponseEntity> getInvoicesPaged(org.springframework.data.domain.Pageable pageable); + @RequestMapping(value = "invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) ResponseEntity> getInvoices(); diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java index d6030d9b..2ea31412 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java @@ -17,6 +17,8 @@ package org.springframework.cloud.openfeign.encoding.app.resource; import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; @@ -50,6 +52,12 @@ public class InvoiceResource { return ResponseEntity.ok(invoices); } + @RequestMapping(value = "invoicesPaged", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> getInvoicesPaged(org.springframework.data.domain.Pageable pageable) { + Page page = new PageImpl<>(createInvoiceList(pageable.getPageSize()), pageable, 100); + return ResponseEntity.ok(page); + } + private List createInvoiceList(int count) { final List invoices = new ArrayList<>(); for (int ind = 0; ind < count; ind++) { diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java new file mode 100644 index 00000000..7a0861b1 --- /dev/null +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java @@ -0,0 +1,106 @@ +package org.springframework.cloud.openfeign.support; + +import feign.RequestTemplate; +import feign.codec.Encoder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.openfeign.FeignContext; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * Tests the pagination encoding and sorting. + * + * @author Charlie Mordant. + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = SpringEncoderTests.Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = { + "spring.application.name=springencodertest", "spring.jmx.enabled=false" }) +@DirtiesContext +public class PageableEncoderTests { + + public static final int PAGE = 1; + public static final int SIZE = 10; + public static final String SORT_2 = "sort2"; + public static final String SORT_1 = "sort1"; + @Autowired + private FeignContext context; + + @Test + public void testPaginationAndSortingRequest() { + Encoder encoder = this.context.getInstance("foo", Encoder.class); + assertThat(encoder, is(notNullValue())); + RequestTemplate request = new RequestTemplate(); + + encoder.encode(createPageAndSortRequest(), null, request); + + assertThat("Request queries shall contain three entries", + request.queries().size(), + equalTo(3)); + assertThat("Request page shall contain page", + request.queries().get("page"), + hasItem(String.valueOf(PAGE))); + assertThat("Request size shall contain size", + request.queries().get("size"), + hasItem(String.valueOf(SIZE))); + assertThat("Request sort size shall contain sort entries", + request.queries().get("sort").size(), + equalTo(2)); + } + + private Pageable createPageAndSortRequest() { + return PageRequest.of(PAGE, SIZE, Sort.Direction.ASC, SORT_1, SORT_2); + } + + @Test + public void testPaginationRequest() { + Encoder encoder = this.context.getInstance("foo", Encoder.class); + assertThat(encoder, is(notNullValue())); + RequestTemplate request = new RequestTemplate(); + encoder.encode(createPageAndRequest(), null, request); + assertThat("Request queries shall contain three entries", + request.queries().size(), + equalTo(2)); + assertThat("Request page shall contain page", + request.queries().get("page"), + hasItem(String.valueOf(PAGE))); + assertThat("Request size shall contain size", + request.queries().get("size"), + hasItem(String.valueOf(SIZE))); + assertThat("Request sort size shall contain sort entries", + request.queries().containsKey("sort"), + equalTo(false)); + } + + private Pageable createPageAndRequest() { + return PageRequest.of(PAGE, SIZE); + } + + @Test + public void testSortingRequest() { + Encoder encoder = this.context.getInstance("foo", Encoder.class); + assertThat(encoder, is(notNullValue())); + RequestTemplate request = new RequestTemplate(); + + encoder.encode(createSort(), null, request); + + assertThat("Request queries shall contain three entries", + request.queries().size(), + equalTo(1)); + assertThat("Request sort size shall contain sort entries", + request.queries().get("sort").size(), + equalTo(2)); + } + + private Sort createSort() { + return Sort.by(SORT_1, SORT_2).ascending(); + } +} diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java index 72a595a4..21f8356e 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java @@ -25,6 +25,7 @@ import java.util.List; import feign.RequestTemplate; import feign.codec.EncodeException; +import feign.codec.Encoder; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; @@ -78,7 +79,7 @@ public class SpringEncoderTests { @Test public void testCustomHttpMessageConverter() { - SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class); + Encoder encoder = this.context.getInstance("foo", Encoder.class); assertThat(encoder, is(notNullValue())); RequestTemplate request = new RequestTemplate(); @@ -97,7 +98,7 @@ public class SpringEncoderTests { @Test public void testBinaryData() { - SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class); + Encoder encoder = this.context.getInstance("foo", Encoder.class); assertThat(encoder, is(notNullValue())); RequestTemplate request = new RequestTemplate(); @@ -110,7 +111,7 @@ public class SpringEncoderTests { @Test(expected = EncodeException.class) public void testMultipartFile1() { - SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class); + Encoder encoder = this.context.getInstance("foo", Encoder.class); assertThat(encoder, is(notNullValue())); RequestTemplate request = new RequestTemplate(); @@ -122,7 +123,7 @@ public class SpringEncoderTests { @Test public void testMultipartFile2() { - SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class); + Encoder encoder = this.context.getInstance("foo", Encoder.class); assertThat(encoder, is(notNullValue())); RequestTemplate request = new RequestTemplate(); request = request.header("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE); From 23ec2a1c4333045e93bc936e554c08050c80c073 Mon Sep 17 00:00:00 2001 From: charliemordant Date: Mon, 7 Jan 2019 17:20:44 +0100 Subject: [PATCH 2/5] License headers --- .../openfeign/support/PageJacksonModule.java | 16 +++++++++++++ .../support/PageableSpringEncoder.java | 16 +++++++++++++ .../support/PageableEncoderTests.java | 24 ++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java index 1d3a2fe9..9012173c 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java @@ -1,3 +1,19 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.openfeign.support; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java index f2ab8a7f..3077f529 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java @@ -1,3 +1,19 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.openfeign.support; import java.lang.reflect.Type; diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java index 7a0861b1..cf1e819a 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java @@ -1,3 +1,21 @@ +/* + * + * * Copyright 2013-2016 the original author or authors. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + package org.springframework.cloud.openfeign.support; import feign.RequestTemplate; @@ -13,9 +31,13 @@ import org.springframework.data.domain.Sort; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; + /** * Tests the pagination encoding and sorting. * From 505a83e6a4ff3500cb7230b0e8f0da9d7dc13e75 Mon Sep 17 00:00:00 2001 From: charliemordant Date: Mon, 28 Jan 2019 13:05:26 +0100 Subject: [PATCH 3/5] registers PageJacksonModule in FeignClientConfiguration --- spring-cloud-openfeign-core/pom.xml | 30 ----------- .../cloud/openfeign/EnableFeignClients.java | 8 +-- .../openfeign/FeignAutoConfiguration.java | 9 ---- .../openfeign/FeignClientsConfiguration.java | 13 +++-- .../openfeign/EnableFeignClientsTests.java | 50 ++++++++++++------- .../cloud/openfeign/NonSpringDataTest.java | 4 -- .../encoding/FeignContentEncodingTests.java | 8 --- .../encoding/FeignPageableEncodingTests.java | 3 +- 8 files changed, 45 insertions(+), 80 deletions(-) delete mode 100644 spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java diff --git a/spring-cloud-openfeign-core/pom.xml b/spring-cloud-openfeign-core/pom.xml index 78476ceb..263b214d 100644 --- a/spring-cloud-openfeign-core/pom.xml +++ b/spring-cloud-openfeign-core/pom.xml @@ -220,36 +220,6 @@ test - - - - org.apache.maven.plugins - maven-surefire-plugin - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - org.springframework.cloud.openfeign.NonSpringDataTest - - - - Non-Spring-Data - - org.springframework.cloud.openfeign.NonSpringDataTest - - org.springframework.data:spring-data-commons - - - - - - - - java8plus diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java index dfed4f63..35ca3f23 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java @@ -25,10 +25,10 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Import; /** - * Scans for interfaces that declare they are feign clients (via {@link FeignClient - * @FeignClient}). Configures component scanning directives for use with - * {@link org.springframework.context.annotation.Configuration - * @Configuration} classes. + * Scans for interfaces that declare they are feign clients (via {@link org.springframework.cloud.openfeign.FeignClient} + * @FeignClient). Configures component scanning directives for use with + * {@link org.springframework.context.annotation.Configuration} + * @Configuration classes. * * @author Spencer Gibb * @author Dave Syer diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java index cdf6b06c..337643d9 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java @@ -22,7 +22,6 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.TimeUnit; -import com.fasterxml.jackson.databind.Module; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.RegistryBuilder; @@ -40,10 +39,8 @@ import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory; import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory; import org.springframework.cloud.commons.httpclient.OkHttpClientFactory; import org.springframework.cloud.openfeign.support.FeignHttpClientProperties; -import org.springframework.cloud.openfeign.support.PageJacksonModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.domain.Page; import feign.Client; import feign.Feign; @@ -209,10 +206,4 @@ public class FeignAutoConfiguration { return new OkHttpClient(client); } } - - @Bean - @ConditionalOnClass(Page.class) - public Module pageJacksonModule(){ - return new PageJacksonModule(); - } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java index c7118d2e..6f737499 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java @@ -20,6 +20,7 @@ package org.springframework.cloud.openfeign; import java.util.ArrayList; import java.util.List; +import com.fasterxml.jackson.databind.Module; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -27,15 +28,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; -import org.springframework.cloud.openfeign.support.PageableSpringEncoder; -import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; -import org.springframework.cloud.openfeign.support.SpringDecoder; -import org.springframework.cloud.openfeign.support.SpringEncoder; -import org.springframework.cloud.openfeign.support.SpringMvcContract; +import org.springframework.cloud.openfeign.support.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; @@ -136,4 +134,9 @@ public class FeignClientsConfiguration { return new DefaultFeignLoggerFactory(logger); } + @Bean + @ConditionalOnClass(Page.class) + public Module pageJacksonModule(){ + return new PageJacksonModule(); + } } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java index af6b9a51..4a96d7b7 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java @@ -17,19 +17,20 @@ package org.springframework.cloud.openfeign; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.cloud.openfeign.support.SpringMvcContract; +import org.springframework.cloud.test.ClassPathExclusions; +import org.springframework.cloud.test.ModifiedClassPathRunner; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import feign.Contract; import feign.Feign; @@ -42,46 +43,57 @@ import feign.slf4j.Slf4jLogger; /** * @author Spencer Gibb */ -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = EnableFeignClientsTests.PlainConfiguration.class) -@DirtiesContext -@Category({NonSpringDataTest.class}) +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions({"spring-data-commons-*.jar"}) public class EnableFeignClientsTests { - @Autowired - private FeignContext feignContext; + private ConfigurableApplicationContext context; + + @Before + public void setUp() { + context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties("debug=true", "feign.httpclient.enabled=false") + .sources(EnableFeignClientsTests.PlainConfiguration.class).run(); + } + + @After + public void tearDown() { + if(context != null) { + context.close(); + } + } + @Test public void decoderDefaultCorrect() { OptionalDecoder.class - .cast(this.feignContext.getInstance("foo", Decoder.class)); + .cast(this.context.getBeansOfType(Decoder.class).get(0)); } @Test public void encoderDefaultCorrect() { - - SpringEncoder.class.cast(this.feignContext.getInstance("foo", Encoder.class)); + SpringEncoder.class.cast(this.context.getBeansOfType(Encoder.class).get(0)); } @Test public void loggerDefaultCorrect() { - Slf4jLogger.class.cast(this.feignContext.getInstance("foo", Logger.class)); + Slf4jLogger.class.cast(this.context.getBeansOfType( Logger.class).get(0)); } @Test public void contractDefaultCorrect() { SpringMvcContract.class - .cast(this.feignContext.getInstance("foo", Contract.class)); + .cast(this.context.getBeansOfType(Contract.class).get(0)); } @Test public void builderDefaultCorrect() { Feign.Builder.class - .cast(this.feignContext.getInstance("foo", Feign.Builder.class)); + .cast(this.context.getBeansOfType(Feign.Builder.class).get(0)); } @Configuration - @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, + @Import({ ArchaiusAutoConfiguration.class, FeignAutoConfiguration.class }) protected static class PlainConfiguration { } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java deleted file mode 100644 index b2af3bfb..00000000 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/NonSpringDataTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.springframework.cloud.openfeign; - -public interface NonSpringDataTest { -} diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java index c85fad45..748b0e6e 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignContentEncodingTests.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.List; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -31,7 +30,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.cloud.openfeign.NonSpringDataTest; import org.springframework.cloud.openfeign.encoding.app.client.InvoiceClient; import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; import org.springframework.cloud.netflix.ribbon.RibbonClient; @@ -39,11 +37,6 @@ import org.springframework.cloud.openfeign.test.NoSecurityConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -62,7 +55,6 @@ import com.netflix.loadbalancer.Server; "hystrix.command.default.execution.isolation.strategy=SEMAPHORE", "ribbon.OkToRetryOnAllOperations=false" }) @RunWith(SpringJUnit4ClassRunner.class) -@Category({NonSpringDataTest.class}) public class FeignContentEncodingTests { @Autowired diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java index c5dbffcc..08c93aca 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java @@ -28,6 +28,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignClientsConfiguration; import org.springframework.cloud.openfeign.encoding.app.client.InvoiceClient; import org.springframework.cloud.openfeign.encoding.app.domain.Invoice; import org.springframework.cloud.openfeign.test.NoSecurityConfiguration; @@ -85,7 +86,7 @@ public class FeignPageableEncodingTests { @RibbonClient(name = "local", configuration = LocalRibbonClientConfiguration.class) @SpringBootApplication(scanBasePackages = "org.springframework.cloud.openfeign.encoding.app") @EnableSpringDataWebSupport - @Import(NoSecurityConfiguration.class) + @Import({NoSecurityConfiguration.class, FeignClientsConfiguration.class}) public static class Application { } From 6e0e63644ba34193f03c2cd74391cac73b9bfdb4 Mon Sep 17 00:00:00 2001 From: charliemordant Date: Sun, 10 Feb 2019 18:53:59 +0100 Subject: [PATCH 4/5] checkstyle rules applied to pageable support --- .../cloud/openfeign/EnableFeignClients.java | 5 +- .../openfeign/FeignAutoConfiguration.java | 1 + .../openfeign/FeignClientsConfiguration.java | 1 + .../openfeign/support/PageJacksonModule.java | 229 +++++++++--------- .../support/PageableSpringEncoder.java | 105 ++++---- .../EnableFeignClientsSpringDataTests.java | 8 +- .../openfeign/EnableFeignClientsTests.java | 33 ++- .../encoding/FeignPageableEncodingTests.java | 27 ++- .../encoding/app/client/InvoiceClient.java | 3 +- .../app/resource/InvoiceResource.java | 6 +- .../support/PageableEncoderTests.java | 163 ++++++------- src/checkstyle/checkstyle-suppressions.xml | 3 +- 12 files changed, 297 insertions(+), 287 deletions(-) diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java index b661f6d0..bd6c790b 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/EnableFeignClients.java @@ -25,8 +25,9 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Import; /** - * Scans for interfaces that declare they are feign clients (via {@link org.springframework.cloud.openfeign.FeignClient} - * @FeignClient). Configures component scanning directives for use with + * Scans for interfaces that declare they are feign clients (via + * {@link org.springframework.cloud.openfeign.FeignClient} @FeignClient). + * Configures component scanning directives for use with * {@link org.springframework.context.annotation.Configuration} * @Configuration classes. * diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java index 056a00b8..6e71b28f 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java @@ -218,4 +218,5 @@ public class FeignAutoConfiguration { } } + } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java index 88d7fdd6..430dbd20 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsConfiguration.java @@ -145,4 +145,5 @@ public class FeignClientsConfiguration { } } + } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java index 9012173c..166b6103 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java @@ -16,149 +16,156 @@ package org.springframework.cloud.openfeign.support; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.springframework.data.domain.*; -import java.util.Iterator; -import java.util.List; -import java.util.function.Function; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; /** - * This jackson module provides support to deserialize spring {Page} - * objects. + * This jackson module provides support to deserialize spring {@link Page} objects. * * @author Pascal Büttiker */ public class PageJacksonModule extends Module { - @Override - public String getModuleName() { - return "PageJacksonModule"; - } + @Override + public String getModuleName() { + return "PageJacksonModule"; + } - @Override - public Version version() { - return new Version(0,1,0, "", null,null); - } + @Override + public Version version() { + return new Version(0, 1, 0, "", null, null); + } - @Override - public void setupModule(SetupContext context) { - context.setMixInAnnotations(Page.class, PageMixIn.class); - } + @Override + public void setupModule(SetupContext context) { + context.setMixInAnnotations(Page.class, PageMixIn.class); + } - @JsonDeserialize(as = SimplePageImpl.class) - private interface PageMixIn{ } + @JsonDeserialize(as = SimplePageImpl.class) + private interface PageMixIn { + } - static class SimplePageImpl implements Page { + static class SimplePageImpl implements Page { - private final Page delegate; + private final Page delegate; - public SimplePageImpl( - @JsonProperty("content") List content, - @JsonProperty("page")int number, - @JsonProperty("size") int size, - @JsonProperty("totalElements") long totalElements){ - delegate = new PageImpl<>(content, PageRequest.of(number, size), totalElements); - } + SimplePageImpl(@JsonProperty("content") List content, + @JsonProperty("page") int number, @JsonProperty("size") int size, + @JsonProperty("totalElements") long totalElements) { + delegate = new PageImpl<>(content, PageRequest.of(number, size), + totalElements); + } + @JsonProperty + @Override + public int getTotalPages() { + return delegate.getTotalPages(); + } - @JsonProperty - @Override - public int getTotalPages() { - return delegate.getTotalPages(); - } + @JsonProperty + @Override + public long getTotalElements() { + return delegate.getTotalElements(); + } - @JsonProperty - @Override - public long getTotalElements() { - return delegate.getTotalElements(); - } + @JsonProperty("page") + @Override + public int getNumber() { + return delegate.getNumber(); + } - @JsonProperty("page") - @Override - public int getNumber() { - return delegate.getNumber(); - } + @JsonProperty + @Override + public int getSize() { + return delegate.getSize(); + } - @JsonProperty - @Override - public int getSize() { - return delegate.getSize(); - } + @JsonProperty + @Override + public int getNumberOfElements() { + return delegate.getNumberOfElements(); + } - @JsonProperty - @Override - public int getNumberOfElements() { - return delegate.getNumberOfElements(); - } + @JsonProperty + @Override + public List getContent() { + return delegate.getContent(); + } - @JsonProperty - @Override - public List getContent() { - return delegate.getContent(); - } + @JsonProperty + @Override + public boolean hasContent() { + return delegate.hasContent(); + } - @JsonProperty - @Override - public boolean hasContent() { - return delegate.hasContent(); - } + @JsonIgnore + @Override + public Sort getSort() { + return delegate.getSort(); + } - @JsonIgnore - @Override - public Sort getSort() { - return delegate.getSort(); - } + @JsonProperty + @Override + public boolean isFirst() { + return delegate.isFirst(); + } - @JsonProperty - @Override - public boolean isFirst() { - return delegate.isFirst(); - } + @JsonProperty + @Override + public boolean isLast() { + return delegate.isLast(); + } - @JsonProperty - @Override - public boolean isLast() { - return delegate.isLast(); - } + @JsonIgnore + @Override + public boolean hasNext() { + return delegate.hasNext(); + } - @JsonIgnore - @Override - public boolean hasNext() { - return delegate.hasNext(); - } + @JsonIgnore + @Override + public boolean hasPrevious() { + return delegate.hasPrevious(); + } - @JsonIgnore - @Override - public boolean hasPrevious() { - return delegate.hasPrevious(); - } + @JsonIgnore + @Override + public Pageable nextPageable() { + return delegate.nextPageable(); + } - @JsonIgnore - @Override - public Pageable nextPageable() { - return delegate.nextPageable(); - } - @JsonIgnore - @Override - public Pageable previousPageable() { - return delegate.previousPageable(); - } - @JsonIgnore - @Override - public Page map(Function converter) { - return delegate.map(converter); - } + @JsonIgnore + @Override + public Pageable previousPageable() { + return delegate.previousPageable(); + } - @JsonIgnore - @Override - public Iterator iterator() { - return delegate.iterator(); - } - } -} \ No newline at end of file + @JsonIgnore + @Override + public Page map(Function converter) { + return delegate.map(converter); + } + + @JsonIgnore + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + } + +} diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java index fbbd4b02..ead1816b 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringEncoder.java @@ -21,13 +21,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; - import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + /** * Provides support for encoding spring Pageable via composition. * @@ -35,54 +35,63 @@ import feign.codec.Encoder; */ public class PageableSpringEncoder implements Encoder { - private final Encoder delegate; + private final Encoder delegate; - /** - * Creates a new PageableSpringEncoder with the given delegate for fallback. - * If no delegate is provided and this encoder cant handle the request, - * an EncodeException is thrown. - * @param delegate The optional delegate. - */ - public PageableSpringEncoder(Encoder delegate){ - this.delegate = delegate; - } + /** + * Creates a new PageableSpringEncoder with the given delegate for fallback. If no + * delegate is provided and this encoder cant handle the request, an EncodeException + * is thrown. + * @param delegate The optional delegate. + */ + public PageableSpringEncoder(Encoder delegate) { + this.delegate = delegate; + } - @Override - public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { + @Override + public void encode(Object object, Type bodyType, RequestTemplate template) + throws EncodeException { - if (supports(object)) { - if (object instanceof Pageable) { - Pageable pageable = (Pageable) object; - template.query("page", pageable.getPageNumber() + ""); - template.query("size", pageable.getPageSize() + ""); - if (pageable.getSort() != null) { - applySort(template, pageable.getSort()); - } - } else if (object instanceof Sort) { - Sort sort = (Sort)object; - applySort(template, sort); - } - } else { - if (delegate != null) { - delegate.encode(object, bodyType, template); - } else { - throw new EncodeException("PageableSpringEncoder does not support the given object " + object.getClass() + " and no delegate was provided for fallback!"); - } - } - } + if (supports(object)) { + if (object instanceof Pageable) { + Pageable pageable = (Pageable) object; + template.query("page", pageable.getPageNumber() + ""); + template.query("size", pageable.getPageSize() + ""); + if (pageable.getSort() != null) { + applySort(template, pageable.getSort()); + } + } + else if (object instanceof Sort) { + Sort sort = (Sort) object; + applySort(template, sort); + } + } + else { + if (delegate != null) { + delegate.encode(object, bodyType, template); + } + else { + throw new EncodeException( + "PageableSpringEncoder does not support the given object " + + object.getClass() + + " and no delegate was provided for fallback!"); + } + } + } - private void applySort(RequestTemplate template, Sort sort) { - Collection existingSorts = template.queries().get("sort"); - List sortQueries = existingSorts != null ? new ArrayList<>(existingSorts) : new ArrayList<>(); - for (Sort.Order order : sort) { - sortQueries.add(order.getProperty() + "," + order.getDirection()); - } - if(!sortQueries.isEmpty()) { - template.query("sort", sortQueries); - } - } + private void applySort(RequestTemplate template, Sort sort) { + Collection existingSorts = template.queries().get("sort"); + List sortQueries = existingSorts != null ? new ArrayList<>(existingSorts) + : new ArrayList<>(); + for (Sort.Order order : sort) { + sortQueries.add(order.getProperty() + "," + order.getDirection()); + } + if (!sortQueries.isEmpty()) { + template.query("sort", sortQueries); + } + } + + protected boolean supports(Object object) { + return object instanceof Pageable || object instanceof Sort; + } - protected boolean supports(Object object) { - return object instanceof Pageable || object instanceof Sort; - } } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java index e408c15f..d749c069 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsSpringDataTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,7 +12,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package org.springframework.cloud.openfeign; @@ -20,6 +19,7 @@ package org.springframework.cloud.openfeign; import feign.codec.Encoder; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -44,13 +44,15 @@ public class EnableFeignClientsSpringDataTests { @Test public void encoderDefaultCorrect() { - PageableSpringEncoder.class.cast(this.feignContext.getInstance("foo", Encoder.class)); + PageableSpringEncoder.class + .cast(this.feignContext.getInstance("foo", Encoder.class)); } @Configuration @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, FeignAutoConfiguration.class }) protected static class PlainConfiguration { + } } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java index d97e63ac..1164aaf7 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/EnableFeignClientsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2019 the original author or authors. + * Copyright 2013-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,6 @@ package org.springframework.cloud.openfeign; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.builder.SpringApplicationBuilder; import feign.Contract; import feign.Feign; import feign.Logger; @@ -29,7 +23,13 @@ import feign.codec.Decoder; import feign.codec.Encoder; import feign.optionals.OptionalDecoder; import feign.slf4j.Slf4jLogger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.cloud.openfeign.support.SpringMvcContract; @@ -43,7 +43,7 @@ import org.springframework.context.annotation.Import; * @author Spencer Gibb */ @RunWith(ModifiedClassPathRunner.class) -@ClassPathExclusions({"spring-data-commons-*.jar"}) +@ClassPathExclusions({ "spring-data-commons-*.jar" }) public class EnableFeignClientsTests { private ConfigurableApplicationContext context; @@ -57,16 +57,14 @@ public class EnableFeignClientsTests { @After public void tearDown() { - if(context != null) { + if (context != null) { context.close(); } } - @Test public void decoderDefaultCorrect() { - OptionalDecoder.class - .cast(this.context.getBeansOfType(Decoder.class).get(0)); + OptionalDecoder.class.cast(this.context.getBeansOfType(Decoder.class).get(0)); } @Test @@ -76,24 +74,21 @@ public class EnableFeignClientsTests { @Test public void loggerDefaultCorrect() { - Slf4jLogger.class.cast(this.context.getBeansOfType( Logger.class).get(0)); + Slf4jLogger.class.cast(this.context.getBeansOfType(Logger.class).get(0)); } @Test public void contractDefaultCorrect() { - SpringMvcContract.class - .cast(this.context.getBeansOfType(Contract.class).get(0)); + SpringMvcContract.class.cast(this.context.getBeansOfType(Contract.class).get(0)); } @Test public void builderDefaultCorrect() { - Feign.Builder.class - .cast(this.context.getBeansOfType(Feign.Builder.class).get(0)); + Feign.Builder.class.cast(this.context.getBeansOfType(Feign.Builder.class).get(0)); } @Configuration - @Import({ ArchaiusAutoConfiguration.class, - FeignAutoConfiguration.class }) + @Import({ ArchaiusAutoConfiguration.class, FeignAutoConfiguration.class }) protected static class PlainConfiguration { } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java index 08c93aca..ff1fef76 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java @@ -16,11 +16,14 @@ package org.springframework.cloud.openfeign.encoding; +import java.util.Collections; + import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -44,17 +47,15 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.Collections; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; /** * Tests the pagination encoding. * * @author Charlie Mordant. */ -@SpringBootTest(classes = FeignPageableEncodingTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = { +@SpringBootTest(classes = FeignPageableEncodingTests.Application.class, + webEnvironment = WebEnvironment.RANDOM_PORT, value = { "feign.compression.request.enabled=true", "hystrix.command.default.execution.isolation.strategy=SEMAPHORE", "ribbon.OkToRetryOnAllOperations=false" }) @@ -68,17 +69,17 @@ public class FeignPageableEncodingTests { public void testPageable() { // given - Pageable pageable = PageRequest.of(0,10, Sort.Direction.ASC, "sortProperty"); + Pageable pageable = PageRequest.of(0, 10, Sort.Direction.ASC, "sortProperty"); // when final ResponseEntity> response = this.invoiceClient .getInvoicesPaged(pageable); // then - assertNotNull(response); - assertEquals(HttpStatus.OK, response.getStatusCode()); - assertNotNull(response.getBody()); - assertEquals(pageable.getPageSize(), response.getBody().getSize()); + assertThat(response).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(pageable.getPageSize()).isEqualTo(response.getBody().getSize()); } @@ -86,8 +87,9 @@ public class FeignPageableEncodingTests { @RibbonClient(name = "local", configuration = LocalRibbonClientConfiguration.class) @SpringBootApplication(scanBasePackages = "org.springframework.cloud.openfeign.encoding.app") @EnableSpringDataWebSupport - @Import({NoSecurityConfiguration.class, FeignClientsConfiguration.class}) + @Import({ NoSecurityConfiguration.class, FeignClientsConfiguration.class }) public static class Application { + } @Configuration @@ -103,6 +105,7 @@ public class FeignPageableEncodingTests { Collections.singletonList(new Server("localhost", this.port))); return balancer; } + } -} \ No newline at end of file +} diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java index aef5ed16..47076d2a 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/client/InvoiceClient.java @@ -35,7 +35,8 @@ import org.springframework.web.bind.annotation.RequestMethod; public interface InvoiceClient { @RequestMapping(value = "invoicesPaged", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - ResponseEntity> getInvoicesPaged(org.springframework.data.domain.Pageable pageable); + ResponseEntity> getInvoicesPaged( + org.springframework.data.domain.Pageable pageable); @RequestMapping(value = "invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) ResponseEntity> getInvoices(); diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java index 61c907e9..a5e3176e 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/app/resource/InvoiceResource.java @@ -52,8 +52,10 @@ public class InvoiceResource { } @RequestMapping(value = "invoicesPaged", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> getInvoicesPaged(org.springframework.data.domain.Pageable pageable) { - Page page = new PageImpl<>(createInvoiceList(pageable.getPageSize()), pageable, 100); + public ResponseEntity> getInvoicesPaged( + org.springframework.data.domain.Pageable pageable) { + Page page = new PageImpl<>(createInvoiceList(pageable.getPageSize()), + pageable, 100); return ResponseEntity.ok(page); } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java index 95f4b6bf..650500bf 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java @@ -1,19 +1,17 @@ /* + * Copyright 2013-2019 the original author or authors. * - * * Copyright 2013-2016 the original author or authors. - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.springframework.cloud.openfeign.support; @@ -22,6 +20,7 @@ import feign.RequestTemplate; import feign.codec.Encoder; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.openfeign.FeignContext; @@ -31,12 +30,7 @@ import org.springframework.data.domain.Sort; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - +import static org.assertj.core.api.Assertions.assertThat; /** * Tests the pagination encoding and sorting. @@ -44,85 +38,78 @@ import static org.junit.Assert.assertThat; * @author Charlie Mordant. */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = SpringEncoderTests.Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = { - "spring.application.name=springencodertest", "spring.jmx.enabled=false" }) +@SpringBootTest(classes = SpringEncoderTests.Application.class, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = { + "spring.application.name=springencodertest", "spring.jmx.enabled=false" }) @DirtiesContext public class PageableEncoderTests { - public static final int PAGE = 1; - public static final int SIZE = 10; - public static final String SORT_2 = "sort2"; - public static final String SORT_1 = "sort1"; - @Autowired - private FeignContext context; + public static final int PAGE = 1; - @Test - public void testPaginationAndSortingRequest() { - Encoder encoder = this.context.getInstance("foo", Encoder.class); - assertThat(encoder, is(notNullValue())); - RequestTemplate request = new RequestTemplate(); + public static final int SIZE = 10; - encoder.encode(createPageAndSortRequest(), null, request); + public static final String SORT_2 = "sort2"; - assertThat("Request queries shall contain three entries", - request.queries().size(), - equalTo(3)); - assertThat("Request page shall contain page", - request.queries().get("page"), - hasItem(String.valueOf(PAGE))); - assertThat("Request size shall contain size", - request.queries().get("size"), - hasItem(String.valueOf(SIZE))); - assertThat("Request sort size shall contain sort entries", - request.queries().get("sort").size(), - equalTo(2)); - } + public static final String SORT_1 = "sort1"; - private Pageable createPageAndSortRequest() { - return PageRequest.of(PAGE, SIZE, Sort.Direction.ASC, SORT_1, SORT_2); - } + @Autowired + private FeignContext context; - @Test - public void testPaginationRequest() { - Encoder encoder = this.context.getInstance("foo", Encoder.class); - assertThat(encoder, is(notNullValue())); - RequestTemplate request = new RequestTemplate(); - encoder.encode(createPageAndRequest(), null, request); - assertThat("Request queries shall contain three entries", - request.queries().size(), - equalTo(2)); - assertThat("Request page shall contain page", - request.queries().get("page"), - hasItem(String.valueOf(PAGE))); - assertThat("Request size shall contain size", - request.queries().get("size"), - hasItem(String.valueOf(SIZE))); - assertThat("Request sort size shall contain sort entries", - request.queries().containsKey("sort"), - equalTo(false)); - } + @Test + public void testPaginationAndSortingRequest() { + Encoder encoder = this.context.getInstance("foo", Encoder.class); + assertThat(encoder).isNotNull(); + RequestTemplate request = new RequestTemplate(); + encoder.encode(createPageAndSortRequest(), null, request); - private Pageable createPageAndRequest() { - return PageRequest.of(PAGE, SIZE); - } + // Request queries shall contain three entries + assertThat(request.queries().size()).isEqualTo(3); + // Request page shall contain page + assertThat(request.queries().get("page")).contains(String.valueOf(PAGE)); + // Request size shall contain size + assertThat(request.queries().get("size")).contains(String.valueOf(SIZE)); + // Request sort size shall contain sort entries + assertThat(request.queries().get("sort").size()).isEqualTo(2); + } - @Test - public void testSortingRequest() { - Encoder encoder = this.context.getInstance("foo", Encoder.class); - assertThat(encoder, is(notNullValue())); - RequestTemplate request = new RequestTemplate(); + private Pageable createPageAndSortRequest() { + return PageRequest.of(PAGE, SIZE, Sort.Direction.ASC, SORT_1, SORT_2); + } - encoder.encode(createSort(), null, request); + @Test + public void testPaginationRequest() { + Encoder encoder = this.context.getInstance("foo", Encoder.class); + assertThat(encoder).isNotNull(); + RequestTemplate request = new RequestTemplate(); + encoder.encode(createPageAndRequest(), null, request); + assertThat(request.queries().size()).isEqualTo(2); + // Request page shall contain page + assertThat(request.queries().get("page")).contains(String.valueOf(PAGE)); + // Request size shall contain size + assertThat(request.queries().get("size")).contains(String.valueOf(SIZE)); + // Request sort size shall contain sort entries + assertThat(request.queries().containsKey("sort")).isEqualTo(false); + } - assertThat("Request queries shall contain three entries", - request.queries().size(), - equalTo(1)); - assertThat("Request sort size shall contain sort entries", - request.queries().get("sort").size(), - equalTo(2)); - } + private Pageable createPageAndRequest() { + return PageRequest.of(PAGE, SIZE); + } - private Sort createSort() { - return Sort.by(SORT_1, SORT_2).ascending(); - } -} \ No newline at end of file + @Test + public void testSortingRequest() { + Encoder encoder = this.context.getInstance("foo", Encoder.class); + assertThat(encoder).isNotNull(); + RequestTemplate request = new RequestTemplate(); + + encoder.encode(createSort(), null, request); + // Request queries shall contain three entries + assertThat(request.queries().size()).isEqualTo(1); + // Request sort size shall contain sort entries + assertThat(request.queries().get("sort").size()).isEqualTo(2); + } + + private Sort createSort() { + return Sort.by(SORT_1, SORT_2).ascending(); + } + +} diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index d55c3a1d..28b09d01 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -12,7 +12,8 @@ - + + From 4ac6429152d5dcdbf73e34bb5394c8f3f3a91c22 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 26 Feb 2019 20:24:00 -0500 Subject: [PATCH 5/5] Polishing checkstyle --- .../cloud/openfeign/encoding/FeignPageableEncodingTests.java | 5 ++--- .../cloud/openfeign/support/PageableEncoderTests.java | 4 ++-- src/checkstyle/checkstyle-suppressions.xml | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java index ff1fef76..424fb1ad 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/encoding/FeignPageableEncodingTests.java @@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignClientsConfiguration; @@ -48,14 +47,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * Tests the pagination encoding. * * @author Charlie Mordant. */ -@SpringBootTest(classes = FeignPageableEncodingTests.Application.class, - webEnvironment = WebEnvironment.RANDOM_PORT, value = { +@SpringBootTest(classes = FeignPageableEncodingTests.Application.class, webEnvironment = RANDOM_PORT, value = { "feign.compression.request.enabled=true", "hystrix.command.default.execution.isolation.strategy=SEMAPHORE", "ribbon.OkToRetryOnAllOperations=false" }) diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java index 650500bf..50015e1b 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/PageableEncoderTests.java @@ -31,6 +31,7 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * Tests the pagination encoding and sorting. @@ -38,8 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Charlie Mordant. */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = SpringEncoderTests.Application.class, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = { +@SpringBootTest(classes = SpringEncoderTests.Application.class, webEnvironment = RANDOM_PORT, value = { "spring.application.name=springencodertest", "spring.jmx.enabled=false" }) @DirtiesContext public class PageableEncoderTests { diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 28b09d01..2bd6edec 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -12,8 +12,6 @@ - -