diff --git a/customer-service-client/.openapi-generator-ignore b/customer-service-client/.openapi-generator-ignore index 762b8cf..c61d05f 100644 --- a/customer-service-client/.openapi-generator-ignore +++ b/customer-service-client/.openapi-generator-ignore @@ -1,3 +1,4 @@ +# existing patterns **/.github/** **/gradle/** **/.gradle/** @@ -15,4 +16,12 @@ **/git_push.sh **/README.md **/.openapi-generator/** -!src/gen/java/main/** \ No newline at end of file +!src/gen/java/** + +# --- Custom additions for generated DTO cleanup --- +# ignore these generated models regardless of location +**/src/gen/java/**/generated/dto/Page*.java +**/src/gen/java/**/generated/dto/ServiceResponse.java +**/src/gen/java/**/generated/dto/ServiceResponseVoid.java +**/src/gen/java/**/generated/dto/Meta.java +**/src/gen/java/**/generated/dto/Sort.java \ No newline at end of file diff --git a/customer-service-client/README.md b/customer-service-client/README.md index 40563a3..0f3c918 100644 --- a/customer-service-client/README.md +++ b/customer-service-client/README.md @@ -178,11 +178,11 @@ public class CustomerClientAdapterImpl implements CustomerClientAdapter { @Override public ServiceClientResponse> getCustomers( String name, String email, Integer page, Integer size, - SortField sortBy, SortDirection direction) { + ClientSortField sortBy, ClientSortDirection direction) { return api.getCustomers( name, email, page, size, - sortBy != null ? sortBy.value() : SortField.CUSTOMER_ID.value(), - direction != null ? direction.value() : SortDirection.ASC.value()); + sortBy != null ? sortBy.value() : ClientSortField.CUSTOMER_ID.value(), + direction != null ? direction.value() : ClientSortDirection.ASC.value()); } } ``` @@ -252,6 +252,22 @@ try { --- +### 🧹 Ignoring Redundant Generated DTOs + +The following patterns in [`.openapi-generator-ignore`](.openapi-generator-ignore) prevent redundant DTOs from being regenerated. +These classes already exist in the shared `common` package and are excluded from code generation. + +```bash +# --- Custom additions for generated DTO cleanup --- +**/src/gen/java/**/generated/dto/Page*.java +**/src/gen/java/**/generated/dto/ServiceResponse.java +**/src/gen/java/**/generated/dto/ServiceResponseVoid.java +**/src/gen/java/**/generated/dto/Meta.java +**/src/gen/java/**/generated/dto/Sort.java +``` + +--- + ## 📚 Notes * **Toolchain:** Java 21, Spring Boot 3.4.10, OpenAPI Generator 7.16.0 diff --git a/customer-service-client/pom.xml b/customer-service-client/pom.xml index bffe0a6..2d27d42 100644 --- a/customer-service-client/pom.xml +++ b/customer-service-client/pom.xml @@ -6,7 +6,7 @@ io.github.bsayli customer-service-client - 0.7.0 + 0.7.2 customer-service-client Generated client (RestClient) using generics-aware OpenAPI templates jar @@ -20,7 +20,7 @@ 7.16.0 3.1.1 - 3.0.0 + ${spotless-maven-plugin.version} 5.1.0 5.5 5.13.4 @@ -32,9 +32,11 @@ 3.6.0 3.3.1 3.8.1 + 3.0.0 ${project.build.directory}/upstream-templates ${project.build.directory}/effective-templates + @@ -217,6 +219,7 @@ commonPackage=io.github.bsayli.openapi.client.common + ${project.basedir}/.openapi-generator-ignore @@ -241,7 +244,31 @@ + + com.diffplug.spotless + spotless-maven-plugin + ${spotless-maven-plugin.version} + + + + target/generated-sources/openapi/src/gen/java/**/*.java + + + cleanthat-javaparser-unnecessaryimport + + + + + + spotless-apply-generated + process-sources + + apply + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/CustomerClientAdapter.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/CustomerClientAdapter.java index 431136a..5616299 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/CustomerClientAdapter.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/CustomerClientAdapter.java @@ -2,8 +2,8 @@ import io.github.bsayli.openapi.client.common.Page; import io.github.bsayli.openapi.client.common.ServiceClientResponse; -import io.github.bsayli.openapi.client.common.sort.SortDirection; -import io.github.bsayli.openapi.client.common.sort.SortField; +import io.github.bsayli.openapi.client.common.sort.ClientSortDirection; +import io.github.bsayli.openapi.client.common.sort.ClientSortField; import io.github.bsayli.openapi.client.generated.dto.CustomerCreateRequest; import io.github.bsayli.openapi.client.generated.dto.CustomerDeleteResponse; import io.github.bsayli.openapi.client.generated.dto.CustomerDto; @@ -22,8 +22,8 @@ ServiceClientResponse> getCustomers( String email, Integer page, Integer size, - SortField sortBy, - SortDirection direction); + ClientSortField sortBy, + ClientSortDirection direction); ServiceClientResponse updateCustomer( Integer customerId, CustomerUpdateRequest request); diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/config/CustomerApiClientConfig.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/config/CustomerApiClientConfig.java index ecaa442..ad221bc 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/config/CustomerApiClientConfig.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/config/CustomerApiClientConfig.java @@ -21,7 +21,6 @@ @Configuration public class CustomerApiClientConfig { - @Bean RestClientCustomizer problemDetailStatusHandler(ObjectMapper om) { diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImpl.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImpl.java index ecb319a..e1817ec 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImpl.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImpl.java @@ -3,8 +3,8 @@ import io.github.bsayli.openapi.client.adapter.CustomerClientAdapter; import io.github.bsayli.openapi.client.common.Page; import io.github.bsayli.openapi.client.common.ServiceClientResponse; -import io.github.bsayli.openapi.client.common.sort.SortDirection; -import io.github.bsayli.openapi.client.common.sort.SortField; +import io.github.bsayli.openapi.client.common.sort.ClientSortDirection; +import io.github.bsayli.openapi.client.common.sort.ClientSortField; import io.github.bsayli.openapi.client.generated.api.CustomerControllerApi; import io.github.bsayli.openapi.client.generated.dto.*; import org.springframework.stereotype.Service; @@ -30,7 +30,7 @@ public ServiceClientResponse getCustomer(Integer customerId) { @Override public ServiceClientResponse> getCustomers() { - return getCustomers(null, null, 0, 5, SortField.CUSTOMER_ID, SortDirection.ASC); + return getCustomers(null, null, 0, 5, ClientSortField.CUSTOMER_ID, ClientSortDirection.ASC); } @Override @@ -39,16 +39,16 @@ public ServiceClientResponse> getCustomers( String email, Integer page, Integer size, - SortField sortBy, - SortDirection direction) { + ClientSortField sortBy, + ClientSortDirection direction) { return api.getCustomers( name, email, page, size, - sortBy != null ? sortBy.value() : SortField.CUSTOMER_ID.value(), - direction != null ? direction.value() : SortDirection.ASC.value()); + sortBy != null ? sortBy.value() : ClientSortField.CUSTOMER_ID.value(), + direction != null ? direction.value() : ClientSortDirection.ASC.value()); } @Override diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/support/ProblemDetailSupport.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/support/ProblemDetailSupport.java index 2d23050..8f8881b 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/support/ProblemDetailSupport.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/adapter/support/ProblemDetailSupport.java @@ -20,7 +20,7 @@ private ProblemDetailSupport() {} public static ProblemDetail extract(ObjectMapper om, ClientHttpResponse response) { ProblemDetail pd; MediaType contentType = - Optional.ofNullable(response.getHeaders().getContentType()).orElse(MediaType.ALL); + Optional.ofNullable(response.getHeaders().getContentType()).orElse(MediaType.ALL); HttpStatusCode status; try { @@ -39,10 +39,10 @@ public static ProblemDetail extract(ObjectMapper om, ClientHttpResponse response } } catch (IOException e) { log.warn( - "Unable to deserialize ProblemDetail (status={}, contentType={}); using generic fallback", - status, - contentType, - e); + "Unable to deserialize ProblemDetail (status={}, contentType={}); using generic fallback", + status, + contentType, + e); pd = fallback(status, "Unparseable problem response"); } catch (Exception e) { log.warn("Unexpected error while parsing ProblemDetail", e); @@ -59,4 +59,4 @@ private static ProblemDetail fallback(HttpStatusCode status, String detail) { pd.setDetail(detail); return pd; } -} \ No newline at end of file +} diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSort.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSort.java index cf0cccb..04ef9de 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSort.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSort.java @@ -1,13 +1,13 @@ package io.github.bsayli.openapi.client.common.sort; -public record ClientSort(SortField field, SortDirection direction) { +public record ClientSort(ClientSortField field, ClientSortDirection direction) { public ClientSort { if (field == null) { - field = SortField.CUSTOMER_ID; + field = ClientSortField.CUSTOMER_ID; } if (direction == null) { - direction = SortDirection.ASC; + direction = ClientSortDirection.ASC; } } } diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/SortDirection.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSortDirection.java similarity index 78% rename from customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/SortDirection.java rename to customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSortDirection.java index be17ad4..0c7f620 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/SortDirection.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSortDirection.java @@ -1,12 +1,12 @@ package io.github.bsayli.openapi.client.common.sort; -public enum SortDirection { +public enum ClientSortDirection { ASC("asc"), DESC("desc"); private final String value; - SortDirection(String value) { + ClientSortDirection(String value) { this.value = value; } diff --git a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/SortField.java b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSortField.java similarity index 82% rename from customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/SortField.java rename to customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSortField.java index d21ff71..95aee0f 100644 --- a/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/SortField.java +++ b/customer-service-client/src/main/java/io/github/bsayli/openapi/client/common/sort/ClientSortField.java @@ -1,13 +1,13 @@ package io.github.bsayli.openapi.client.common.sort; -public enum SortField { +public enum ClientSortField { CUSTOMER_ID("customerId"), NAME("name"), EMAIL("email"); private final String value; - SortField(String value) { + ClientSortField(String value) { this.value = value; } diff --git a/customer-service-client/src/main/resources/customer-api-docs.yaml b/customer-service-client/src/main/resources/customer-api-docs.yaml index 8e5417d..e4eec45 100644 --- a/customer-service-client/src/main/resources/customer-api-docs.yaml +++ b/customer-service-client/src/main/resources/customer-api-docs.yaml @@ -2,7 +2,7 @@ openapi: 3.1.0 info: title: Customer Service API description: Customer Service API with type-safe generic responses using OpenAPI - version: 0.7.0 + version: 0.7.2 servers: - url: http://localhost:8084/customer-service description: Local service URL diff --git a/customer-service-client/src/test/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImplTest.java b/customer-service-client/src/test/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImplTest.java index ee98830..1df22e9 100644 --- a/customer-service-client/src/test/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImplTest.java +++ b/customer-service-client/src/test/java/io/github/bsayli/openapi/client/adapter/impl/CustomerClientAdapterImplTest.java @@ -8,16 +8,10 @@ import io.github.bsayli.openapi.client.common.ClientMeta; import io.github.bsayli.openapi.client.common.Page; import io.github.bsayli.openapi.client.common.ServiceClientResponse; -import io.github.bsayli.openapi.client.common.sort.SortDirection; -import io.github.bsayli.openapi.client.common.sort.SortField; +import io.github.bsayli.openapi.client.common.sort.ClientSortDirection; +import io.github.bsayli.openapi.client.common.sort.ClientSortField; import io.github.bsayli.openapi.client.generated.api.CustomerControllerApi; -import io.github.bsayli.openapi.client.generated.dto.CustomerCreateRequest; -import io.github.bsayli.openapi.client.generated.dto.CustomerDeleteResponse; -import io.github.bsayli.openapi.client.generated.dto.CustomerDto; -import io.github.bsayli.openapi.client.generated.dto.CustomerUpdateRequest; -import io.github.bsayli.openapi.client.generated.dto.ServiceResponseCustomerDeleteResponse; -import io.github.bsayli.openapi.client.generated.dto.ServiceResponseCustomerDto; -import io.github.bsayli.openapi.client.generated.dto.ServiceResponsePageCustomerDto; +import io.github.bsayli.openapi.client.generated.dto.*; import java.time.OffsetDateTime; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -106,7 +100,7 @@ void getCustomers_delegates_and_returnsPage() { when(api.getCustomers(any(), any(), any(), any(), any(), any())).thenReturn(wrapper); ServiceClientResponse> res = - adapter.getCustomers(null, null, 0, 5, SortField.CUSTOMER_ID, SortDirection.ASC); + adapter.getCustomers(null, null, 0, 5, ClientSortField.CUSTOMER_ID, ClientSortDirection.ASC); assertNotNull(res); assertNotNull(res.getData()); diff --git a/customer-service/pom.xml b/customer-service/pom.xml index 0a23d11..d57ca47 100644 --- a/customer-service/pom.xml +++ b/customer-service/pom.xml @@ -13,7 +13,7 @@ io.github.bsayli customer-service - 0.7.0 + 0.7.2 customer-service Spring Boot 3.4 + Springdoc (OpenAPI) for generics-aware client generation diff --git a/docs/_includes/head_custom.html b/docs/_includes/head_custom.html index 46a4b73..4c40958 100644 --- a/docs/_includes/head_custom.html +++ b/docs/_includes/head_custom.html @@ -2,7 +2,11 @@ \ No newline at end of file diff --git a/docs/adoption/client-side-adoption-pom.md b/docs/adoption/client-side-adoption-pom.md index b5d73ce..d19a152 100644 --- a/docs/adoption/client-side-adoption-pom.md +++ b/docs/adoption/client-side-adoption-pom.md @@ -72,6 +72,10 @@ Define reusable properties to simplify plugin management and template resolution 7.16.0 ${project.build.directory}/openapi-templates-upstream ${project.build.directory}/openapi-templates-effective + 3.6.0 + 3.3.1 + 3.8.1 + 3.0.0 ``` @@ -195,8 +199,9 @@ These plugins work in sequence to **unpack, overlay, and compile** OpenAPI templ - commonPackage=your.base.openapi.client.common + commonPackage=your.base.openapi.client.common + ${project.basedir}/.openapi-generator-ignore @@ -221,6 +226,35 @@ These plugins work in sequence to **unpack, overlay, and compile** OpenAPI templ + + + + + com.diffplug.spotless + spotless-maven-plugin + ${spotless-maven-plugin.version} + + + + + target/generated-sources/openapi/src/gen/java/**/*.java + + + cleanthat-javaparser-unnecessaryimport + + + + + + spotless-apply-generated + process-sources + + apply + + + + + ``` @@ -235,6 +269,7 @@ These plugins work in sequence to **unpack, overlay, and compile** OpenAPI templ | **maven-resources-plugin** | Overlays your local Mustache templates on top of upstream ones. | | **openapi-generator-maven-plugin** | Generates type-safe client code using the effective templates. | | **build-helper-maven-plugin** | Ensures generated sources are included in the compilation phase. | +| **spotless-maven-plugin** | Automatically removes unused imports and keeps generated sources clean. | Together, these guarantee your **generics‑aware response wrappers** (e.g., `ServiceClientResponse`) are generated cleanly and consistently across builds. diff --git a/docs/adoption/client-side-adoption.md b/docs/adoption/client-side-adoption.md index 8b8e5be..7355f6b 100644 --- a/docs/adoption/client-side-adoption.md +++ b/docs/adoption/client-side-adoption.md @@ -61,6 +61,34 @@ new `{ data, meta }` response structure and RFC 9457 `ProblemDetail` error model --- +### 🧹 Ignoring Redundant Generated DTOs + +To prevent OpenAPI Generator from re-creating DTOs that already exist in the shared `common` package, +add the following patterns to your `.openapi-generator-ignore` file. +This avoids redundant model generation (e.g., `Page`, `Meta`, `Sort`, `ServiceResponse`) and keeps diffs minimal. + +```bash +# --- Custom additions for generated DTO cleanup --- +**/src/gen/java/**/generated/dto/Page*.java +**/src/gen/java/**/generated/dto/ServiceResponse.java +**/src/gen/java/**/generated/dto/ServiceResponseVoid.java +**/src/gen/java/**/generated/dto/Meta.java +**/src/gen/java/**/generated/dto/Sort.java +``` + +> **Note:** +> The paths above assume your `openapi-generator-maven-plugin` uses +> `sourceFolder=src/gen/java`. +> If your configuration differs, adjust the directory prefix accordingly. +> +> Also make sure your POM specifies the file override: +> +> ```xml +> ${project.basedir}/.openapi-generator-ignore +> ``` + +--- + ## 🧩 Core Classes (Shared Base) Copy these into your client module under `openapi/client/common`: diff --git a/docs/go/repo.html b/docs/go/repo.html index 539f897..ad1af8a 100644 --- a/docs/go/repo.html +++ b/docs/go/repo.html @@ -1,18 +1,22 @@ - + Redirecting… - + - - + +

Redirecting to GitHub repo…

@@ -27,7 +31,12 @@ const go = () => location.href = target + utm; let redirected = false; - const safeGo = () => { if (!redirected) { redirected = true; go(); } }; + const safeGo = () => { + if (!redirected) { + redirected = true; + go(); + } + }; gtag('event', 'outbound_to_github', { destination: 'github_repo',