Skip to content

Commit 1653f94

Browse files
Merge branch 'main' into dependabot/maven/quarkus.version-2.8.0.Final
2 parents 9c037be + 82bd048 commit 1653f94

File tree

48 files changed

+914
-245
lines changed

Some content is hidden

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

48 files changed

+914
-245
lines changed

.github/project.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
release:
2-
current-version: 0.3.1
2+
current-version: 0.4.1
33
next-version: 1.0.0-SNAPSHOT
44

README.md

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Add the following dependency to your project's `pom.xml` file:
1717
<dependency>
1818
<groupId>io.quarkiverse.openapi.generator</groupId>
1919
<artifactId>quarkus-openapi-generator</artifactId>
20-
<version>0.3.1</version>
20+
<version>0.4.0</version>
2121
</dependency>
2222
```
2323

@@ -277,21 +277,29 @@ org.acme.openapi.simple.api.DefaultApi/byeGet/CircuitBreaker/successThreshold=22
277277
````
278278

279279
## Sending multipart/form-data
280-
The rest client also supports request with mime-type multipart/form-data and, if the schema of the request body is known in advance, we can also automatically generate the models of the request bodies.
280+
281+
The rest client also supports request with mime-type multipart/form-data and, if the schema of the request body is known in advance, we can also automatically generate the models of the request
282+
bodies.
281283

282284
You need to add the following additional dependency to your `pom.xml`:
285+
283286
```xml
287+
284288
<dependency>
285289
<groupId>io.quarkus</groupId>
286290
<artifactId>quarkus-resteasy-multipart</artifactId>
287291
</dependency>
288292
```
293+
289294
For any multipart/form-data operation a model for the request body will be generated. Each part of the multipart is a field in this model that is annotated with the following annotations:
290-
- `javax.ws.rs.FormParam`, where the value parameter denotes the part name,
295+
296+
- `javax.ws.rs.FormParam`, where the value parameter denotes the part name,
291297
- `org.jboss.resteasy.annotations.providers.multipart.PartType`, where the parameter is the jax-rs MediaType of the part (see below for details),
292-
- and, if the part contains a file, `org.jboss.resteasy.annotations.providers.multipart.PartFilename`, with a generated default parameter that will be passed as the fileName sub-header in the Content-Disposition header of the part.
298+
- and, if the part contains a file, `org.jboss.resteasy.annotations.providers.multipart.PartFilename`, with a generated default parameter that will be passed as the fileName sub-header in the
299+
Content-Disposition header of the part.
300+
301+
For example, the model for a request that requires a file, a string and some complex object will look like this:
293302

294-
For example, the model for a request that requires a file, a string and some complex object will look like this:
295303
```java
296304
public class MultipartBody {
297305

@@ -311,42 +319,57 @@ public class MultipartBody {
311319
```
312320

313321
Then in the client the `org.jboss.resteasy.annotations.providers.multipart.MultipartForm` annotation is added in front of the multipart parameter:
322+
314323
```java
315324
@Path("/echo")
316325
@RegisterRestClient
317326
public interface MultipartService {
318-
327+
319328
@POST
320329
@Consumes(MediaType.MULTIPART_FORM_DATA)
321330
@Produces(MediaType.TEXT_PLAIN)
322331
String sendMultipartData(@MultipartForm MultipartBody data);
323-
332+
324333
}
325334
```
326-
See [Quarkus - Using the REST Client with Multipart](https://quarkus.io/guides/rest-client-multipart) and the [RESTEasy JAX-RS specifications](https://docs.jboss.org/resteasy/docs/4.7.5.Final/userguide/html_single/index.html) for more details.
327335

328-
Importantly, if some multipart request bodies contain complex objects (i.e. non-primitives) you need to explicitly tell the Open API generator to create models for these objects by setting the `skip-form-model` property corresponding to your spec in the `application.properties` to `false`, e.g.:
336+
See [Quarkus - Using the REST Client with Multipart](https://quarkus.io/guides/rest-client-multipart) and
337+
the [RESTEasy JAX-RS specifications](https://docs.jboss.org/resteasy/docs/4.7.5.Final/userguide/html_single/index.html) for more details.
338+
339+
Importantly, if some multipart request bodies contain complex objects (i.e. non-primitives) you need to explicitly tell the Open API generator to create models for these objects by setting
340+
the `skip-form-model` property corresponding to your spec in the `application.properties` to `false`, e.g.:
341+
329342
```properties
330343
quarkus.openapi-generator.codegen.spec."my-multipart-requests.yml".skip-form-model=false
331344
```
332345

333346
### Default content-types according to OpenAPI Specification and limitations
347+
334348
The [OAS 3.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#special-considerations-for-multipart-content) specifies the following default content-types for a multipart:
349+
335350
- If the property is a primitive, or an array of primitive values, the default Content-Type is `text/plain`
336351
- If the property is complex, or an array of complex values, the default Content-Type is `application/json`
337352
- If the property is a `type: string` with `format: binary` or `format: base64` (aka a file object), the default Content-Type is `application/octet-stream`
338353

339-
A different content-type may be defined in your api spec, but this is not yet supported in the code generation. Also, this "annotation-oriented" approach of RestEasy (i.e. using `@MultipartForm` to denote the multipart body parameter) does not seem to properly support the unmarshalling of arrays of the same type (e.g. array of files), in these cases it uses Content-Type equal to `application/json`.
340-
354+
A different content-type may be defined in your api spec, but this is not yet supported in the code generation. Also, this "annotation-oriented" approach of RestEasy (i.e. using `@MultipartForm` to
355+
denote the multipart body parameter) does not seem to properly support the unmarshalling of arrays of the same type (e.g. array of files), in these cases it uses Content-Type equal
356+
to `application/json`.
341357

342358
## Generating files via InputStream
343359

344-
Having the files in the `src/main/openapi` directory will generate the REST stubs by default. Alternatively, you can implement the `io.quarkiverse.openapi.generator.codegen.OpenApiSpecInputProvider`
360+
Having the files in the `src/main/openapi` directory will generate the REST stubs by default. Alternatively, you can implement the `io.quarkiverse.openapi.generator.deployment.codegen.OpenApiSpecInputProvider`
345361
interface to provide a list of `InputStream`s of OpenAPI specification files. This is useful in scenarios where you want to dynamically generate the client code without having the target spec file
346362
saved locally in your project.
347363

348364
See the example implementation [here](test-utils/src/main/java/io/quarkiverse/openapi/generator/testutils/codegen/ClassPathPetstoreOpenApiSpecInputProvider.java)
349365

366+
## Skip Deprecated Attributes in Model classes
367+
368+
The domain objects are classes generated in the `model` package. These classes might have [deprecated attributes](https://spec.openapis.org/oas/v3.1.0#fixed-fields-9) in the Open API specification
369+
file. By default, these attributes are generated. You can fine tune this behavior if the deprecated attributes should not be generated.
370+
371+
Use the property key `<base_package>.model.MyClass.generateDeprecated=false` to disable the deprecated attributes in the given model. For example `org.acme.weather.Country.generatedDeprecated=false`.
372+
350373
## Known Limitations
351374

352375
These are the known limitations of this pre-release version:

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratedOpenApiFile.java

Lines changed: 0 additions & 17 deletions
This file was deleted.

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratedOpenApiModelBuildItem.java

Lines changed: 0 additions & 17 deletions
This file was deleted.

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/GeneratedOpenApiRestClientBuildItem.java

Lines changed: 0 additions & 17 deletions
This file was deleted.

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/OpenApiGeneratorBuildTimeConfig.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/OpenApiGeneratorProcessor.java

Lines changed: 0 additions & 39 deletions
This file was deleted.

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/SpecConfig.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,21 @@
11
package io.quarkiverse.openapi.generator.deployment;
22

3-
import static io.quarkiverse.openapi.generator.deployment.OpenApiGeneratorBuildTimeConfig.BUILD_TIME_CONFIG_PREFIX;
4-
53
import java.nio.file.Path;
64

7-
import io.quarkus.runtime.annotations.ConfigGroup;
8-
import io.quarkus.runtime.annotations.ConfigItem;
9-
10-
@ConfigGroup
115
public class SpecConfig {
6+
7+
private static final String BUILD_TIME_CONFIG_PREFIX = "quarkus.openapi-generator.codegen";
128
public static final String API_PKG_SUFFIX = ".api";
139
public static final String MODEL_PKG_SUFFIX = ".model";
1410
public static final String BUILD_TIME_SPEC_PREFIX_FORMAT = BUILD_TIME_CONFIG_PREFIX + ".spec.\"%s\"";
1511
private static final String BASE_PACKAGE_PROP_FORMAT = "%s.base-package";
1612
private static final String SKIP_FORM_MODEL_PROP_FORMAT = "%s.skip-form-model";
1713

18-
/**
19-
* Defines the base package name for the generated classes.
20-
*/
21-
@ConfigItem
22-
public String basePackage;
23-
24-
public String getApiPackage() {
14+
public static String resolveApiPackage(final String basePackage) {
2515
return String.format("%s%s", basePackage, API_PKG_SUFFIX);
2616
}
2717

28-
public String getModelPackage() {
18+
public static String resolveModelPackage(final String basePackage) {
2919
return String.format("%s%s", basePackage, MODEL_PKG_SUFFIX);
3020
}
3121

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.quarkiverse.openapi.generator.deployment.codegen;
2+
3+
import static io.quarkiverse.openapi.generator.deployment.SpecConfig.resolveModelPackage;
4+
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.stream.Collectors;
9+
import java.util.stream.StreamSupport;
10+
11+
import org.eclipse.microprofile.config.Config;
12+
13+
/**
14+
* Extracts the Model codegen properties from a given {@link Config} reference.
15+
* These properties are then injected in the OpenAPI generator to tweak the code generation properties.
16+
*/
17+
public final class ModelCodegenConfigParser {
18+
19+
public static Map<String, Object> parse(final Config config, final String basePackage) {
20+
final List<String> modelProperties = filterModelPropertyNames(config.getPropertyNames(),
21+
resolveModelPackage(basePackage));
22+
final Map<String, Object> modelConfig = new HashMap<>();
23+
modelProperties.forEach(m -> {
24+
modelConfig.put(m, config.getValue(m, String.class));
25+
});
26+
return modelConfig;
27+
}
28+
29+
private static List<String> filterModelPropertyNames(final Iterable<String> propertyNames, final String modelPackage) {
30+
return StreamSupport.stream(propertyNames.spliterator(), false)
31+
.filter(propertyName -> propertyName.startsWith(modelPackage))
32+
.collect(Collectors.toList());
33+
}
34+
}

deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,16 @@ public boolean trigger(CodeGenContext context) throws CodeGenException {
5555
}
5656

5757
protected void generate(CodeGenContext context, final Path openApiFilePath, final Path outDir) {
58-
// TODO: do not generate with the output dir has generated files and the openapi file has the same checksum of the previous runz
58+
// TODO: do not generate if the output dir has generated files and the openapi file has the same checksum of the previous run
59+
final String basePackage = getResolvedBasePackageProperty(openApiFilePath);
60+
5961
final OpenApiClientGeneratorWrapper generator = new OpenApiClientGeneratorWrapper(
6062
openApiFilePath.normalize(), outDir)
63+
.withModelCodeGenConfiguration(ModelCodegenConfigParser.parse(context.config(), basePackage))
6164
.withCircuitBreakerConfiguration(CircuitBreakerConfigurationParser.parse(
6265
context.config()));
6366
context.config()
64-
.getOptionalValue(getResolvedBasePackageProperty(openApiFilePath), String.class)
67+
.getOptionalValue(basePackage, String.class)
6568
.ifPresent(generator::withBasePackage);
6669
context.config()
6770
.getOptionalValue(getSkipFormModelPropertyName(openApiFilePath), String.class)

0 commit comments

Comments
 (0)