Skip to content

Commit b915501

Browse files
committed
feature(jackson3) add jackson3 support for spring generator
* add 'useJackson3' option * add 'useSpringBoot4' option * add support for RestClient in spring-http-interfaces * add 'jacksonPackage' template variable set from useJackson3 option See #22294
1 parent 73dcdd6 commit b915501

File tree

179 files changed

+16059
-385
lines changed

Some content is hidden

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

179 files changed

+16059
-385
lines changed

.github/workflows/samples-spring-jdk17.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ on:
44
push:
55
paths:
66
- samples/openapi3/client/petstore/spring-cloud-3-with-optional
7+
- samples/openapi3/client/petstore/spring-cloud-4-with-optional
8+
- samples/client/petstore/spring-http-interface
9+
- samples/client/petstore/spring-http-interface-springboot-4
710
- samples/openapi3/server/petstore/springboot-3
11+
- samples/openapi3/server/petstore/springboot-4
812
- samples/server/petstore/springboot-api-response-examples
913
- samples/server/petstore/springboot-lombok-data
1014
- samples/server/petstore/springboot-lombok-tostring
@@ -15,7 +19,11 @@ on:
1519
pull_request:
1620
paths:
1721
- samples/openapi3/client/petstore/spring-cloud-3-with-optional
22+
- samples/openapi3/client/petstore/spring-cloud-4-with-optional
23+
- samples/client/petstore/spring-http-interface
24+
- samples/client/petstore/spring-http-interface-springboot-4
1825
- samples/openapi3/server/petstore/springboot-3
26+
- samples/openapi3/server/petstore/springboot-4
1927
- samples/server/petstore/springboot-api-response-examples
2028
- samples/server/petstore/springboot-lombok-data
2129
- samples/server/petstore/springboot-lombok-tostring
@@ -33,8 +41,12 @@ jobs:
3341
sample:
3442
# clients
3543
- samples/openapi3/client/petstore/spring-cloud-3-with-optional
44+
- samples/openapi3/client/petstore/spring-cloud-4-with-optional
45+
- samples/client/petstore/spring-http-interface
46+
- samples/client/petstore/spring-http-interface-springboot-4
3647
# servers
3748
- samples/openapi3/server/petstore/springboot-3
49+
- samples/openapi3/server/petstore/springboot-4
3850
- samples/server/petstore/springboot-api-response-examples
3951
- samples/server/petstore/springboot-lombok-data
4052
- samples/server/petstore/springboot-lombok-tostring

bin/configs/spring-boot-4.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
generatorName: spring
2+
outputDir: samples/openapi3/server/petstore/springboot-4
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
5+
additionalProperties:
6+
groupId: org.openapitools.openapi3
7+
documentationProvider: springdoc
8+
artifactId: springboot
9+
snapshotVersion: "true"
10+
useSpringBoot4: true
11+
useJackson3: true
12+
useBeanValidation: true
13+
withXml: true
14+
hideGenerationTimestamp: "true"
15+
generateConstructorWithAllArgs: true
16+
generateBuilders: true
17+
openApiNullable: false
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
generatorName: spring
2+
library: spring-cloud
3+
outputDir: samples/openapi3/client/petstore/spring-cloud-4-with-optional
4+
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
6+
additionalProperties:
7+
groupId: org.openapitools.openapi3
8+
documentationProvider: springdoc
9+
artifactId: spring-cloud-oas4
10+
useSpringBoot4: "true"
11+
useJackson3: true
12+
openApiNullable: false
13+
dateLibrary: "java8"
14+
useOptional: "true"
15+
useSwaggerUI: "false"
16+
hideGenerationTimestamp: "true"
17+
documentationProvider: none
18+
#optionalAcceptNullable: "false" # default to true
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
generatorName: spring
2+
library: spring-http-interface
3+
outputDir: samples/client/petstore/spring-http-interface-springboot-4
4+
inputSpec: modules/openapi-generator/src/test/resources/3_0/spring/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'
11+
generatedConstructorWithRequiredArgs: "false"
12+
# documentation provider should be ignored
13+
documentationProvider: "springdoc"
14+
# annotation provider should be ignored
15+
annotationLibrary: "swagger2"
16+
# validation should be ignored
17+
useBeanValidation: "true"
18+
performBeanValidation: "true"
19+
useSpringBoot4: "true"
20+
useJackson3: true
21+
openApiNullable: false

docs/generators/java-camel.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
107107
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
108108
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
109109
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
110+
|useJackson3|Set it in order to use jackson 3 dependencies (only allowed when `useSpringBoot4` is set and incompatible with `openApiNullable`).| |false|
110111
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
111112
|useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |true|
112113
|useOptional|Use Optional container for optional parameters| |false|
113114
|useResponseEntity|Use the `ResponseEntity` type to wrap return values of generated API methods. If disabled, method are annotated using a `@ResponseStatus` annotation, which has the status of the first response declared in the Api definition| |true|
114115
|useSealed|Whether to generate sealed model interfaces and classes| |false|
115116
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot ≥ 3 (use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
117+
|useSpringBoot4|Generate code and provide dependencies for use with Spring Boot 4.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
116118
|useSpringBuiltInValidation|Disable `@Validated` at the class level when using built-in validation.| |false|
117119
|useSpringController|Annotate the generated API as a Spring Controller| |false|
118120
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|

docs/generators/spring.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,14 @@ These options may be applied as additional-properties (cli) or configOptions (pl
100100
|useEnumCaseInsensitive|Use `equalsIgnoreCase` when String for enum comparison| |false|
101101
|useFeignClientContextId|Whether to generate Feign client with contextId parameter.| |true|
102102
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|
103+
|useJackson3|Set it in order to use jackson 3 dependencies (only allowed when `useSpringBoot4` is set and incompatible with `openApiNullable`).| |false|
103104
|useJakartaEe|whether to use Jakarta EE namespace instead of javax| |false|
104105
|useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |true|
105106
|useOptional|Use Optional container for optional parameters| |false|
106107
|useResponseEntity|Use the `ResponseEntity` type to wrap return values of generated API methods. If disabled, method are annotated using a `@ResponseStatus` annotation, which has the status of the first response declared in the Api definition| |true|
107108
|useSealed|Whether to generate sealed model interfaces and classes| |false|
108109
|useSpringBoot3|Generate code and provide dependencies for use with Spring Boot ≥ 3 (use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
110+
|useSpringBoot4|Generate code and provide dependencies for use with Spring Boot 4.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
109111
|useSpringBuiltInValidation|Disable `@Validated` at the class level when using built-in validation.| |false|
110112
|useSpringController|Annotate the generated API as a Spring Controller| |false|
111113
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|

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

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public class SpringCodegen extends AbstractJavaCodegen
9393
public static final String GENERATE_GENERIC_RESPONSE_ENTITY = "generateGenericResponseEntity";
9494
public static final String USE_ENUM_CASE_INSENSITIVE = "useEnumCaseInsensitive";
9595
public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
96+
public static final String USE_SPRING_BOOT4 = "useSpringBoot4";
9697
public static final String REQUEST_MAPPING_OPTION = "requestMappingMode";
9798
public static final String USE_REQUEST_MAPPING_ON_CONTROLLER = "useRequestMappingOnController";
9899
public static final String USE_REQUEST_MAPPING_ON_INTERFACE = "useRequestMappingOnInterface";
@@ -101,6 +102,10 @@ public class SpringCodegen extends AbstractJavaCodegen
101102
public static final String USE_SPRING_BUILT_IN_VALIDATION = "useSpringBuiltInValidation";
102103
public static final String USE_DEDUCTION_FOR_ONE_OF_INTERFACES = "useDeductionForOneOfInterfaces";
103104
public static final String SPRING_API_VERSION = "springApiVersion";
105+
public static final String USE_JACKSON_3 = "useJackson3";
106+
public static final String JACKSON2_PACKAGE = "com.fasterxml.jackson";
107+
public static final String JACKSON3_PACKAGE = "tools.jackson";
108+
public static final String JACKSON_PACKAGE = "jacksonPackage";
104109

105110
@Getter
106111
public enum RequestMappingMode {
@@ -154,6 +159,8 @@ public enum RequestMappingMode {
154159
@Setter protected boolean useEnumCaseInsensitive = false;
155160
@Getter @Setter
156161
protected boolean useSpringBoot3 = false;
162+
@Getter @Setter
163+
protected boolean useSpringBoot4 = false;
157164
protected boolean generatedConstructorWithRequiredArgs = true;
158165
@Getter @Setter
159166
protected RequestMappingMode requestMappingMode = RequestMappingMode.controller;
@@ -163,6 +170,8 @@ public enum RequestMappingMode {
163170
protected boolean useSpringBuiltInValidation = false;
164171
@Getter @Setter
165172
protected boolean useDeductionForOneOfInterfaces = false;
173+
@Getter @Setter
174+
protected boolean useJackson3 = false;
166175

167176
public SpringCodegen() {
168177
super();
@@ -281,6 +290,10 @@ public SpringCodegen() {
281290
cliOptions.add(CliOption.newBoolean(USE_SPRING_BOOT3,
282291
"Generate code and provide dependencies for use with Spring Boot ≥ 3 (use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.",
283292
useSpringBoot3));
293+
cliOptions.add(CliOption.newBoolean(USE_SPRING_BOOT4,
294+
"Generate code and provide dependencies for use with Spring Boot 4.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.",
295+
useSpringBoot4));
296+
cliOptions.add(CliOption.newBoolean(USE_JACKSON_3, "Set it in order to use jackson 3 dependencies (only allowed when `" + USE_SPRING_BOOT4 + "` is set and incompatible with `"+OPENAPI_NULLABLE+"`).", useJackson3));
284297
cliOptions.add(CliOption.newBoolean(GENERATE_CONSTRUCTOR_WITH_REQUIRED_ARGS,
285298
"Whether to generate constructors with required args for models",
286299
generatedConstructorWithRequiredArgs));
@@ -463,8 +476,13 @@ public void processOpts() {
463476
additionalProperties.put("springHttpStatus", new SpringHttpStatusLambda());
464477

465478
convertPropertyToBooleanAndWriteBack(USE_ENUM_CASE_INSENSITIVE, this::setUseEnumCaseInsensitive);
479+
convertPropertyToBooleanAndWriteBack(USE_JACKSON_3, this::setUseJackson3);
466480
convertPropertyToBooleanAndWriteBack(USE_SPRING_BOOT3, this::setUseSpringBoot3);
467-
if (isUseSpringBoot3()) {
481+
convertPropertyToBooleanAndWriteBack(USE_SPRING_BOOT4, this::setUseSpringBoot4);
482+
if(isUseSpringBoot3() && isUseSpringBoot4()){
483+
throw new IllegalArgumentException("Choose between Spring Boot 3 and Spring Boot 4");
484+
}
485+
if (isUseSpringBoot3() || isUseSpringBoot4()) {
468486
if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) {
469487
throw new IllegalArgumentException(DocumentationProvider.SPRINGFOX.getPropertyName() + " is not supported with Spring Boot > 3.x");
470488
}
@@ -474,15 +492,30 @@ public void processOpts() {
474492
useJakartaEe = true;
475493
applyJakartaPackage();
476494
}
495+
if(isUseJackson3() && !isUseSpringBoot4()){
496+
throw new IllegalArgumentException("useJackson3 is only available with Spring Boot >= 4");
497+
}
498+
if(isUseJackson3() && isOpenApiNullable()){
499+
throw new IllegalArgumentException("openApiNullable cannot be set with useJackson3");
500+
}
501+
if(this.useJackson3){
502+
this.applyJackson3Package();
503+
} else {
504+
this.applyJackson2Package();
505+
}
477506
convertPropertyToStringAndWriteBack(RESOURCE_FOLDER, this::setResourceFolder);
478507

508+
509+
// override parent one
510+
importMapping.put("JsonDeserialize", (useJackson3 ? JACKSON3_PACKAGE : JACKSON2_PACKAGE) + ".databind.annotation.JsonDeserialize");
511+
479512
typeMapping.put("file", "org.springframework.core.io.Resource");
480513
importMapping.put("Nullable", "org.springframework.lang.Nullable");
481514
importMapping.put("org.springframework.core.io.Resource", "org.springframework.core.io.Resource");
482515
importMapping.put("DateTimeFormat", "org.springframework.format.annotation.DateTimeFormat");
483516
importMapping.put("ApiIgnore", "springfox.documentation.annotations.ApiIgnore");
484517
importMapping.put("ParameterObject", "org.springdoc.api.annotations.ParameterObject");
485-
if (isUseSpringBoot3()) {
518+
if (isUseSpringBoot3() || isUseSpringBoot4()) {
486519
importMapping.put("ParameterObject", "org.springdoc.core.annotations.ParameterObject");
487520
}
488521

@@ -491,7 +524,9 @@ public void processOpts() {
491524
additionalProperties.put("delegate-method", true);
492525
}
493526

494-
if (isUseSpringBoot3()) {
527+
if (isUseSpringBoot4()) {
528+
supportingFiles.add(new SupportingFile("pom-sb4.mustache", "", "pom.xml"));
529+
} else if (isUseSpringBoot3()) {
495530
supportingFiles.add(new SupportingFile("pom-sb3.mustache", "", "pom.xml"));
496531
} else {
497532
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
@@ -657,6 +692,14 @@ public void processOpts() {
657692
supportsAdditionalPropertiesWithComposedSchema = true;
658693
}
659694

695+
protected void applyJackson2Package() {
696+
writePropertyBack(JACKSON_PACKAGE, JACKSON2_PACKAGE);
697+
}
698+
699+
protected void applyJackson3Package() {
700+
writePropertyBack(JACKSON_PACKAGE, JACKSON3_PACKAGE);
701+
}
702+
660703
private boolean supportLibraryUseTags() {
661704
return SPRING_BOOT.equals(library) || SPRING_CLOUD_LIBRARY.equals(library);
662705
}

modules/openapi-generator/src/main/resources/JavaSpring/homeController.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import org.springframework.context.annotation.Bean;
44
import org.springframework.stereotype.Controller;
55
import org.springframework.web.bind.annotation.RequestMapping;
66
{{#sourceDocumentationProvider}}
7-
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
7+
import {{jacksonPackage}}.dataformat.yaml.YAMLMapper;
88
import org.springframework.beans.factory.annotation.Value;
99
import org.springframework.core.io.Resource;
1010
import org.springframework.util.StreamUtils;

modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-boot/RFC3339DateFormat.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package {{basePackage}};
22

3-
import com.fasterxml.jackson.databind.util.StdDateFormat;
3+
import {{jacksonPackage}}.databind.util.StdDateFormat;
44

55
import java.text.DateFormat;
66
import java.text.FieldPosition;

modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-boot/application.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
server.port={{serverPort}}
22
spring.jackson.date-format={{basePackage}}.RFC3339DateFormat
3+
{{#useSpringBoot4}}
4+
spring.jackson.datatype.datetime.WRITE_DATES_AS_TIMESTAMPS=false
5+
{{/useSpringBoot4}}
6+
{{^useSpringBoot4}}
37
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
8+
{{/useSpringBoot4}}
49
{{#virtualService}}
510
virtualan.datasource.driver-class-name=org.hsqldb.jdbcDriver
611
virtualan.datasource.jdbcurl=jdbc:hsqldb:mem:dataSource

0 commit comments

Comments
 (0)