Skip to content

Commit 28493df

Browse files
authored
[Spring] Spring HTTP Interface library (#14485)
1 parent 8540c82 commit 28493df

130 files changed

Lines changed: 16970 additions & 7 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/samples-jdk17.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ on:
66
- samples/openapi3/client/petstore/spring-cloud-3/**
77
- samples/client/petstore/java-helidon-client/mp/**
88
- samples/client/petstore/java-helidon-client/se/**
9+
- samples/client/petstore/spring-http-interface-reactive/**
10+
- samples/client/petstore/spring-http-interface/**
911
# servers
1012
- samples/openapi3/server/petstore/springboot-3/**
1113
- samples/server/petstore/java-helidon-server/mp/**
@@ -16,6 +18,8 @@ on:
1618
- samples/openapi3/client/petstore/spring-cloud-3/**
1719
- samples/client/petstore/java-helidon-client/mp/**
1820
- samples/client/petstore/java-helidon-client/se/**
21+
- samples/client/petstore/spring-http-interface-reactive/**
22+
- samples/client/petstore/spring-http-interface/**
1923
# servers
2024
- samples/openapi3/server/petstore/springboot-3/**
2125
- samples/server/petstore/java-helidon-server/mp/**
@@ -32,10 +36,14 @@ jobs:
3236
- samples/openapi3/client/petstore/spring-cloud-3
3337
- samples/client/petstore/java-helidon-client/mp
3438
- samples/client/petstore/java-helidon-client/se
39+
- samples/client/petstore/spring-http-interface-reactive
40+
- samples/client/petstore/spring-http-interface
3541
# servers
3642
- samples/openapi3/server/petstore/springboot-3
3743
- samples/server/petstore/java-helidon-server/mp
3844
- samples/server/petstore/java-helidon-server/se
45+
- samples/client/petstore/spring-http-interface-reactive
46+
- samples/client/petstore/spring-http-interface
3947
steps:
4048
- uses: actions/checkout@v3
4149
- uses: actions/setup-java@v3
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
generatorName: spring
2+
library: spring-http-interface
3+
outputDir: samples/client/petstore/spring-http-interface-reactive
4+
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
6+
additionalProperties:
7+
artifactId: spring-http-interface-reactive
8+
snapshotVersion: "true"
9+
hideGenerationTimestamp: "true"
10+
reactive: "true"
11+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
generatorName: spring
2+
library: spring-http-interface
3+
outputDir: samples/client/petstore/spring-http-interface
4+
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
6+
additionalProperties:
7+
artifactId: spring-http-interface
8+
snapshotVersion: "true"
9+
hideGenerationTimestamp: "true"
10+
modelNameSuffix: 'Dto'

docs/generators/java-camel.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
6464
|interfaceOnly|Whether to generate only API interface stubs without the server files.| |false|
6565
|invokerPackage|root package for generated code| |org.openapitools.api|
6666
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
67-
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dt>**spring-cloud**</dt><dd>Spring-Cloud-Feign client with Spring-Boot auto-configured settings.</dd></dl>|spring-boot|
67+
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dt>**spring-cloud**</dt><dd>Spring-Cloud-Feign client with Spring-Boot auto-configured settings.</dd><dt>**spring-http-interface**</dt><dd>Spring 6 HTTP interfaces (testing)</dd></dl>|spring-boot|
6868
|licenseName|The name of the license| |Unlicense|
6969
|licenseUrl|The URL of the license| |http://unlicense.org|
7070
|modelPackage|package for generated models| |org.openapitools.model|

docs/generators/spring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
5757
|interfaceOnly|Whether to generate only API interface stubs without the server files.| |false|
5858
|invokerPackage|root package for generated code| |org.openapitools.api|
5959
|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C#have this enabled by default).|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
60-
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dt>**spring-cloud**</dt><dd>Spring-Cloud-Feign client with Spring-Boot auto-configured settings.</dd></dl>|spring-boot|
60+
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dt>**spring-cloud**</dt><dd>Spring-Cloud-Feign client with Spring-Boot auto-configured settings.</dd><dt>**spring-http-interface**</dt><dd>Spring 6 HTTP interfaces (testing)</dd></dl>|spring-boot|
6161
|licenseName|The name of the license| |Unlicense|
6262
|licenseUrl|The URL of the license| |http://unlicense.org|
6363
|modelPackage|package for generated models| |org.openapitools.model|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public class SpringCodegen extends AbstractJavaCodegen
9999
public static final String USE_TAGS = "useTags";
100100
public static final String SPRING_BOOT = "spring-boot";
101101
public static final String SPRING_CLOUD_LIBRARY = "spring-cloud";
102+
public static final String SPRING_HTTP_INTERFACE = "spring-http-interface";
102103
public static final String API_FIRST = "apiFirst";
103104
public static final String SPRING_CONTROLLER = "useSpringController";
104105
public static final String HATEOAS = "hateoas";
@@ -247,6 +248,7 @@ public SpringCodegen() {
247248
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
248249
supportedLibraries.put(SPRING_CLOUD_LIBRARY,
249250
"Spring-Cloud-Feign client with Spring-Boot auto-configured settings.");
251+
supportedLibraries.put(SPRING_HTTP_INTERFACE, "Spring 6 HTTP interfaces (testing)");
250252
setLibrary(SPRING_BOOT);
251253
final CliOption library = new CliOption(CodegenConstants.LIBRARY, CodegenConstants.LIBRARY_DESC)
252254
.defaultValue(SPRING_BOOT);
@@ -272,7 +274,7 @@ public String getHelp() {
272274

273275
@Override
274276
public DocumentationProvider defaultDocumentationProvider() {
275-
return DocumentationProvider.SPRINGDOC;
277+
return SPRING_HTTP_INTERFACE.equals(library) ? DocumentationProvider.NONE : DocumentationProvider.SPRINGDOC;
276278
}
277279

278280
public List<DocumentationProvider> supportedDocumentationProvider() {
@@ -343,6 +345,14 @@ public void processOpts() {
343345
// Please refrain from updating values of Config Options after super.ProcessOpts() is called
344346
super.processOpts();
345347

348+
if (SPRING_HTTP_INTERFACE.equals(library)) {
349+
documentationProvider = DocumentationProvider.NONE;
350+
annotationLibrary = AnnotationLibrary.NONE;
351+
useJakartaEe=true;
352+
additionalProperties.put(USE_JAKARTA_EE, useJakartaEe);
353+
applyJakartaPackage();
354+
}
355+
346356
if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) {
347357
LOGGER.warn("The springfox documentation provider is deprecated for removal. Use the springdoc provider instead.");
348358
}
@@ -402,8 +412,8 @@ public void processOpts() {
402412
}
403413

404414
if (additionalProperties.containsKey(REACTIVE)) {
405-
if (!SPRING_BOOT.equals(library)) {
406-
throw new IllegalArgumentException("Currently, reactive option is only supported with Spring-boot");
415+
if (SPRING_CLOUD_LIBRARY.equals(library)) {
416+
throw new IllegalArgumentException("Currently, reactive option doesn't supported by Spring Cloud");
407417
}
408418
this.setReactive(Boolean.parseBoolean(additionalProperties.get(REACTIVE).toString()));
409419
}
@@ -537,7 +547,7 @@ public void processOpts() {
537547
// @RequestMapping not supported with spring cloud openfeign.
538548
setRequestMappingMode(RequestMappingMode.none);
539549
additionalProperties.put(USE_FEIGN_CLIENT, "true");
540-
} else {
550+
} else if (SPRING_BOOT.equals(library)) {
541551
apiTemplateFiles.put("apiController.mustache", "Controller.java");
542552
if (containsEnums()) {
543553
supportingFiles.add(new SupportingFile("converter.mustache",
@@ -561,10 +571,14 @@ public void processOpts() {
561571
"SpringFoxConfiguration.java"));
562572
}
563573
}
574+
} else if (SPRING_HTTP_INTERFACE.equals(library)) {
575+
supportingFiles.add(new SupportingFile("httpInterfacesConfiguration.mustache",
576+
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "HttpInterfacesAbstractConfigurator.java"));
577+
writePropertyBack(USE_BEANVALIDATION, false);
564578
}
565579
}
566580

567-
if (!SPRING_CLOUD_LIBRARY.equals(library)) {
581+
if (SPRING_BOOT.equals(library)) {
568582
supportingFiles.add(new SupportingFile("apiUtil.mustache",
569583
(sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiUtil.java"));
570584
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# OpenAPI generated API stub
2+
3+
[Spring Framework 6 HTTP Interface](https://docs.spring.io/spring-framework/docs/6.0.0/reference/html/integration.html#rest-http-interface)
4+
5+
6+
## Overview
7+
This code was generated by the [OpenAPI Generator](https://openapi-generator.tech) project.
8+
By using the [OpenAPI-Spec](https://openapis.org), you can easily generate an API stub.
9+
This is an example of building API stub interfaces in Java using the Spring framework.
10+
11+
The stubs generated can be used in your existing Spring application for HTTP integration with other REST services
12+
To use auto-generated interfaces you have to create your own configuration which extends default abstract configurator & provide `WebClient` instance via constructor
13+
```java
14+
@Configuration
15+
public class MyConfiguration extends {{configPackage}}.HttpInterfacesAbstractConfigurator {
16+
17+
public MyConfiguration(WebClient myWebClient) { // separately created WebClient instance
18+
super(myWebClient);
19+
}
20+
}
21+
```
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) ({{{generatorVersion}}}).
3+
* https://openapi-generator.tech
4+
* Do not edit the class manually.
5+
*/
6+
package {{package}};
7+
8+
{{#imports}}import {{import}};
9+
{{/imports}}
10+
import org.springframework.http.ResponseEntity;
11+
import org.springframework.web.bind.annotation.*;
12+
import org.springframework.web.service.annotation.*;
13+
import org.springframework.web.multipart.MultipartFile;
14+
{{#reactive}}
15+
16+
import org.springframework.http.codec.multipart.Part;
17+
import reactor.core.publisher.Flux;
18+
import reactor.core.publisher.Mono;
19+
{{/reactive}}
20+
21+
import java.util.List;
22+
import java.util.Map;
23+
import java.util.Optional;
24+
import {{javaxPackage}}.annotation.Generated;
25+
26+
27+
{{>generatedAnnotation}}
28+
{{#operations}}
29+
public interface {{classname}} {
30+
{{#operation}}
31+
32+
/**
33+
* {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}}
34+
{{#notes}}
35+
* {{.}}
36+
{{/notes}}
37+
*
38+
{{#allParams}}
39+
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
40+
{{/allParams}}
41+
* @return {{#responses}}{{message}} (status code {{code}}){{^-last}}
42+
* or {{/-last}}{{/responses}}
43+
{{#isDeprecated}}
44+
* @deprecated
45+
{{/isDeprecated}}
46+
{{#externalDocs}}
47+
* {{description}}
48+
* @see <a href="{{url}}">{{summary}} Documentation</a>
49+
{{/externalDocs}}
50+
*/
51+
{{#isDeprecated}}
52+
@Deprecated
53+
{{/isDeprecated}}
54+
@HttpExchange(
55+
method = "{{{httpMethod}}}",
56+
value = "{{{path}}}"{{#vendorExtensions.x-accepts}},
57+
accept = "{{{vendorExtensions.x-accepts}}}"{{/vendorExtensions.x-accepts}}{{#vendorExtensions.x-content-type}},
58+
contentType = "{{{vendorExtensions.x-content-type}}}"{{/vendorExtensions.x-content-type}}
59+
)
60+
{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}(
61+
{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},
62+
{{/-last}}{{/allParams}}
63+
){{#unhandledException}} throws Exception{{/unhandledException}};
64+
65+
{{/operation}}
66+
}
67+
{{/operations}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) ({{{generatorVersion}}}).
3+
* https://openapi-generator.tech
4+
* Do not edit the class manually.
5+
*/
6+
package {{configPackage}};
7+
8+
{{#apiInfo}}
9+
{{#apis}}
10+
import {{apiPackage}}.{{classname}};
11+
{{/apis}}
12+
{{/apiInfo}}
13+
14+
import org.springframework.context.annotation.Bean;
15+
import org.springframework.web.reactive.function.client.WebClient;
16+
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
17+
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
18+
19+
public abstract class HttpInterfacesAbstractConfigurator {
20+
21+
private final WebClient webClient;
22+
23+
public HttpInterfacesAbstractConfigurator(final WebClient webClient) {
24+
this.webClient = webClient;
25+
}
26+
27+
{{#apiInfo}}
28+
{{#apis}}
29+
@Bean(name = "{{configPackage}}.HttpInterfacesAbstractConfigurator.{{classVarName}}")
30+
{{classname}} {{classVarName}}HttpProxy() {
31+
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).build();
32+
return factory.createClient({{classname}}.class);
33+
}
34+
35+
{{/apis}}
36+
{{/apiInfo}}
37+
38+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<groupId>{{groupId}}</groupId>
4+
<artifactId>{{artifactId}}</artifactId>
5+
<packaging>jar</packaging>
6+
<name>{{artifactId}}</name>
7+
<version>{{artifactVersion}}</version>
8+
<properties>
9+
<java.version>17</java.version>
10+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
11+
</properties>
12+
{{#parentOverridden}}
13+
<parent>
14+
<groupId>{{{parentGroupId}}}</groupId>
15+
<artifactId>{{{parentArtifactId}}}</artifactId>
16+
<version>{{{parentVersion}}}</version>
17+
</parent>
18+
{{/parentOverridden}}
19+
{{^parentOverridden}}
20+
<parent>
21+
<groupId>org.springframework.boot</groupId>
22+
<artifactId>spring-boot-starter-parent</artifactId>
23+
<version>3.0.1</version>
24+
<relativePath/> <!-- lookup parent from repository -->
25+
</parent>
26+
{{/parentOverridden}}
27+
28+
<build>
29+
<plugins>
30+
<plugin>
31+
<groupId>org.apache.maven.plugins</groupId>
32+
<artifactId>maven-compiler-plugin</artifactId>
33+
<version>3.8.1</version>
34+
<configuration>
35+
<source>${java.version}</source>
36+
<target>${java.version}</target>
37+
</configuration>
38+
</plugin>
39+
<plugin>
40+
<groupId>org.apache.maven.plugins</groupId>
41+
<artifactId>maven-source-plugin</artifactId>
42+
<version>3.2.1</version>
43+
<executions>
44+
<execution>
45+
<id>attach-sources</id>
46+
<goals>
47+
<goal>jar-no-fork</goal>
48+
</goals>
49+
</execution>
50+
</executions>
51+
</plugin>
52+
</plugins>
53+
</build>
54+
55+
<dependencies>
56+
<dependency>
57+
<groupId>org.springframework.boot</groupId>
58+
<artifactId>spring-boot-starter-webflux</artifactId>
59+
</dependency>
60+
<!-- @Nullable annotation -->
61+
<dependency>
62+
<groupId>com.google.code.findbugs</groupId>
63+
<artifactId>jsr305</artifactId>
64+
<version>3.0.2</version>
65+
</dependency>
66+
<dependency>
67+
<groupId>jakarta.validation</groupId>
68+
<artifactId>jakarta.validation-api</artifactId>
69+
</dependency>
70+
{{#withXml}}
71+
<!-- XML processing: Jackson -->
72+
<dependency>
73+
<groupId>jakarta.xml.bind</groupId>
74+
<artifactId>jakarta.xml.bind-api</artifactId>
75+
</dependency>
76+
<dependency>
77+
<groupId>com.fasterxml.jackson.dataformat</groupId>
78+
<artifactId>jackson-dataformat-xml</artifactId>
79+
</dependency>
80+
{{/withXml}}
81+
<dependency>
82+
<groupId>com.fasterxml.jackson.datatype</groupId>
83+
<artifactId>jackson-datatype-jsr310</artifactId>
84+
</dependency>
85+
{{#openApiNullable}}
86+
<dependency>
87+
<groupId>org.openapitools</groupId>
88+
<artifactId>jackson-databind-nullable</artifactId>
89+
<version>0.2.2</version>
90+
</dependency>
91+
{{/openApiNullable}}
92+
<dependency>
93+
<groupId>org.springframework.boot</groupId>
94+
<artifactId>spring-boot-starter-test</artifactId>
95+
<scope>test</scope>
96+
</dependency>
97+
</dependencies>
98+
</project>

0 commit comments

Comments
 (0)