From be5de892296407d69b97d4d15ce79025f546b3a1 Mon Sep 17 00:00:00 2001 From: Ignacio Vidal Date: Wed, 1 Jul 2026 01:02:04 +0100 Subject: [PATCH 1/3] [jaxrs-spec] Support useRecords Adds a useRecords option to the jaxrs-spec generator. When useRecords=true, the concrete subtypes that implement a generated oneOf interface render as Java records instead of mutable classes. - JavaJAXRSSpecServerCodegen: useRecords option, and postProcessAllModels marks record-eligible implementors with x-jaxrs-record (no parent, no additional properties, implements a generated oneOf interface). - record.mustache renders the record; model.mustache routes x-jaxrs-record to it. - oneof_interface.mustache declares the discriminator accessor in record style (petType()) under useRecords so records satisfy the interface via their canonical accessors; sealed.mustache no longer marks a record final. - pom.mustache bumps java.version to 17 when useRecords (records need JDK 16+). - Adds testOneOfRecordImplementationGeneration and a jaxrs-spec-records sample (registered in the JDK17 samples workflow). useRecords is independent of useSealed. The feature stays opt-in; default jaxrs-spec output is unchanged. --- .github/workflows/samples-jdk17.yaml | 3 + bin/configs/jaxrs-spec-records.yaml | 10 ++ docs/generators/jaxrs-cxf-cdi.md | 1 + docs/generators/jaxrs-spec.md | 1 + .../languages/JavaJAXRSSpecServerCodegen.java | 68 +++++++- .../resources/JavaJaxRS/spec/model.mustache | 2 +- .../JavaJaxRS/spec/oneof_interface.mustache | 2 +- .../resources/JavaJaxRS/spec/pom.mustache | 2 +- .../resources/JavaJaxRS/spec/record.mustache | 64 ++++++++ .../resources/JavaJaxRS/spec/sealed.mustache | 2 +- .../jaxrs/JavaJAXRSSpecServerCodegenTest.java | 132 ++++++++++++++++ .../.openapi-generator-ignore | 23 +++ .../.openapi-generator/FILES | 11 ++ .../.openapi-generator/VERSION | 1 + .../petstore/jaxrs-spec-records/README.md | 27 ++++ .../petstore/jaxrs-spec-records/pom.xml | 149 ++++++++++++++++++ .../java/org/openapitools/api/PetsApi.java | 33 ++++ .../org/openapitools/api/RestApplication.java | 9 ++ .../openapitools/api/RestResourceRoot.java | 5 + .../org/openapitools/model/CatRequest.java | 27 ++++ .../org/openapitools/model/DogRequest.java | 27 ++++ .../java/org/openapitools/model/PetBase.java | 114 ++++++++++++++ .../org/openapitools/model/PetRequest.java | 29 ++++ .../java/org/openapitools/model/PetType.java | 58 +++++++ .../src/main/openapi/openapi.yaml | 78 +++++++++ 25 files changed, 868 insertions(+), 10 deletions(-) create mode 100644 bin/configs/jaxrs-spec-records.yaml create mode 100644 modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache create mode 100644 samples/server/petstore/jaxrs-spec-records/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-records/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-records/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-records/README.md create mode 100644 samples/server/petstore/jaxrs-spec-records/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-records/src/main/openapi/openapi.yaml diff --git a/.github/workflows/samples-jdk17.yaml b/.github/workflows/samples-jdk17.yaml index e4ea6b9d299c..82d57c817434 100644 --- a/.github/workflows/samples-jdk17.yaml +++ b/.github/workflows/samples-jdk17.yaml @@ -23,6 +23,7 @@ on: - samples/server/petstore/java-helidon-server/v3/mp/** - samples/server/petstore/java-helidon-server/v3/se/** - samples/server/petstore/jaxrs-spec-sealed/** + - samples/server/petstore/jaxrs-spec-records/** pull_request: paths: # clients @@ -46,6 +47,7 @@ on: - samples/server/petstore/java-helidon-server/v3/mp/** - samples/server/petstore/java-helidon-server/v3/se/** - samples/server/petstore/jaxrs-spec-sealed/** + - samples/server/petstore/jaxrs-spec-records/** jobs: build: name: Build with JDK17 @@ -75,6 +77,7 @@ jobs: - samples/server/petstore/java-helidon-server/v3/mp/ - samples/server/petstore/java-helidon-server/v3/se - samples/server/petstore/jaxrs-spec-sealed + - samples/server/petstore/jaxrs-spec-records steps: - uses: actions/checkout@v7 - uses: actions/setup-java@v5 diff --git a/bin/configs/jaxrs-spec-records.yaml b/bin/configs/jaxrs-spec-records.yaml new file mode 100644 index 000000000000..75b343f107e2 --- /dev/null +++ b/bin/configs/jaxrs-spec-records.yaml @@ -0,0 +1,10 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-records +inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec +additionalProperties: + artifactId: jaxrs-spec-records-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + useRecords: "true" + hideGenerationTimestamp: "true" diff --git a/docs/generators/jaxrs-cxf-cdi.md b/docs/generators/jaxrs-cxf-cdi.md index d7be87c2a622..9992b0356ee3 100644 --- a/docs/generators/jaxrs-cxf-cdi.md +++ b/docs/generators/jaxrs-cxf-cdi.md @@ -87,6 +87,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |useMicroProfileOpenAPIAnnotations|Whether to generate Microprofile OpenAPI annotations. Only valid when library is set to quarkus.| |false| |useMutiny|Whether to use Smallrye Mutiny instead of CompletionStage for asynchronous computation. Only valid when library is set to quarkus.| |false| |useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |false| +|useRecords|Whether to render the implementations of a generated oneOf interface (useOneOfInterfaces=true) as Java records instead of classes (requires Java 17 and useSealed=true). All other models, including inheritance participants and models with additionalProperties, remain classes. Cannot be combined with withXml.| |false| |useSealed|Whether to generate sealed model interfaces and classes.| |false| |useSwaggerAnnotations|Whether to generate Swagger annotations.| |true| |useSwaggerV3Annotations|Whether to generate Swagger v3 (OpenAPI v3) annotations.| |false| diff --git a/docs/generators/jaxrs-spec.md b/docs/generators/jaxrs-spec.md index c3bb79c787cc..51c6b19d2374 100644 --- a/docs/generators/jaxrs-spec.md +++ b/docs/generators/jaxrs-spec.md @@ -88,6 +88,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |useMicroProfileOpenAPIAnnotations|Whether to generate Microprofile OpenAPI annotations. Only valid when library is set to quarkus.| |false| |useMutiny|Whether to use Smallrye Mutiny instead of CompletionStage for asynchronous computation. Only valid when library is set to quarkus.| |false| |useOneOfInterfaces|whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface| |false| +|useRecords|Whether to render the implementations of a generated oneOf interface (useOneOfInterfaces=true) as Java records instead of classes (requires Java 17 and useSealed=true). All other models, including inheritance participants and models with additionalProperties, remain classes. Cannot be combined with withXml.| |false| |useSealed|Whether to generate sealed model interfaces and classes.| |false| |useSwaggerAnnotations|Whether to generate Swagger annotations.| |true| |useSwaggerV3Annotations|Whether to generate Swagger v3 (OpenAPI v3) annotations.| |false| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java index a19abc67b903..e4038d5f9ed2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java @@ -34,8 +34,10 @@ import java.io.File; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import static org.openapitools.codegen.languages.features.GzipFeatures.USE_GZIP_FEATURE; @@ -60,6 +62,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen { public static final String USE_JAKARTA_SECURITY_ANNOTATIONS = "useJakartaSecurityAnnotations"; public static final String USE_ENUM_CASE_INSENSITIVE = "useEnumCaseInsensitive"; public static final String USE_SEALED = "useSealed"; + public static final String USE_RECORDS = "useRecords"; public static final String QUARKUS_LIBRARY = "quarkus"; public static final String THORNTAIL_LIBRARY = "thorntail"; @@ -83,6 +86,9 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen { @Setter protected boolean useSealed = false; + @Setter + protected boolean useRecords = false; + private final JakartaSecurityAnnotationProcessor jakartaSecurityAnnotationProcessor = new JakartaSecurityAnnotationProcessor(); @Getter @Setter @@ -167,6 +173,7 @@ public JavaJAXRSSpecServerCodegen() { cliOptions.add(CliOption.newBoolean(GENERATE_JSON_CREATOR, "Whether to generate @JsonCreator constructor for required properties.", generateJsonCreator)); cliOptions.add(CliOption.newBoolean(USE_ENUM_CASE_INSENSITIVE, "Use `equalsIgnoreCase` when String for enum comparison", useEnumCaseInsensitive)); cliOptions.add(CliOption.newBoolean(USE_SEALED, "Whether to generate sealed model interfaces and classes.", useSealed)); + cliOptions.add(CliOption.newBoolean(USE_RECORDS, "Whether to render the implementations of a generated oneOf interface (useOneOfInterfaces=true) as Java records instead of classes (requires Java 17 and useSealed=true). All other models, including inheritance participants and models with additionalProperties, remain classes. Cannot be combined with withXml.", useRecords)); } @Override @@ -211,6 +218,7 @@ public void processOpts() { convertPropertyToBooleanAndWriteBack(GENERATE_JSON_CREATOR, this::setGenerateJsonCreator); convertPropertyToBooleanAndWriteBack(USE_ENUM_CASE_INSENSITIVE, this::setUseEnumCaseInsensitive); convertPropertyToBooleanAndWriteBack(USE_SEALED, this::setUseSealed); + convertPropertyToBooleanAndWriteBack(USE_RECORDS, this::setUseRecords); if (additionalProperties.containsKey(OPEN_API_SPEC_FILE_LOCATION)) { openApiSpecFileLocation = additionalProperties.get(OPEN_API_SPEC_FILE_LOCATION).toString(); @@ -234,6 +242,13 @@ public void processOpts() { convertPropertyToBooleanAndWriteBack(USE_JAKARTA_SECURITY_ANNOTATIONS, value -> useJakartaSecurityAnnotations = value); } + if (useRecords && withXml) { + throw new IllegalArgumentException( + "Flag '" + USE_RECORDS + "' cannot be combined with '" + WITH_XML + + "': JAXB binding requires mutable JavaBeans with a no-argument " + + "constructor, which records cannot provide."); + } + if (useJakartaSecurityAnnotations && !useJakartaEe) { throw new IllegalArgumentException( "Flag '" + USE_JAKARTA_SECURITY_ANNOTATIONS + "' requires '" + USE_JAKARTA_EE @@ -400,16 +415,20 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List postProcessAllModels(Map objs) { Map result = super.postProcessAllModels(objs); - // Index the discriminators of the generated oneOf interfaces by classname. A child of a oneOf - // interface (useOneOfInterfaces) inherits a shared base via allOf and therefore has no Java - // parentModel carrying the discriminator - the discriminator lives on the interface it implements. + // Collect, for the interfaces generated by the useOneOfInterfaces feature: their classnames (to + // identify which concrete models implement one of them and are therefore record candidates) and + // their discriminators indexed by classname (a child of a oneOf interface inherits a shared base + // via allOf and has no Java parentModel carrying the discriminator - it lives on the interface). + Set oneOfInterfaceNames = new HashSet<>(); Map oneOfInterfaceDiscriminators = new HashMap<>(); for (ModelsMap modelsMap : result.values()) { for (ModelMap modelMap : modelsMap.getModels()) { CodegenModel model = modelMap.getModel(); - if (Boolean.TRUE.equals(model.getVendorExtensions().get("x-is-one-of-interface")) - && model.getDiscriminator() != null) { - oneOfInterfaceDiscriminators.put(model.classname, model.getDiscriminator()); + if (Boolean.TRUE.equals(model.getVendorExtensions().get("x-is-one-of-interface"))) { + oneOfInterfaceNames.add(model.classname); + if (model.getDiscriminator() != null) { + oneOfInterfaceDiscriminators.put(model.classname, model.getDiscriminator()); + } } } } @@ -437,6 +456,9 @@ public Map postProcessAllModels(Map objs) if (useSealed && !Boolean.TRUE.equals(model.getVendorExtensions().get("x-is-one-of-interface"))) { model.permits.removeAll(model.oneOf); } + if (useRecords && useSealed && isOneOfInterfaceRecordCandidate(model, oneOfInterfaceNames)) { + model.getVendorExtensions().put("x-jaxrs-record", true); + } } } return result; @@ -463,6 +485,40 @@ private CodegenDiscriminator discriminatorOfImplementedOneOfInterface( return null; } + /** + * A model is rendered as a record when it implements one of the interfaces generated by the + * useOneOfInterfaces feature and is structurally record-compatible: it is not an enum, has no Java + * parent and no subclasses (records can neither extend nor be extended), carries no additional + * (undeclared) properties (those require a mutable map-backed pojo), and is not itself a oneOf/anyOf + * container. Models outside a oneOf interface hierarchy - ordinary pojos, inheritance participants + * and map-backed models - are deliberately left untouched. + * + * @param model the concrete model that may implement a oneOf interface + * @param oneOfInterfaceNames the classnames of the generated oneOf interfaces + * @return {@code true} when the model should be rendered as a record + */ + @SuppressWarnings("unchecked") + private boolean isOneOfInterfaceRecordCandidate(CodegenModel model, Set oneOfInterfaceNames) { + if (model.isEnum + || model.getParent() != null + || model.hasChildren + || model.getAdditionalPropertiesType() != null + || (model.oneOf != null && !model.oneOf.isEmpty()) + || (model.anyOf != null && !model.anyOf.isEmpty())) { + return false; + } + Object implementsExtension = model.getVendorExtensions().get("x-implements"); + if (!(implementsExtension instanceof Collection)) { + return false; + } + for (Object intf : (Collection) implementsExtension) { + if (oneOfInterfaceNames.contains(String.valueOf(intf))) { + return true; + } + } + return false; + } + @Override public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, List servers) { CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/model.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/model.mustache index 6060ce15d2ed..89bf0a6e6619 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/model.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/model.mustache @@ -16,6 +16,6 @@ import {{javaxPackage}}.validation.Valid; {{>enumOuterClass}} {{/isEnum}} -{{^isEnum}}{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}}{{/isEnum}} +{{^isEnum}}{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{#vendorExtensions.x-jaxrs-record}}{{>record}}{{/vendorExtensions.x-jaxrs-record}}{{^vendorExtensions.x-jaxrs-record}}{{>pojo}}{{/vendorExtensions.x-jaxrs-record}}{{/vendorExtensions.x-is-one-of-interface}}{{/isEnum}} {{/model}} {{/models}} diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/oneof_interface.mustache index 34d601b12c5f..c67ad8ec52cc 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/oneof_interface.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/oneof_interface.mustache @@ -16,6 +16,6 @@ public {{>sealed}}interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {{>permits}}{ {{#discriminator}} - {{propertyType}} {{propertyGetter}}(); + {{propertyType}} {{#useSealed}}{{#useRecords}}{{propertyName}}{{/useRecords}}{{^useRecords}}{{propertyGetter}}{{/useRecords}}{{/useSealed}}{{^useSealed}}{{propertyGetter}}{{/useSealed}}(); {{/discriminator}} } diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pom.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pom.mustache index 8640e276e9ee..2ba823155c7b 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pom.mustache @@ -184,7 +184,7 @@ {{/openApiNullable}} - {{#useSealed}}17{{/useSealed}}{{^useSealed}}1.8{{/useSealed}} + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} ${java.version} ${java.version} UTF-8 diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache new file mode 100644 index 000000000000..22430e7affd9 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache @@ -0,0 +1,64 @@ +{{#useSwaggerAnnotations}} +import io.swagger.annotations.*; +{{/useSwaggerAnnotations}} +{{#useSwaggerV3Annotations}} +import io.swagger.v3.oas.annotations.media.Schema; +{{/useSwaggerV3Annotations}} +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; +{{/jackson}} +{{#withXml}} +import {{javaxPackage}}.xml.bind.annotation.XmlElement; +import {{javaxPackage}}.xml.bind.annotation.XmlRootElement; +import {{javaxPackage}}.xml.bind.annotation.XmlAccessType; +import {{javaxPackage}}.xml.bind.annotation.XmlAccessorType; +import {{javaxPackage}}.xml.bind.annotation.XmlType; +import {{javaxPackage}}.xml.bind.annotation.XmlEnum; +import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue; +{{/withXml}} + +{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/** + * {{.}} + {{#isDeprecated}} + * @deprecated + {{/isDeprecated}} + **/{{/description}} +{{#isDeprecated}} +@Deprecated + +{{/isDeprecated}}{{#useSwaggerAnnotations}}{{#description}}@ApiModel(description = "{{{.}}}"){{/description}}{{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}} +@Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}{{#isDeprecated}}, deprecated = true{{/isDeprecated}}){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}} +@org.eclipse.microprofile.openapi.annotations.media.Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}{{#isDeprecated}}, deprecated = true{{/isDeprecated}}){{/useMicroProfileOpenAPIAnnotations}} +{{#jackson}} +@JsonTypeName("{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}") +{{/jackson}} +{{>generatedAnnotation}}{{>additionalModelTypeAnnotations}} +{{#vendorExtensions.x-class-extra-annotation}} +{{{vendorExtensions.x-class-extra-annotation}}} +{{/vendorExtensions.x-class-extra-annotation}} +public {{>sealed}}record {{classname}}( + {{#vars}} + {{#vendorExtensions.x-field-extra-annotation}} + {{{.}}} + {{/vendorExtensions.x-field-extra-annotation}} + {{#deprecated}} + @Deprecated + {{/deprecated}} + {{#jackson}}@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}") {{/jackson}}{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}{{{datatypeWithEnum}}} {{name}}{{^-last}},{{/-last}} + {{/vars}} +) {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { + {{#vars}} + {{#isEnum}} + {{^isContainer}} + {{>enumClass}}{{! prevent indent}} + {{/isContainer}} + {{#isContainer}} + {{#mostInnerItems}} + {{>enumClass}}{{! prevent indent}} + {{/mostInnerItems}} + {{/isContainer}} + {{/isEnum}} + {{/vars}} +} diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache index a5c0af002702..6c860355c15f 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache @@ -1 +1 @@ -{{#useSealed}}{{#permits.0}}sealed {{/permits.0}}{{^permits.0}}{{^vendorExtensions.x-is-one-of-interface}}final {{/vendorExtensions.x-is-one-of-interface}}{{/permits.0}}{{/useSealed}} \ No newline at end of file +{{#useSealed}}{{#permits.0}}sealed {{/permits.0}}{{^permits.0}}{{^vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-jaxrs-record}}final {{/vendorExtensions.x-jaxrs-record}}{{/vendorExtensions.x-is-one-of-interface}}{{/permits.0}}{{/useSealed}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java index 2e5b97cb646f..d52fa316fd4b 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java @@ -1630,6 +1630,138 @@ public void testWithoutUseSealedOutputIsUnchanged() throws Exception { assertFileContains(Paths.get(outputDir + "/pom.xml"), "1.8"); } + /** + * With {@code useRecords=true} the concrete subtypes of a generated oneOf interface render as Java + * records rather than mutable classes. Because a record component {@code petType} exposes the + * canonical accessor {@code petType()} (not {@code getPetType()}), the interface declares the + * discriminator accessor in record style so the records satisfy it without bridge methods. The + * record components carry the {@code @JsonProperty} annotations. Combined here with + * {@code useSealed=true} so the interface is also sealed and permits the record subtypes. + */ + @Test + public void testOneOfRecordImplementationGeneration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useSealed", "true"); + properties.put("useRecords", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(configurator.toClientOptInput()).generate(); + + // assertFileContains is used rather than JavaFileAssert because the latter parses the source + // with a JavaParser language level that predates sealed/record types. + String modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + // The interface is sealed, permits the record subtypes, and declares the discriminator accessor + // in record style (petType(), not getPetType()) so the records implement it via their canonical + // accessors. + assertFileContains(Paths.get(modelDir + "PetRequest.java"), + "public sealed interface PetRequest", + "permits CatRequest, DogRequest", + "PetType petType();"); + assertFileNotContains(Paths.get(modelDir + "PetRequest.java"), "getPetType"); + + // The concrete subtypes are records implementing (not extending) the interface, with @JsonProperty + // on the components and no JavaBean getters or final-class declaration. + assertFileContains(Paths.get(modelDir + "CatRequest.java"), + "public record CatRequest(", + "@JsonProperty(required = true, value = \"petType\")", + "PetType petType", + "implements PetRequest"); + assertFileNotContains(Paths.get(modelDir + "CatRequest.java"), + "class CatRequest", "extends PetRequest", "public PetType getPetType()"); + + assertFileContains(Paths.get(modelDir + "DogRequest.java"), + "public record DogRequest(", + "implements PetRequest"); + assertFileNotContains(Paths.get(modelDir + "DogRequest.java"), + "class DogRequest", "extends PetRequest"); + } + + /** + * Records require {@code useSealed=true}: with {@code useRecords} alone the oneOf interface + * implementations stay classes, and the interface must keep the {@code get}-prefixed accessor those + * classes implement - declaring {@code petType()} against JavaBean classes would not compile. + */ + @Test + public void testUseRecordsWithoutUseSealedKeepsClasses() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useRecords", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(configurator.toClientOptInput()).generate(); + + String modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + assertFileContains(Paths.get(modelDir + "CatRequest.java"), "class CatRequest"); + assertFileNotContains(Paths.get(modelDir + "CatRequest.java"), "public record CatRequest("); + // The interface accessor must match the classes that implement it. + assertFileContains(Paths.get(modelDir + "PetRequest.java"), "getPetType();"); + } + + /** + * Only the implementations of a generated oneOf interface become records. Models outside that + * hierarchy - here the shared allOf base, which is an ordinary standalone pojo - stay classes. + */ + @Test + public void testRecordsAreScopedToOneOfInterfaceImplementations() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useSealed", "true"); + properties.put("useRecords", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(configurator.toClientOptInput()).generate(); + + String modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + // PetBase does not implement the oneOf interface and is left as a class. + assertFileContains(Paths.get(modelDir + "PetBase.java"), "class PetBase"); + assertFileNotContains(Paths.get(modelDir + "PetBase.java"), "record PetBase"); + // The enum is never a record candidate. + assertFileContains(Paths.get(modelDir + "PetType.java"), "public enum PetType"); + } + + /** + * {@code useRecords} cannot be combined with {@code withXml}: JAXB binding requires mutable + * JavaBeans with a no-argument constructor, which records cannot provide. + */ + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*useRecords.*withXml.*") + public void useRecordsRejectsWithXml() { + codegen.additionalProperties().put(USE_RECORDS, true); + codegen.additionalProperties().put("withXml", true); + codegen.processOpts(); + } + @Test public void testGenerateJsonNullableListFieldsHelperMethodReferences_issue23251() throws Exception { Map properties = new HashMap<>(); diff --git a/samples/server/petstore/jaxrs-spec-records/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-records/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/jaxrs-spec-records/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-records/.openapi-generator/FILES new file mode 100644 index 000000000000..a83382320388 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/.openapi-generator/FILES @@ -0,0 +1,11 @@ +README.md +pom.xml +src/gen/java/org/openapitools/api/PetsApi.java +src/gen/java/org/openapitools/api/RestApplication.java +src/gen/java/org/openapitools/api/RestResourceRoot.java +src/gen/java/org/openapitools/model/CatRequest.java +src/gen/java/org/openapitools/model/DogRequest.java +src/gen/java/org/openapitools/model/PetBase.java +src/gen/java/org/openapitools/model/PetRequest.java +src/gen/java/org/openapitools/model/PetType.java +src/main/openapi/openapi.yaml diff --git a/samples/server/petstore/jaxrs-spec-records/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-records/.openapi-generator/VERSION new file mode 100644 index 000000000000..8fc8df61083a --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.25.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-records/README.md b/samples/server/petstore/jaxrs-spec-records/README.md new file mode 100644 index 000000000000..b9d190efc443 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/README.md @@ -0,0 +1,27 @@ +# JAX-RS server with OpenAPI + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an +[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. + +This is an example of building a OpenAPI-enabled JAX-RS server. +This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework. + + +The JAX-RS implementation needs to be provided by the application server you are deploying on. + +To run the server from the command line, you can use maven to provision and start a TomEE Server. +Please execute the following: + +``` +mvn -Dtomee-embedded-plugin.http=8080 package org.apache.tomee.maven:tomee-embedded-maven-plugin:7.0.5:run +``` + +You can then call your server endpoints under: + +``` +http://localhost:8080/ +``` + +Note that if you have configured the `host` to be something other than localhost, the calls through +swagger-ui will be directed to that host and not localhost! diff --git a/samples/server/petstore/jaxrs-spec-records/pom.xml b/samples/server/petstore/jaxrs-spec-records/pom.xml new file mode 100644 index 000000000000..53ce216da478 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/pom.xml @@ -0,0 +1,149 @@ + + 4.0.0 + org.openapitools + jaxrs-spec-records-petstore-server + war + jaxrs-spec-records-petstore-server + 1.0.0 + + + + src/main/java + + + org.codehaus.mojo + build-helper-maven-plugin + 1.9.1 + + + add-source + generate-sources + + add-source + + + + src/gen/java + + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + false + + + + maven-surefire-plugin + 3.5.6 + + + maven-failsafe-plugin + 3.5.6 + + + + integration-test + verify + + + + + + + + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta.ws.rs-version} + provided + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson-version} + + + joda-time + joda-time + ${joda-version} + + + javax.annotation + javax.annotation-api + ${javax.annotation-api-version} + + + io.swagger + swagger-annotations + provided + 1.5.3 + + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + org.junit.jupiter + junit-jupiter-engine + ${junit-version} + test + + + org.testng + testng + 6.8.8 + test + + + junit + junit + + + snakeyaml + org.yaml + + + bsh + org.beanshell + + + + + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + provided + + + org.openapitools + jackson-databind-nullable + ${jackson-databind-nullable-version} + + + + 17 + ${java.version} + ${java.version} + UTF-8 + 2.21.5 + 5.14.4 + 2.10.13 + 1.3.2 + 2.0.2 + 2.1.6 + 0.2.11 + + diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..72e76513cd26 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/PetsApi.java @@ -0,0 +1,33 @@ +package org.openapitools.api; + +import org.openapitools.model.PetRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + +import io.swagger.annotations.*; + +import java.io.InputStream; +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +import javax.validation.Valid; + +/** +* Represents a collection of functions to interact with the API endpoints. +*/ +@Path("/pets") +@Api(description = "the pets API") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public class PetsApi { + + @POST + @Consumes({ "application/json" }) + @ApiOperation(value = "", notes = "", response = Void.class, tags={ }) + @ApiResponses(value = { + @ApiResponse(code = 201, message = "created", response = Void.class) + }) + public Response createPet(@Valid @NotNull PetRequest petRequest) { + return Response.ok().entity("magic!").build(); + } +} diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestApplication.java @@ -0,0 +1,9 @@ +package org.openapitools.api; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath(RestResourceRoot.APPLICATION_PATH) +public class RestApplication extends Application { + +} diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/api/RestResourceRoot.java @@ -0,0 +1,5 @@ +package org.openapitools.api; + +public class RestResourceRoot { + public static final String APPLICATION_PATH = ""; +} diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..5e5fb5689840 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record CatRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..9fd07e5db6e9 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record DogRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "trained") @NotNull Boolean trained +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..604a218725a6 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetBase.java @@ -0,0 +1,114 @@ +package org.openapitools.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import io.swagger.annotations.*; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; +import org.openapitools.jackson.nullable.JsonNullable; + + + +@JsonTypeName("PetBase") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public final class PetBase { + private PetType petType; + private String name; + + public PetBase() { + } + + @JsonCreator + public PetBase( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name + ) { + this.petType = petType; + this.name = name; + } + + /** + **/ + public PetBase petType(PetType petType) { + this.petType = petType; + return this; + } + + + @ApiModelProperty(required = true, value = "") + @JsonProperty(required = true, value = "petType") + @NotNull public PetType getPetType() { + return petType; + } + + @JsonProperty(required = true, value = "petType") + public void setPetType(PetType petType) { + this.petType = petType; + } + + /** + **/ + public PetBase name(String name) { + this.name = name; + return this; + } + + + @ApiModelProperty(required = true, value = "") + @JsonProperty(required = true, value = "name") + @NotNull public String getName() { + return name; + } + + @JsonProperty(required = true, value = "name") + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetBase petBase = (PetBase) o; + return Objects.equals(this.petType, petBase.petType) && + Objects.equals(this.name, petBase.name); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetBase {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + +} diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..e48a7e1f76a0 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,29 @@ +package org.openapitools.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.openapitools.model.CatRequest; +import org.openapitools.model.DogRequest; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@JsonIgnoreProperties( + value = "petType", // ignore manually set petType, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the petType to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRequest.class, name = "CAT"), + @JsonSubTypes.Type(value = DogRequest.class, name = "DOG"), +}) + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public sealed interface PetRequest permits CatRequest, DogRequest { + PetType petType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..696f45a7e2a1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/PetType.java @@ -0,0 +1,58 @@ +package org.openapitools.model; + +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Discriminator value identifying the type of pet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public enum PetType { + + CAT("CAT"), + + DOG("DOG"); + + private String value; + + PetType(String value) { + this.value = value; + } + + /** + * Convert a String into String, as specified in the + * See JAX RS 2.0 Specification, section 3.2, p. 12 + */ + public static PetType fromString(String s) { + for (PetType b : PetType.values()) { + // using Objects.toString() to be safe if value type non-object type + // because types like 'int' etc. will be auto-boxed + if (java.util.Objects.toString(b.value).equals(s)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected string value '" + s + "'"); + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PetType fromValue(String value) { + for (PetType b : PetType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + diff --git a/samples/server/petstore/jaxrs-spec-records/src/main/openapi/openapi.yaml b/samples/server/petstore/jaxrs-spec-records/src/main/openapi/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/main/openapi/openapi.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.3 +info: + description: | + A oneOf interface whose subtypes inherit shared properties from a base schema (acyclic pattern). The discriminator property is declared on the oneOf container and on the shared base the subtypes inherit via allOf, so the interface getter type resolves to the enum from the container's own properties. + title: oneOf interface + version: 1.0.0 +servers: +- url: / +paths: + /pets: + post: + operationId: createPet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PetRequest" + required: true + responses: + "201": + description: created + x-content-type: application/json + x-accepts: + - application/json +components: + schemas: + PetType: + description: Discriminator value identifying the type of pet + enum: + - CAT + - DOG + type: string + PetRequest: + discriminator: + mapping: + CAT: "#/components/schemas/CatRequest" + DOG: "#/components/schemas/DogRequest" + propertyName: petType + example: + petType: CAT + oneOf: + - $ref: "#/components/schemas/CatRequest" + - $ref: "#/components/schemas/DogRequest" + properties: + petType: + $ref: "#/components/schemas/PetType" + type: object + x-one-of-name: PetRequest + PetBase: + properties: + petType: + $ref: "#/components/schemas/PetType" + name: + type: string + required: + - name + - petType + type: object + CatRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + indoor: + type: boolean + required: + - indoor + type: object + type: object + DogRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + trained: + type: boolean + required: + - trained + type: object + type: object From e621e73f5d88fc3461ddf973f3c2acca474362ac Mon Sep 17 00:00:00 2001 From: Ignacio Vidal Date: Sat, 11 Jul 2026 14:00:14 +0100 Subject: [PATCH 2/3] [jaxrs-spec] Bring useRecords records to pojo feature parity Records stay scoped to the implementations of a generated oneOf interface (useOneOfInterfaces=true) and now additionally require useSealed=true. Models outside that hierarchy - ordinary pojos, inheritance participants and models with additionalProperties - are left untouched and keep rendering as classes. Brings record.mustache to feature parity with pojo.mustache for the records that are emitted: - defaults (scalar, enum, container) applied in a compact canonical constructor - x-is-jackson-optional-nullable properties render as JsonNullable components defaulting to undefined - byte[] properties get content-based equals/hashCode overrides (the implicit record equals compares arrays by reference) - password properties are masked in an explicit toString override - property doc annotations (@ApiModelProperty/@Schema/MicroProfile @Schema) emitted on the record components - generateBuilders produces a flat builder inside the record carrying the pojo field defaults, as a fluent replacement for setters - useRecords + withXml is rejected (JAXB requires mutable JavaBeans) The oneOf interface only drops the get-prefix from its accessor when records are actually emitted (useRecords and useSealed), so with useRecords alone the interface keeps getX() and still matches the classes implementing it. --- .../languages/JavaJAXRSSpecServerCodegen.java | 16 ++ .../resources/JavaJaxRS/spec/record.mustache | 116 ++++++++++++-- .../jaxrs/JavaJAXRSSpecServerCodegenTest.java | 113 ++++++++++++- .../3_0/jaxrs-spec/records_parity.yaml | 151 ++++++++++++++++++ .../org/openapitools/model/CatRequest.java | 5 + .../org/openapitools/model/DogRequest.java | 5 + 6 files changed, 394 insertions(+), 12 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/records_parity.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java index e4038d5f9ed2..7604dd51a95d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java @@ -458,6 +458,22 @@ public Map postProcessAllModels(Map objs) } if (useRecords && useSealed && isOneOfInterfaceRecordCandidate(model, oneOfInterfaceNames)) { model.getVendorExtensions().put("x-jaxrs-record", true); + // Records have no field initializers: defaults (and the JsonNullable undefined + // state) must be applied in a compact canonical constructor. + if (model.vars.stream().anyMatch(v -> v.defaultValue != null + || Boolean.TRUE.equals(v.getVendorExtensions().get("x-is-jackson-optional-nullable")))) { + model.getVendorExtensions().put("x-jaxrs-record-has-defaults", true); + } + // The implicit record equals/hashCode compares arrays by reference; mirror the + // pojo's Arrays.equals/hashCode semantics for byte[] properties. + if (model.vars.stream().anyMatch(v -> v.isByteArray)) { + model.getVendorExtensions().put("x-jaxrs-record-has-byte-array", true); + } + // The implicit record toString prints component values; mask password properties + // like the pojo does. + if (model.vars.stream().anyMatch(v -> v.isPassword)) { + model.getVendorExtensions().put("x-jaxrs-record-has-password", true); + } } } } diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache index 22430e7affd9..4f267830b248 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache @@ -4,20 +4,18 @@ import io.swagger.annotations.*; {{#useSwaggerV3Annotations}} import io.swagger.v3.oas.annotations.media.Schema; {{/useSwaggerV3Annotations}} +{{#vendorExtensions.x-jaxrs-record-has-byte-array}} +import java.util.Objects; +{{/vendorExtensions.x-jaxrs-record-has-byte-array}} {{#jackson}} import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonTypeName; {{/jackson}} -{{#withXml}} -import {{javaxPackage}}.xml.bind.annotation.XmlElement; -import {{javaxPackage}}.xml.bind.annotation.XmlRootElement; -import {{javaxPackage}}.xml.bind.annotation.XmlAccessType; -import {{javaxPackage}}.xml.bind.annotation.XmlAccessorType; -import {{javaxPackage}}.xml.bind.annotation.XmlType; -import {{javaxPackage}}.xml.bind.annotation.XmlEnum; -import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue; -{{/withXml}} +{{#openApiNullable}} +import org.openapitools.jackson.nullable.JsonNullable; +{{/openApiNullable}} {{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/** * {{.}} @@ -46,7 +44,16 @@ public {{>sealed}}record {{classname}}( {{#deprecated}} @Deprecated {{/deprecated}} - {{#jackson}}@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}") {{/jackson}}{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}{{{datatypeWithEnum}}} {{name}}{{^-last}},{{/-last}} + {{#useSwaggerAnnotations}} + @ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}") + {{/useSwaggerAnnotations}} + {{#useSwaggerV3Annotations}} + @Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"{{#deprecated}}, deprecated = true{{/deprecated}}) + {{/useSwaggerV3Annotations}} + {{#useMicroProfileOpenAPIAnnotations}} + @org.eclipse.microprofile.openapi.annotations.media.Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"{{#deprecated}}, deprecated = true{{/deprecated}}) + {{/useMicroProfileOpenAPIAnnotations}} + {{#jackson}}@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}") {{/jackson}}{{#vendorExtensions.x-is-jackson-optional-nullable}}JsonNullable<{{{datatypeWithEnum}}}>{{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}{{{datatypeWithEnum}}}{{/vendorExtensions.x-is-jackson-optional-nullable}} {{name}}{{^-last}},{{/-last}} {{/vars}} ) {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { {{#vars}} @@ -61,4 +68,93 @@ public {{>sealed}}record {{classname}}( {{/isContainer}} {{/isEnum}} {{/vars}} + {{#vendorExtensions.x-jaxrs-record-has-defaults}} + public {{classname}} { + {{#vars}} + {{#vendorExtensions.x-is-jackson-optional-nullable}} + if ({{name}} == null) { + {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#isContainer}}undefined(){{/isContainer}}{{^isContainer}}{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}}{{/isContainer}}; + } + {{/vendorExtensions.x-is-jackson-optional-nullable}} + {{^vendorExtensions.x-is-jackson-optional-nullable}} + {{#defaultValue}} + if ({{name}} == null) { + {{name}} = {{{.}}}; + } + {{/defaultValue}} + {{/vendorExtensions.x-is-jackson-optional-nullable}} + {{/vars}} + } + + {{/vendorExtensions.x-jaxrs-record-has-defaults}} + {{#vendorExtensions.x-jaxrs-record-has-byte-array}} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + {{classname}} {{classVarName}} = ({{classname}}) o; + return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} && + {{/-last}}{{/vars}}; + } + + @Override + public int hashCode() { + return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}); + } + + {{/vendorExtensions.x-jaxrs-record-has-byte-array}} + {{#vendorExtensions.x-jaxrs-record-has-password}} + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#vars}}sb.append(" {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n"); + {{/vars}}sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + {{/vendorExtensions.x-jaxrs-record-has-password}} + {{#generateBuilders}} + public static {{classname}}Builder builder() { + return new {{classname}}Builder(); + } + + public static class {{classname}}Builder { + {{#vars}} + {{#vendorExtensions.x-is-jackson-optional-nullable}} + private JsonNullable<{{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}}> {{name}} = JsonNullable.<{{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}}>{{#isContainer}}undefined(){{/isContainer}}{{^isContainer}}{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}}{{/isContainer}}; + {{/vendorExtensions.x-is-jackson-optional-nullable}} + {{^vendorExtensions.x-is-jackson-optional-nullable}} + private {{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}; + {{/vendorExtensions.x-is-jackson-optional-nullable}} + {{/vars}} + + {{#vars}} + {{#deprecated}} + @Deprecated + {{/deprecated}} + public {{classname}}Builder {{name}}({{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}) { + this.{{name}} = {{#vendorExtensions.x-is-jackson-optional-nullable}}JsonNullable.<{{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}}>of({{name}}){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{name}}{{/vendorExtensions.x-is-jackson-optional-nullable}}; + return this; + } + {{/vars}} + + public {{classname}} build() { + return new {{classname}}({{#vars}}{{name}}{{^-last}}, {{/-last}}{{/vars}}); + } + } + + {{/generateBuilders}} } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java index d52fa316fd4b..b8bbd3f6dba1 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java @@ -1751,9 +1751,118 @@ public void testRecordsAreScopedToOneOfInterfaceImplementations() throws Excepti } /** - * {@code useRecords} cannot be combined with {@code withXml}: JAXB binding requires mutable - * JavaBeans with a no-argument constructor, which records cannot provide. + * The records emitted for oneOf interface implementations keep pojo semantics: defaults (scalar, + * enum and container) are applied in a compact canonical constructor, spec-marked JsonNullable + * properties render as JsonNullable components defaulting to undefined, byte[] properties get + * content-based equals/hashCode, and password properties are masked in toString. Models outside the + * oneOf hierarchy stay untouched classes. */ + @Test + public void testRecordsForOneOfInterfaceImplementationsOnly() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useSealed", "true"); + properties.put("useRecords", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/records_parity.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(configurator.toClientOptInput()).generate(); + + String outputDir = output.getAbsolutePath().replace("\\", "/"); + String modelDir = outputDir + "/src/gen/java/org/openapitools/model/"; + + // The oneOf interface implementation becomes a record; components carry the property annotations. + assertFileContains(Paths.get(modelDir + "Item.java"), + "public record Item(", + "@JsonProperty(required = true, value = \"name\") @NotNull String name", + "@ApiModelProperty(required = true, value = \"\")", + "@JsonProperty(\"nickname\") JsonNullable nickname"); + assertFileNotContains(Paths.get(modelDir + "Item.java"), + "public class Item", "public void setName", "ItemBuilder"); + + // Defaults are applied in the compact canonical constructor. + assertFileContains(Paths.get(modelDir + "Item.java"), + "public Item {", + "count = 10;", + "status = StatusEnum.AVAILABLE;", + "tags = new ArrayList<>();", + "nickname = JsonNullable.undefined();"); + + // byte[] properties keep content-based equality; password properties are masked in toString. + assertFileContains(Paths.get(modelDir + "Item.java"), + "Arrays.equals(this.payload, item.payload)", + "Arrays.hashCode(payload)", + "sb.append(\" secret: \").append(\"*\")"); + + // An ordinary pojo outside the oneOf hierarchy is left untouched by useRecords: still a class, + // still mutable, still carrying its field-initialised defaults. (It is final because useSealed + // finalises standalone pojos - that is useSealed's behaviour, not useRecords'.) + assertFileContains(Paths.get(modelDir + "Standalone.java"), + "public final class Standalone", + "public void setCount", + "private Integer count = 5;"); + assertFileNotContains(Paths.get(modelDir + "Standalone.java"), "record Standalone"); + + // Models taking part in inheritance stay classes (a record can neither extend nor be extended). + assertFileContains(Paths.get(modelDir + "Animal.java"), "public sealed class Animal", "permits Cat"); + assertFileNotContains(Paths.get(modelDir + "Animal.java"), "record Animal"); + assertFileContains(Paths.get(modelDir + "Cat.java"), "public final class Cat", "extends Animal"); + assertFileNotContains(Paths.get(modelDir + "Cat.java"), "record Cat"); + + // Models with additionalProperties need the map-backed pojo and stay classes. + assertFileContains(Paths.get(modelDir + "FreeForm.java"), "public final class FreeForm"); + assertFileNotContains(Paths.get(modelDir + "FreeForm.java"), "record FreeForm"); + + assertFileContains(Paths.get(outputDir + "/pom.xml"), "17"); + } + + /** + * {@code useRecords=true} + {@code generateBuilders=true}: since records drop setters, a flat + * builder inside the record offers fluent construction. Builder fields carry the pojo field + * defaults so an unset property builds to the same value a pojo would have, and JsonNullable + * properties are wrapped on the fluent setter. + */ + @Test + public void testRecordsBuilderGeneration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useSealed", "true"); + properties.put("useRecords", "true"); + properties.put("generateBuilders", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/records_parity.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(configurator.toClientOptInput()).generate(); + + String modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + assertFileContains(Paths.get(modelDir + "Item.java"), + "public static ItemBuilder builder()", + "public static class ItemBuilder {", + "private Integer count = 10;", + "private List tags = new ArrayList<>();", + "private JsonNullable nickname = JsonNullable.undefined();", + "public ItemBuilder name(String name)", + "this.nickname = JsonNullable.of(nickname);", + "return new Item(itemType, name, count, status, tags, nickname, payload, secret);"); + } + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*useRecords.*withXml.*") public void useRecordsRejectsWithXml() { diff --git a/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/records_parity.yaml b/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/records_parity.yaml new file mode 100644 index 000000000000..12ce445df08c --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/records_parity.yaml @@ -0,0 +1,151 @@ +openapi: 3.0.1 +info: + title: records parity + description: > + Exercises useRecords across the pojo feature matrix: defaults (scalar, enum and container), + nullable properties (JsonNullable), byte[] and password properties. Item carries that matrix and + implements a generated oneOf interface, so it is the model rendered as a record. Everything else + is a negative case: Standalone is an ordinary pojo outside any oneOf hierarchy, Animal/Cat take + part in inheritance and FreeForm declares additionalProperties. + version: 1.0.0 +paths: + /items: + get: + operationId: getItem + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ItemRequest' + /standalone: + get: + operationId: getStandalone + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Standalone' + /animals: + get: + operationId: getAnimal + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Animal' + /cats: + get: + operationId: getCat + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Cat' + /freeform: + get: + operationId: getFreeForm + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FreeForm' +components: + schemas: + ItemRequest: + oneOf: + - $ref: '#/components/schemas/Item' + - $ref: '#/components/schemas/OtherItem' + discriminator: + propertyName: itemType + mapping: + ITEM: '#/components/schemas/Item' + OTHER: '#/components/schemas/OtherItem' + properties: + itemType: + type: string + OtherItem: + type: object + required: + - itemType + properties: + itemType: + type: string + label: + type: string + Standalone: + type: object + description: An ordinary pojo outside any oneOf hierarchy - must stay a class. + properties: + id: + type: string + count: + type: integer + default: 5 + Item: + type: object + required: + - name + - itemType + properties: + itemType: + type: string + name: + type: string + count: + type: integer + default: 10 + status: + type: string + enum: + - available + - sold + default: available + tags: + type: array + items: + type: string + nickname: + type: string + nullable: true + x-is-jackson-optional-nullable: true + payload: + type: string + format: byte + secret: + type: string + format: password + Animal: + type: object + required: + - petType + properties: + petType: + type: string + discriminator: + propertyName: petType + mapping: + CAT: '#/components/schemas/Cat' + Cat: + allOf: + - $ref: '#/components/schemas/Animal' + - type: object + properties: + meows: + type: boolean + FreeForm: + type: object + properties: + id: + type: string + additionalProperties: + type: string diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java index 5e5fb5689840..c4e0c79bbed9 100644 --- a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java @@ -11,16 +11,21 @@ import io.swagger.annotations.*; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonTypeName; +import org.openapitools.jackson.nullable.JsonNullable; @JsonTypeName("CAT") @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") public record CatRequest( + @ApiModelProperty(required = true, value = "") @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @ApiModelProperty(required = true, value = "") @JsonProperty(required = true, value = "name") @NotNull String name, + @ApiModelProperty(required = true, value = "") @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor ) implements PetRequest { } diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java index 9fd07e5db6e9..2a6daca300bf 100644 --- a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java @@ -11,16 +11,21 @@ import io.swagger.annotations.*; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonTypeName; +import org.openapitools.jackson.nullable.JsonNullable; @JsonTypeName("DOG") @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") public record DogRequest( + @ApiModelProperty(required = true, value = "") @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @ApiModelProperty(required = true, value = "") @JsonProperty(required = true, value = "name") @NotNull String name, + @ApiModelProperty(required = true, value = "") @JsonProperty(required = true, value = "trained") @NotNull Boolean trained ) implements PetRequest { } From 20a862f7beff3bd9b2abaeb81c0b22db1be4f127 Mon Sep 17 00:00:00 2001 From: Ignacio Vidal Date: Sat, 1 Aug 2026 18:43:48 +0100 Subject: [PATCH 3/3] [jaxrs-spec] Add records samples for every library and build them in CI useRecords is implemented in the shared model/record templates, so it applies to all five jaxrs-spec libraries, but only the default one had a sample. Add a records sample per library - helidon, kumuluzee, openliberty, quarkus and thorntail - and register all five in the JDK17 samples workflow so they are compiled on every push and pull request. Two things had to be fixed to make those samples compile: * Each library overrides pom.mustache and hardcoded Java 1.8 (helidon: 11), so a records or sealed sample could not build. Gate the compiler source/target on useSealed/useRecords exactly as the base pom.mustache already does. * record.mustache imported JsonNullable unconditionally. The import is already contributed through the imports block for the models that use it, so records with a nullable component carried a duplicate import, and records without one carried an unused import that fails to compile on the libraries whose pom does not ship jackson-databind-nullable. kumuluzee, openliberty and thorntail additionally set openApiNullable=false in their sample config: their poms omit jackson-databind-nullable while the pojo template imports JsonNullable whenever openApiNullable is on, which is a pre-existing issue unrelated to records (it reproduces with no records flags set at all). All six records samples plus jaxrs-spec-sealed build under JDK 17. --- .github/workflows/samples-jdk17.yaml | 15 ++ bin/configs/jaxrs-spec-records-helidon.yaml | 11 + bin/configs/jaxrs-spec-records-kumuluzee.yaml | 15 ++ .../jaxrs-spec-records-openliberty.yaml | 15 ++ bin/configs/jaxrs-spec-records-quarkus.yaml | 11 + bin/configs/jaxrs-spec-records-thorntail.yaml | 15 ++ .../spec/libraries/helidon/pom.mustache | 2 +- .../spec/libraries/kumuluzee/pom.mustache | 4 +- .../spec/libraries/openliberty/pom.mustache | 4 +- .../spec/libraries/quarkus/pom.mustache | 4 +- .../spec/libraries/thorntail/pom.mustache | 4 +- .../resources/JavaJaxRS/spec/record.mustache | 6 +- .../jaxrs/JavaJAXRSSpecServerCodegenTest.java | 30 +++ .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 14 ++ .../.openapi-generator/VERSION | 1 + .../jaxrs-spec-records-helidon/README.md | 37 +++ .../jaxrs-spec-records-helidon/pom.xml | 231 ++++++++++++++++++ .../java/org/openapitools/api/PetsApi.java | 27 ++ .../org/openapitools/api/RestApplication.java | 9 + .../openapitools/api/RestResourceRoot.java | 5 + .../org/openapitools/model/CatRequest.java | 25 ++ .../org/openapitools/model/DogRequest.java | 25 ++ .../java/org/openapitools/model/PetBase.java | 109 +++++++++ .../org/openapitools/model/PetRequest.java | 27 ++ .../java/org/openapitools/model/PetType.java | 57 +++++ .../src/main/resources/META-INF/beans.xml | 9 + .../META-INF/microprofile-config.properties | 11 + .../src/main/resources/META-INF/openapi.yaml | 78 ++++++ .../src/main/resources/logging.properties | 25 ++ .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 12 + .../.openapi-generator/VERSION | 1 + .../jaxrs-spec-records-kumuluzee/README.md | 36 +++ .../jaxrs-spec-records-kumuluzee/pom.xml | 68 ++++++ .../java/org/openapitools/api/PetsApi.java | 27 ++ .../org/openapitools/api/RestApplication.java | 9 + .../openapitools/api/RestResourceRoot.java | 5 + .../org/openapitools/model/CatRequest.java | 25 ++ .../org/openapitools/model/DogRequest.java | 25 ++ .../java/org/openapitools/model/PetBase.java | 108 ++++++++ .../org/openapitools/model/PetRequest.java | 27 ++ .../java/org/openapitools/model/PetType.java | 57 +++++ .../src/main/resources/META-INF/openapi.yaml | 78 ++++++ .../src/main/resources/config.yaml | 5 + .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 16 ++ .../.openapi-generator/VERSION | 1 + .../jaxrs-spec-records-openliberty/README.md | 37 +++ .../jaxrs-spec-records-openliberty/pom.xml | 118 +++++++++ .../java/org/openapitools/api/PetsApi.java | 27 ++ .../org/openapitools/api/RestApplication.java | 9 + .../openapitools/api/RestResourceRoot.java | 5 + .../org/openapitools/model/CatRequest.java | 25 ++ .../org/openapitools/model/DogRequest.java | 25 ++ .../java/org/openapitools/model/PetBase.java | 108 ++++++++ .../org/openapitools/model/PetRequest.java | 27 ++ .../java/org/openapitools/model/PetType.java | 57 +++++ .../src/main/liberty/config/server.xml | 19 ++ .../src/main/webapp/META-INF/MANIFEST.MF | 2 + .../src/main/webapp/META-INF/beans.xml | 5 + .../META-INF/microprofile-config.properties | 1 + .../src/main/webapp/META-INF/openapi.yaml | 78 ++++++ .../src/main/webapp/WEB-INF/ibm-web-ext.xml | 15 ++ .../jaxrs-spec-records-quarkus/.dockerignore | 4 + .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 15 ++ .../.openapi-generator/VERSION | 1 + .../jaxrs-spec-records-quarkus/README.md | 33 +++ .../jaxrs-spec-records-quarkus/pom.xml | 156 ++++++++++++ .../java/org/openapitools/api/PetsApi.java | 27 ++ .../org/openapitools/api/RestApplication.java | 9 + .../openapitools/api/RestResourceRoot.java | 5 + .../org/openapitools/model/CatRequest.java | 25 ++ .../org/openapitools/model/DogRequest.java | 25 ++ .../java/org/openapitools/model/PetBase.java | 109 +++++++++ .../org/openapitools/model/PetRequest.java | 27 ++ .../java/org/openapitools/model/PetType.java | 57 +++++ .../src/main/docker/Dockerfile.jvm | 34 +++ .../src/main/docker/Dockerfile.native | 22 ++ .../src/main/resources/META-INF/openapi.yaml | 78 ++++++ .../src/main/resources/application.properties | 5 + .../.openapi-generator-ignore | 23 ++ .../.openapi-generator/FILES | 11 + .../.openapi-generator/VERSION | 1 + .../jaxrs-spec-records-thorntail/README.md | 31 +++ .../jaxrs-spec-records-thorntail/pom.xml | 83 +++++++ .../java/org/openapitools/api/PetsApi.java | 27 ++ .../org/openapitools/api/RestApplication.java | 9 + .../openapitools/api/RestResourceRoot.java | 5 + .../org/openapitools/model/CatRequest.java | 25 ++ .../org/openapitools/model/DogRequest.java | 25 ++ .../java/org/openapitools/model/PetBase.java | 108 ++++++++ .../org/openapitools/model/PetRequest.java | 27 ++ .../java/org/openapitools/model/PetType.java | 57 +++++ .../src/main/resources/META-INF/openapi.yaml | 78 ++++++ .../org/openapitools/model/CatRequest.java | 1 - .../org/openapitools/model/DogRequest.java | 1 - 98 files changed, 3106 insertions(+), 14 deletions(-) create mode 100644 bin/configs/jaxrs-spec-records-helidon.yaml create mode 100644 bin/configs/jaxrs-spec-records-kumuluzee.yaml create mode 100644 bin/configs/jaxrs-spec-records-openliberty.yaml create mode 100644 bin/configs/jaxrs-spec-records-quarkus.yaml create mode 100644 bin/configs/jaxrs-spec-records-thorntail.yaml create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/README.md create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/beans.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/microprofile-config.properties create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/openapi.yaml create mode 100644 samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/logging.properties create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/README.md create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/META-INF/openapi.yaml create mode 100644 samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/config.yaml create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/README.md create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/main/liberty/config/server.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/MANIFEST.MF create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/beans.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/microprofile-config.properties create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/openapi.yaml create mode 100644 samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/WEB-INF/ibm-web-ext.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/.dockerignore create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/README.md create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.jvm create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.native create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/META-INF/openapi.yaml create mode 100644 samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/application.properties create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/README.md create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-records-thorntail/src/main/resources/META-INF/openapi.yaml diff --git a/.github/workflows/samples-jdk17.yaml b/.github/workflows/samples-jdk17.yaml index 82d57c817434..8bda69e1573a 100644 --- a/.github/workflows/samples-jdk17.yaml +++ b/.github/workflows/samples-jdk17.yaml @@ -24,6 +24,11 @@ on: - samples/server/petstore/java-helidon-server/v3/se/** - samples/server/petstore/jaxrs-spec-sealed/** - samples/server/petstore/jaxrs-spec-records/** + - samples/server/petstore/jaxrs-spec-records-helidon/** + - samples/server/petstore/jaxrs-spec-records-kumuluzee/** + - samples/server/petstore/jaxrs-spec-records-openliberty/** + - samples/server/petstore/jaxrs-spec-records-quarkus/** + - samples/server/petstore/jaxrs-spec-records-thorntail/** pull_request: paths: # clients @@ -48,6 +53,11 @@ on: - samples/server/petstore/java-helidon-server/v3/se/** - samples/server/petstore/jaxrs-spec-sealed/** - samples/server/petstore/jaxrs-spec-records/** + - samples/server/petstore/jaxrs-spec-records-helidon/** + - samples/server/petstore/jaxrs-spec-records-kumuluzee/** + - samples/server/petstore/jaxrs-spec-records-openliberty/** + - samples/server/petstore/jaxrs-spec-records-quarkus/** + - samples/server/petstore/jaxrs-spec-records-thorntail/** jobs: build: name: Build with JDK17 @@ -78,6 +88,11 @@ jobs: - samples/server/petstore/java-helidon-server/v3/se - samples/server/petstore/jaxrs-spec-sealed - samples/server/petstore/jaxrs-spec-records + - samples/server/petstore/jaxrs-spec-records-helidon + - samples/server/petstore/jaxrs-spec-records-kumuluzee + - samples/server/petstore/jaxrs-spec-records-openliberty + - samples/server/petstore/jaxrs-spec-records-quarkus + - samples/server/petstore/jaxrs-spec-records-thorntail steps: - uses: actions/checkout@v7 - uses: actions/setup-java@v5 diff --git a/bin/configs/jaxrs-spec-records-helidon.yaml b/bin/configs/jaxrs-spec-records-helidon.yaml new file mode 100644 index 000000000000..d9b1bd851cb7 --- /dev/null +++ b/bin/configs/jaxrs-spec-records-helidon.yaml @@ -0,0 +1,11 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-records-helidon +library: helidon +inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec +additionalProperties: + artifactId: jaxrs-spec-records-helidon-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + useRecords: "true" + hideGenerationTimestamp: "true" diff --git a/bin/configs/jaxrs-spec-records-kumuluzee.yaml b/bin/configs/jaxrs-spec-records-kumuluzee.yaml new file mode 100644 index 000000000000..779c19dfbd7e --- /dev/null +++ b/bin/configs/jaxrs-spec-records-kumuluzee.yaml @@ -0,0 +1,15 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-records-kumuluzee +library: kumuluzee +inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec +additionalProperties: + artifactId: jaxrs-spec-records-kumuluzee-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + useRecords: "true" + hideGenerationTimestamp: "true" + # This library's pom does not ship jackson-databind-nullable, and the pojo + # template imports JsonNullable whenever openApiNullable is on (the default), + # so the sample would not compile. Unrelated to records; see PetBase. + openApiNullable: "false" diff --git a/bin/configs/jaxrs-spec-records-openliberty.yaml b/bin/configs/jaxrs-spec-records-openliberty.yaml new file mode 100644 index 000000000000..df2cf02b0142 --- /dev/null +++ b/bin/configs/jaxrs-spec-records-openliberty.yaml @@ -0,0 +1,15 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-records-openliberty +library: openliberty +inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec +additionalProperties: + artifactId: jaxrs-spec-records-openliberty-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + useRecords: "true" + hideGenerationTimestamp: "true" + # This library's pom does not ship jackson-databind-nullable, and the pojo + # template imports JsonNullable whenever openApiNullable is on (the default), + # so the sample would not compile. Unrelated to records; see PetBase. + openApiNullable: "false" diff --git a/bin/configs/jaxrs-spec-records-quarkus.yaml b/bin/configs/jaxrs-spec-records-quarkus.yaml new file mode 100644 index 000000000000..58738996a02e --- /dev/null +++ b/bin/configs/jaxrs-spec-records-quarkus.yaml @@ -0,0 +1,11 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-records-quarkus +library: quarkus +inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec +additionalProperties: + artifactId: jaxrs-spec-records-quarkus-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + useRecords: "true" + hideGenerationTimestamp: "true" diff --git a/bin/configs/jaxrs-spec-records-thorntail.yaml b/bin/configs/jaxrs-spec-records-thorntail.yaml new file mode 100644 index 000000000000..44b616974bbd --- /dev/null +++ b/bin/configs/jaxrs-spec-records-thorntail.yaml @@ -0,0 +1,15 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-records-thorntail +library: thorntail +inputSpec: modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml +templateDir: modules/openapi-generator/src/main/resources/JavaJaxRS/spec +additionalProperties: + artifactId: jaxrs-spec-records-thorntail-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + useRecords: "true" + hideGenerationTimestamp: "true" + # This library's pom does not ship jackson-databind-nullable, and the pojo + # template imports JsonNullable whenever openApiNullable is on (the default), + # so the sample would not compile. Unrelated to records; see PetBase. + openApiNullable: "false" diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/helidon/pom.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/helidon/pom.mustache index 91c575960dc7..369f59f8dbbe 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/helidon/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/helidon/pom.mustache @@ -20,7 +20,7 @@ {{helidonVersion}} io.helidon.microprofile.cdi.Main - 11 + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}11{{/useRecords}}{{/useSealed}} ${maven.compiler.source} true UTF-8 diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/kumuluzee/pom.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/kumuluzee/pom.mustache index 2e83ada78427..3ebff4b50098 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/kumuluzee/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/kumuluzee/pom.mustache @@ -20,8 +20,8 @@ The microservice was generated automatically with the OpenAPI Generator project - 1.8 - 1.8 + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} UTF-8 3.9.0 diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/openliberty/pom.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/openliberty/pom.mustache index 07b5dfdc712c..355d359a81a8 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/openliberty/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/openliberty/pom.mustache @@ -51,8 +51,8 @@ UTF-8 - 1.8 - 1.8 + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} false 3.2.2 diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/pom.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/pom.mustache index 24b70e34283e..2b4a6147d7a5 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/pom.mustache @@ -18,8 +18,8 @@ 3.8.1 true - 1.8 - 1.8 + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} UTF-8 UTF-8 {{#useJakartaEe}} diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/thorntail/pom.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/thorntail/pom.mustache index 863236dce533..0cd211e73042 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/thorntail/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/thorntail/pom.mustache @@ -19,8 +19,8 @@ 2.5.0.Final 5.14.4 - 1.8 - 1.8 + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} + {{#useSealed}}17{{/useSealed}}{{^useSealed}}{{#useRecords}}17{{/useRecords}}{{^useRecords}}1.8{{/useRecords}}{{/useSealed}} false UTF-8 diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache index 4f267830b248..67768278f5d0 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/record.mustache @@ -13,9 +13,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonTypeName; {{/jackson}} -{{#openApiNullable}} -import org.openapitools.jackson.nullable.JsonNullable; -{{/openApiNullable}} +{{! JsonNullable is already contributed through the imports block above for the models that use + it, so importing it here as well produced a duplicate import, and an unused one on records + with no nullable component - which broke libraries whose pom omits jackson-databind-nullable. }} {{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/** * {{.}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java index b8bbd3f6dba1..49fc55f0c562 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java @@ -1863,6 +1863,36 @@ public void testRecordsBuilderGeneration() throws Exception { "return new Item(itemType, name, count, status, tags, nickname, payload, secret);"); } + @Test + public void testRecordsDoNotDuplicateTheJsonNullableImport() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useSealed", "true"); + properties.put("useRecords", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/records_parity.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + + String modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + // Item has a JsonNullable component, so it needs the import -- but exactly once. The + // record template used to add its own copy on top of the one already contributed through + // {{#imports}}, so every record with a nullable component carried a duplicate import. + String importLine = "import org.openapitools.jackson.nullable.JsonNullable;"; + long itemImports = Files.readAllLines(Paths.get(modelDir + "Item.java")).stream() + .filter(l -> l.trim().equals(importLine)).count(); + assertTrue(itemImports == 1L, "Item should import JsonNullable exactly once, was " + itemImports); + assertFileContains(Paths.get(modelDir + "Item.java"), "JsonNullable nickname"); + } + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*useRecords.*withXml.*") public void useRecordsRejectsWithXml() { diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/FILES new file mode 100644 index 000000000000..18d6ebf0a567 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/FILES @@ -0,0 +1,14 @@ +README.md +pom.xml +src/gen/java/org/openapitools/api/PetsApi.java +src/gen/java/org/openapitools/api/RestApplication.java +src/gen/java/org/openapitools/api/RestResourceRoot.java +src/gen/java/org/openapitools/model/CatRequest.java +src/gen/java/org/openapitools/model/DogRequest.java +src/gen/java/org/openapitools/model/PetBase.java +src/gen/java/org/openapitools/model/PetRequest.java +src/gen/java/org/openapitools/model/PetType.java +src/main/resources/META-INF/beans.xml +src/main/resources/META-INF/microprofile-config.properties +src/main/resources/META-INF/openapi.yaml +src/main/resources/logging.properties diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/VERSION new file mode 100644 index 000000000000..8fc8df61083a --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.25.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/README.md b/samples/server/petstore/jaxrs-spec-records-helidon/README.md new file mode 100644 index 000000000000..1a1191a52fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/README.md @@ -0,0 +1,37 @@ +# JAX-RS server with OpenAPI using Helidon + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an +[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. + +This is an example of building a OpenAPI-enabled JAX-RS server. +This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework and +the [Eclipse-MicroProfile-OpenAPI](https://github.com/eclipse/microprofile-open-api) addition. + +The pom file is configured to use [Helidon](https://helidon.io/) as application server. + + +To build the server, run this maven command (with JDK 11+): + +```bash +mvn package +``` + +To run the server, run this maven command: + +```bash +java -jar target/jaxrs-spec-records-helidon-petstore-server.jar +``` + +You can then call your server endpoints under: + +``` +http://localhost:8080/ +``` + +You can access the OpenAPI specification at: + +``` +http://localhost:8080/openapi +``` + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/pom.xml b/samples/server/petstore/jaxrs-spec-records-helidon/pom.xml new file mode 100644 index 000000000000..c38f13585c0e --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/pom.xml @@ -0,0 +1,231 @@ + + + + 4.0.0 + + org.openapitools + jaxrs-spec-records-helidon-petstore-server + 1.0.0 + + + + + 2.4.1 + io.helidon.microprofile.cdi.Main + + 17 + ${maven.compiler.source} + true + UTF-8 + UTF-8 + + + 3.8.1 + 3.0.0 + 2.7.5.1 + 1.6.0 + 3.0.0-M5 + 2.3.0 + 2.3.0 + 1.0.6 + 3.0.2 + 1.5.0.Final + 0.5.1 + 2.7 + 3.0.0-M5 + + + + + + io.helidon + helidon-dependencies + ${helidon.version} + pom + import + + + + + + + io.helidon.microprofile.bundles + helidon-microprofile + + + org.jboss + jandex + runtime + true + + + org.junit.jupiter + junit-jupiter-api + test + + + + + ${project.artifactId} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${version.plugin.compiler} + + + org.apache.maven.plugins + maven-surefire-plugin + ${version.plugin.surefire} + + false + + ${project.build.outputDirectory}/logging.properties + + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${version.plugin.failsafe} + + false + true + + + + org.apache.maven.plugins + maven-dependency-plugin + ${version.plugin.dependency} + + + org.apache.maven.plugins + maven-resources-plugin + ${version.plugin.resources} + + + org.apache.maven.plugins + maven-jar-plugin + ${version.plugin.jar} + + + + true + libs + ${mainClass} + false + + + + + + org.jboss.jandex + jandex-maven-plugin + ${version.plugin.jandex} + + + org.codehaus.mojo + exec-maven-plugin + ${version.plugin.exec} + + ${mainClass} + + + + io.helidon.build-tools + helidon-maven-plugin + ${version.plugin.helidon} + + + io.helidon.build-tools + helidon-cli-maven-plugin + ${version.plugin.helidon-cli} + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + prepare-package + + copy-dependencies + + + ${project.build.directory}/libs + false + false + true + true + runtime + test + + + + + + org.jboss.jandex + jandex-maven-plugin + + + make-index + + jandex + + process-classes + + + + + + + + + native-image + + + + io.helidon.build-tools + helidon-maven-plugin + + + native-image + + native-image + + + + + + + + + io.helidon.integrations.graal + helidon-mp-graal-native-image-extension + + + + + jlink-image + + + + io.helidon.build-tools + helidon-maven-plugin + + + + jlink-image + + + + + + + + + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..cbfb8b5c4fbb --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/PetsApi.java @@ -0,0 +1,27 @@ +package org.openapitools.api; + +import org.openapitools.model.PetRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + + +import java.io.InputStream; +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +import javax.validation.Valid; + +/** +* Represents a collection of functions to interact with the API endpoints. +*/ +@Path("/pets") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public class PetsApi { + + @POST + @Consumes({ "application/json" }) + public Response createPet(@Valid @NotNull PetRequest petRequest) { + return Response.ok().entity("magic!").build(); + } +} diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestApplication.java @@ -0,0 +1,9 @@ +package org.openapitools.api; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath(RestResourceRoot.APPLICATION_PATH) +public class RestApplication extends Application { + +} diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/api/RestResourceRoot.java @@ -0,0 +1,5 @@ +package org.openapitools.api; + +public class RestResourceRoot { + public static final String APPLICATION_PATH = ""; +} diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..569a3be25729 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record CatRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..8a0218af0848 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record DogRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "trained") @NotNull Boolean trained +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..217f439bfee5 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetBase.java @@ -0,0 +1,109 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; +import org.openapitools.jackson.nullable.JsonNullable; + + + +@JsonTypeName("PetBase") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public final class PetBase { + private PetType petType; + private String name; + + public PetBase() { + } + + @JsonCreator + public PetBase( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name + ) { + this.petType = petType; + this.name = name; + } + + /** + **/ + public PetBase petType(PetType petType) { + this.petType = petType; + return this; + } + + + @JsonProperty(required = true, value = "petType") + @NotNull public PetType getPetType() { + return petType; + } + + @JsonProperty(required = true, value = "petType") + public void setPetType(PetType petType) { + this.petType = petType; + } + + /** + **/ + public PetBase name(String name) { + this.name = name; + return this; + } + + + @JsonProperty(required = true, value = "name") + @NotNull public String getName() { + return name; + } + + @JsonProperty(required = true, value = "name") + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetBase petBase = (PetBase) o; + return Objects.equals(this.petType, petBase.petType) && + Objects.equals(this.name, petBase.name); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetBase {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + +} diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..af2810f3fb63 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.openapitools.model.CatRequest; +import org.openapitools.model.DogRequest; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@JsonIgnoreProperties( + value = "petType", // ignore manually set petType, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the petType to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRequest.class, name = "CAT"), + @JsonSubTypes.Type(value = DogRequest.class, name = "DOG"), +}) + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public sealed interface PetRequest permits CatRequest, DogRequest { + PetType petType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..22f34b78056c --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/gen/java/org/openapitools/model/PetType.java @@ -0,0 +1,57 @@ +package org.openapitools.model; + +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Discriminator value identifying the type of pet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public enum PetType { + + CAT("CAT"), + + DOG("DOG"); + + private String value; + + PetType(String value) { + this.value = value; + } + + /** + * Convert a String into String, as specified in the + * See JAX RS 2.0 Specification, section 3.2, p. 12 + */ + public static PetType fromString(String s) { + for (PetType b : PetType.values()) { + // using Objects.toString() to be safe if value type non-object type + // because types like 'int' etc. will be auto-boxed + if (java.util.Objects.toString(b.value).equals(s)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected string value '" + s + "'"); + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PetType fromValue(String value) { + for (PetType b : PetType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/beans.xml b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000000..125ef995e5ee --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/beans.xml @@ -0,0 +1,9 @@ + + + + diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/microprofile-config.properties b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/microprofile-config.properties new file mode 100644 index 000000000000..38988f20e5e2 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/microprofile-config.properties @@ -0,0 +1,11 @@ +# Microprofile server properties + +# Application properties. This is the default greeting +app.greeting=Hello + +# Microprofile server properties +server.port=8080 +server.host=0.0.0.0 + +# Enable the optional MicroProfile Metrics REST.request metrics +metrics.rest-request.enabled=true diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/openapi.yaml b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/META-INF/openapi.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.3 +info: + description: | + A oneOf interface whose subtypes inherit shared properties from a base schema (acyclic pattern). The discriminator property is declared on the oneOf container and on the shared base the subtypes inherit via allOf, so the interface getter type resolves to the enum from the container's own properties. + title: oneOf interface + version: 1.0.0 +servers: +- url: / +paths: + /pets: + post: + operationId: createPet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PetRequest" + required: true + responses: + "201": + description: created + x-content-type: application/json + x-accepts: + - application/json +components: + schemas: + PetType: + description: Discriminator value identifying the type of pet + enum: + - CAT + - DOG + type: string + PetRequest: + discriminator: + mapping: + CAT: "#/components/schemas/CatRequest" + DOG: "#/components/schemas/DogRequest" + propertyName: petType + example: + petType: CAT + oneOf: + - $ref: "#/components/schemas/CatRequest" + - $ref: "#/components/schemas/DogRequest" + properties: + petType: + $ref: "#/components/schemas/PetType" + type: object + x-one-of-name: PetRequest + PetBase: + properties: + petType: + $ref: "#/components/schemas/PetType" + name: + type: string + required: + - name + - petType + type: object + CatRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + indoor: + type: boolean + required: + - indoor + type: object + type: object + DogRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + trained: + type: boolean + required: + - trained + type: object + type: object diff --git a/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/logging.properties b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/logging.properties new file mode 100644 index 000000000000..3e909fb7d903 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-helidon/src/main/resources/logging.properties @@ -0,0 +1,25 @@ +# Example Logging Configuration File +# For more information see $JAVA_HOME/jre/lib/logging.properties + +## Send messages to the console +handlers=io.helidon.common.HelidonConsoleHandler +# +## HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n +# +## Global logging level. Can be overridden by specific loggers +.level=INFO + +# Quiet Weld +org.jboss.level=WARNING + +# +# Component specific log levels +#io.helidon.webserver.level=INFO +#io.helidon.config.level=INFO +#io.helidon.security.level=INFO +#io.helidon.microprofile.level=INFO +#io.helidon.common.level=INFO +#io.netty.level=INFO +#org.glassfish.jersey.level=INFO +#org.jboss.weld=INFO diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/FILES new file mode 100644 index 000000000000..6fdfe1b7fea5 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/FILES @@ -0,0 +1,12 @@ +README.md +pom.xml +src/main/java/org/openapitools/api/PetsApi.java +src/main/java/org/openapitools/api/RestApplication.java +src/main/java/org/openapitools/api/RestResourceRoot.java +src/main/java/org/openapitools/model/CatRequest.java +src/main/java/org/openapitools/model/DogRequest.java +src/main/java/org/openapitools/model/PetBase.java +src/main/java/org/openapitools/model/PetRequest.java +src/main/java/org/openapitools/model/PetType.java +src/main/resources/META-INF/openapi.yaml +src/main/resources/config.yaml diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/VERSION new file mode 100644 index 000000000000..8fc8df61083a --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.25.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/README.md b/samples/server/petstore/jaxrs-spec-records-kumuluzee/README.md new file mode 100644 index 000000000000..6fda399ec402 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/README.md @@ -0,0 +1,36 @@ +# JAX-RS server with OpenAPI using KumuluzEE + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an +[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. + +This is an example of building a OpenAPI-enabled JAX-RS server. +This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework and +the [Eclipse-MicroProfile-OpenAPI](https://github.com/eclipse/microprofile-open-api) addition. + +The pom file is configured to use [KumuluzEE](https://ee.kumuluz.com/) as application server. + + +To build the server, run this maven command: + +```bash +mvn clean package +``` + +To run the server, run this maven command: + +```bash +java -jar target/${project.build.finalName}.jar +``` + +You can then call your server endpoints under: + +``` +http://localhost:8080 +``` + +Example endpoint: + +``` +http://localhost:8080/v2/user/example +``` diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/pom.xml b/samples/server/petstore/jaxrs-spec-records-kumuluzee/pom.xml new file mode 100644 index 000000000000..71d9d4c2e567 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.openapitools + jaxrs-spec-records-kumuluzee-petstore-server + 1.0.0 + + + Automatically generated KumuluzEE microservice + The microservice was generated automatically with the OpenAPI Generator project + + + 17 + 17 + UTF-8 + + 3.9.0 + + + + + + com.kumuluz.ee + kumuluzee-bom + ${kumuluzee.version} + pom + import + + + + + + + com.kumuluz.ee + kumuluzee-core + + + com.kumuluz.ee + kumuluzee-servlet-jetty + + + com.kumuluz.ee + kumuluzee-jax-rs-jersey + + + + + + + com.kumuluz.ee + kumuluzee-maven-plugin + ${kumuluzee.version} + + + package + + repackage + + + + + + + + \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..cbfb8b5c4fbb --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/PetsApi.java @@ -0,0 +1,27 @@ +package org.openapitools.api; + +import org.openapitools.model.PetRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + + +import java.io.InputStream; +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +import javax.validation.Valid; + +/** +* Represents a collection of functions to interact with the API endpoints. +*/ +@Path("/pets") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public class PetsApi { + + @POST + @Consumes({ "application/json" }) + public Response createPet(@Valid @NotNull PetRequest petRequest) { + return Response.ok().entity("magic!").build(); + } +} diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestApplication.java @@ -0,0 +1,9 @@ +package org.openapitools.api; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath(RestResourceRoot.APPLICATION_PATH) +public class RestApplication extends Application { + +} diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/api/RestResourceRoot.java @@ -0,0 +1,5 @@ +package org.openapitools.api; + +public class RestResourceRoot { + public static final String APPLICATION_PATH = ""; +} diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..569a3be25729 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record CatRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..8a0218af0848 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record DogRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "trained") @NotNull Boolean trained +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..0e258ba99762 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetBase.java @@ -0,0 +1,108 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("PetBase") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public final class PetBase { + private PetType petType; + private String name; + + public PetBase() { + } + + @JsonCreator + public PetBase( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name + ) { + this.petType = petType; + this.name = name; + } + + /** + **/ + public PetBase petType(PetType petType) { + this.petType = petType; + return this; + } + + + @JsonProperty(required = true, value = "petType") + @NotNull public PetType getPetType() { + return petType; + } + + @JsonProperty(required = true, value = "petType") + public void setPetType(PetType petType) { + this.petType = petType; + } + + /** + **/ + public PetBase name(String name) { + this.name = name; + return this; + } + + + @JsonProperty(required = true, value = "name") + @NotNull public String getName() { + return name; + } + + @JsonProperty(required = true, value = "name") + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetBase petBase = (PetBase) o; + return Objects.equals(this.petType, petBase.petType) && + Objects.equals(this.name, petBase.name); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetBase {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + +} diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..af2810f3fb63 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.openapitools.model.CatRequest; +import org.openapitools.model.DogRequest; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@JsonIgnoreProperties( + value = "petType", // ignore manually set petType, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the petType to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRequest.class, name = "CAT"), + @JsonSubTypes.Type(value = DogRequest.class, name = "DOG"), +}) + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public sealed interface PetRequest permits CatRequest, DogRequest { + PetType petType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..22f34b78056c --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/java/org/openapitools/model/PetType.java @@ -0,0 +1,57 @@ +package org.openapitools.model; + +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Discriminator value identifying the type of pet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public enum PetType { + + CAT("CAT"), + + DOG("DOG"); + + private String value; + + PetType(String value) { + this.value = value; + } + + /** + * Convert a String into String, as specified in the + * See JAX RS 2.0 Specification, section 3.2, p. 12 + */ + public static PetType fromString(String s) { + for (PetType b : PetType.values()) { + // using Objects.toString() to be safe if value type non-object type + // because types like 'int' etc. will be auto-boxed + if (java.util.Objects.toString(b.value).equals(s)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected string value '" + s + "'"); + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PetType fromValue(String value) { + for (PetType b : PetType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/META-INF/openapi.yaml b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/META-INF/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/META-INF/openapi.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.3 +info: + description: | + A oneOf interface whose subtypes inherit shared properties from a base schema (acyclic pattern). The discriminator property is declared on the oneOf container and on the shared base the subtypes inherit via allOf, so the interface getter type resolves to the enum from the container's own properties. + title: oneOf interface + version: 1.0.0 +servers: +- url: / +paths: + /pets: + post: + operationId: createPet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PetRequest" + required: true + responses: + "201": + description: created + x-content-type: application/json + x-accepts: + - application/json +components: + schemas: + PetType: + description: Discriminator value identifying the type of pet + enum: + - CAT + - DOG + type: string + PetRequest: + discriminator: + mapping: + CAT: "#/components/schemas/CatRequest" + DOG: "#/components/schemas/DogRequest" + propertyName: petType + example: + petType: CAT + oneOf: + - $ref: "#/components/schemas/CatRequest" + - $ref: "#/components/schemas/DogRequest" + properties: + petType: + $ref: "#/components/schemas/PetType" + type: object + x-one-of-name: PetRequest + PetBase: + properties: + petType: + $ref: "#/components/schemas/PetType" + name: + type: string + required: + - name + - petType + type: object + CatRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + indoor: + type: boolean + required: + - indoor + type: object + type: object + DogRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + trained: + type: boolean + required: + - trained + type: object + type: object diff --git a/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/config.yaml b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/config.yaml new file mode 100644 index 000000000000..648632700fd7 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-kumuluzee/src/main/resources/config.yaml @@ -0,0 +1,5 @@ +kumuluzee: + name: jaxrs-spec-records-kumuluzee-petstore-server + version: 1.0.0 + env: + name: dev \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/FILES new file mode 100644 index 000000000000..b40f9be811b6 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/FILES @@ -0,0 +1,16 @@ +README.md +pom.xml +src/gen/java/org/openapitools/api/PetsApi.java +src/gen/java/org/openapitools/api/RestApplication.java +src/gen/java/org/openapitools/api/RestResourceRoot.java +src/gen/java/org/openapitools/model/CatRequest.java +src/gen/java/org/openapitools/model/DogRequest.java +src/gen/java/org/openapitools/model/PetBase.java +src/gen/java/org/openapitools/model/PetRequest.java +src/gen/java/org/openapitools/model/PetType.java +src/main/liberty/config/server.xml +src/main/webapp/META-INF/MANIFEST.MF +src/main/webapp/META-INF/beans.xml +src/main/webapp/META-INF/microprofile-config.properties +src/main/webapp/META-INF/openapi.yaml +src/main/webapp/WEB-INF/ibm-web-ext.xml diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/VERSION new file mode 100644 index 000000000000..8fc8df61083a --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.25.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/README.md b/samples/server/petstore/jaxrs-spec-records-openliberty/README.md new file mode 100644 index 000000000000..0bf7f40a486d --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/README.md @@ -0,0 +1,37 @@ +# JAX-RS server with OpenAPI using Open Liberty + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an +[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. + +This is an example of building a OpenAPI-enabled JAX-RS server. +This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework and +the [Eclipse-MicroProfile-OpenAPI](https://github.com/eclipse/microprofile-open-api) addition. + +The pom file is configured to use [Open Liberty](https://openliberty.io/) as application server. + + +To start the server with maven, run this command: + +```bash +mvn install liberty:start-server +``` + +The OpenAPI specification is available at: + +``` +http://localhost:9080/openapi +``` + +A UI for this OpenAPI Specification is available at: + +``` +http://localhost:9080/openapi/ui +``` + +When you are done stop Open Liberty with: + +``` +mvn liberty:stop-server +``` + diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/pom.xml b/samples/server/petstore/jaxrs-spec-records-openliberty/pom.xml new file mode 100644 index 000000000000..2e7728292575 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/pom.xml @@ -0,0 +1,118 @@ + + 4.0.0 + + + net.wasdev.wlp.maven.parent + liberty-maven-app-parent + 2.6 + + + org.openapitools + jaxrs-spec-records-openliberty-petstore-server + 1.0.0 + war + + + + javax + javaee-api + 8.0 + provided + + + org.eclipse.microprofile + microprofile + 2.0.1 + pom + provided + + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + + + com.fasterxml.jackson.core + jackson-annotations + 2.21 + + + + + UTF-8 + 17 + 17 + false + 3.2.2 + + 19.0.0.7 + 9080 + 9443 + usr + ${project.artifactId} + ${project.build.directory}/${app.name}.zip + 2.0.2 + + + + jaxrs-spec-records-openliberty-petstore-server + + + org.codehaus.mojo + build-helper-maven-plugin + 1.9.1 + + + add-source + generate-sources + + add-source + + + + src/gen/java + + + + + + + + org.apache.maven.plugins + maven-war-plugin + ${version.maven-war-plugin} + + false + pom.xml + + + + + + net.wasdev.wlp.maven.plugins + liberty-maven-plugin + + + io.openliberty + openliberty-runtime + ${version.openliberty-runtime} + zip + + OpenAPIGeneratorServer + true + src/main/liberty/config/server.xml + true + ${package.file} + ${packaging.type} + + ${http.port} + ${https.port} + ${app.name} + + + + + + diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..cbfb8b5c4fbb --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/PetsApi.java @@ -0,0 +1,27 @@ +package org.openapitools.api; + +import org.openapitools.model.PetRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + + +import java.io.InputStream; +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +import javax.validation.Valid; + +/** +* Represents a collection of functions to interact with the API endpoints. +*/ +@Path("/pets") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public class PetsApi { + + @POST + @Consumes({ "application/json" }) + public Response createPet(@Valid @NotNull PetRequest petRequest) { + return Response.ok().entity("magic!").build(); + } +} diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestApplication.java @@ -0,0 +1,9 @@ +package org.openapitools.api; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath(RestResourceRoot.APPLICATION_PATH) +public class RestApplication extends Application { + +} diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/api/RestResourceRoot.java @@ -0,0 +1,5 @@ +package org.openapitools.api; + +public class RestResourceRoot { + public static final String APPLICATION_PATH = ""; +} diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..569a3be25729 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record CatRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..8a0218af0848 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record DogRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "trained") @NotNull Boolean trained +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..0e258ba99762 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetBase.java @@ -0,0 +1,108 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("PetBase") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public final class PetBase { + private PetType petType; + private String name; + + public PetBase() { + } + + @JsonCreator + public PetBase( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name + ) { + this.petType = petType; + this.name = name; + } + + /** + **/ + public PetBase petType(PetType petType) { + this.petType = petType; + return this; + } + + + @JsonProperty(required = true, value = "petType") + @NotNull public PetType getPetType() { + return petType; + } + + @JsonProperty(required = true, value = "petType") + public void setPetType(PetType petType) { + this.petType = petType; + } + + /** + **/ + public PetBase name(String name) { + this.name = name; + return this; + } + + + @JsonProperty(required = true, value = "name") + @NotNull public String getName() { + return name; + } + + @JsonProperty(required = true, value = "name") + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetBase petBase = (PetBase) o; + return Objects.equals(this.petType, petBase.petType) && + Objects.equals(this.name, petBase.name); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetBase {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + +} diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..af2810f3fb63 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.openapitools.model.CatRequest; +import org.openapitools.model.DogRequest; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@JsonIgnoreProperties( + value = "petType", // ignore manually set petType, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the petType to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRequest.class, name = "CAT"), + @JsonSubTypes.Type(value = DogRequest.class, name = "DOG"), +}) + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public sealed interface PetRequest permits CatRequest, DogRequest { + PetType petType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..22f34b78056c --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/gen/java/org/openapitools/model/PetType.java @@ -0,0 +1,57 @@ +package org.openapitools.model; + +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Discriminator value identifying the type of pet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public enum PetType { + + CAT("CAT"), + + DOG("DOG"); + + private String value; + + PetType(String value) { + this.value = value; + } + + /** + * Convert a String into String, as specified in the + * See JAX RS 2.0 Specification, section 3.2, p. 12 + */ + public static PetType fromString(String s) { + for (PetType b : PetType.values()) { + // using Objects.toString() to be safe if value type non-object type + // because types like 'int' etc. will be auto-boxed + if (java.util.Objects.toString(b.value).equals(s)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected string value '" + s + "'"); + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PetType fromValue(String value) { + for (PetType b : PetType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/liberty/config/server.xml b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/liberty/config/server.xml new file mode 100644 index 000000000000..2962ecd8fa41 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/liberty/config/server.xml @@ -0,0 +1,19 @@ + + + cdi-2.0 + jaxrs-2.1 + mpOpenAPI-1.1 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/MANIFEST.MF b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/MANIFEST.MF new file mode 100644 index 000000000000..65b9fe16a698 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Class-Path: diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/beans.xml b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/beans.xml new file mode 100644 index 000000000000..17d17df35c24 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/beans.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/microprofile-config.properties b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/microprofile-config.properties new file mode 100644 index 000000000000..c3fe390239c8 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/microprofile-config.properties @@ -0,0 +1 @@ +mp.openapi.scan.disable=true \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/openapi.yaml b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/META-INF/openapi.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.3 +info: + description: | + A oneOf interface whose subtypes inherit shared properties from a base schema (acyclic pattern). The discriminator property is declared on the oneOf container and on the shared base the subtypes inherit via allOf, so the interface getter type resolves to the enum from the container's own properties. + title: oneOf interface + version: 1.0.0 +servers: +- url: / +paths: + /pets: + post: + operationId: createPet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PetRequest" + required: true + responses: + "201": + description: created + x-content-type: application/json + x-accepts: + - application/json +components: + schemas: + PetType: + description: Discriminator value identifying the type of pet + enum: + - CAT + - DOG + type: string + PetRequest: + discriminator: + mapping: + CAT: "#/components/schemas/CatRequest" + DOG: "#/components/schemas/DogRequest" + propertyName: petType + example: + petType: CAT + oneOf: + - $ref: "#/components/schemas/CatRequest" + - $ref: "#/components/schemas/DogRequest" + properties: + petType: + $ref: "#/components/schemas/PetType" + type: object + x-one-of-name: PetRequest + PetBase: + properties: + petType: + $ref: "#/components/schemas/PetType" + name: + type: string + required: + - name + - petType + type: object + CatRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + indoor: + type: boolean + required: + - indoor + type: object + type: object + DogRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + trained: + type: boolean + required: + - trained + type: object + type: object diff --git a/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/WEB-INF/ibm-web-ext.xml b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/WEB-INF/ibm-web-ext.xml new file mode 100644 index 000000000000..62e9c10b53a2 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-openliberty/src/main/webapp/WEB-INF/ibm-web-ext.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/.dockerignore b/samples/server/petstore/jaxrs-spec-records-quarkus/.dockerignore new file mode 100644 index 000000000000..b86c7ac34057 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/.dockerignore @@ -0,0 +1,4 @@ +* +!target/*-runner +!target/*-runner.jar +!target/lib/* \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/FILES new file mode 100644 index 000000000000..3a42e4154935 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/FILES @@ -0,0 +1,15 @@ +.dockerignore +README.md +pom.xml +src/gen/java/org/openapitools/api/PetsApi.java +src/gen/java/org/openapitools/api/RestApplication.java +src/gen/java/org/openapitools/api/RestResourceRoot.java +src/gen/java/org/openapitools/model/CatRequest.java +src/gen/java/org/openapitools/model/DogRequest.java +src/gen/java/org/openapitools/model/PetBase.java +src/gen/java/org/openapitools/model/PetRequest.java +src/gen/java/org/openapitools/model/PetType.java +src/main/docker/Dockerfile.jvm +src/main/docker/Dockerfile.native +src/main/resources/META-INF/openapi.yaml +src/main/resources/application.properties diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/VERSION new file mode 100644 index 000000000000..8fc8df61083a --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.25.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/README.md b/samples/server/petstore/jaxrs-spec-records-quarkus/README.md new file mode 100644 index 000000000000..929e2bbe4b9d --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/README.md @@ -0,0 +1,33 @@ +# JAX-RS server with OpenAPI using Quarkus + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an +[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. + +This is an example of building a OpenAPI-enabled JAX-RS server. +This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework and +the [Eclipse-MicroProfile-OpenAPI](https://github.com/eclipse/microprofile-open-api) addition. + +The pom file is configured to use [Quarkus](https://quarkus.io/) as application server. + + +To start the server in dev mode, run this maven command: + +```bash +mvn compile quarkus:dev +``` + +You can then call your server endpoints under: + +``` +http://localhost:8080/ +``` + +In dev-mode, you can open Swagger-UI at: + +``` +http://localhost:8080/swagger-ui/ +``` + +Read more in the [Quarkus OpenAPI guide](https://quarkus.io/guides/openapi-swaggerui-guide). + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/pom.xml b/samples/server/petstore/jaxrs-spec-records-quarkus/pom.xml new file mode 100644 index 000000000000..bdd34c5ebe97 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/pom.xml @@ -0,0 +1,156 @@ + + + 4.0.0 + org.openapitools + jaxrs-spec-records-quarkus-petstore-server + jaxrs-spec-records-quarkus-petstore-server + 1.0.0 + + + + 3.8.1 + true + 17 + 17 + UTF-8 + UTF-8 + 1.13.7.Final + 1.13.7.Final + quarkus-universe-bom + io.quarkus + 2.22.1 + 2.1.1 + 1.3.2 + 0.2.11 + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + io.quarkus + quarkus-smallrye-openapi + + + javax.ws.rs + javax.ws.rs-api + ${javax.ws.rs-version} + provided + + + javax.annotation + javax.annotation-api + ${javax.annotation-api-version} + + + org.openapitools + jackson-databind-nullable + ${jackson-databind-nullable-version} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.9.1 + + + add-source + generate-sources + + add-source + + + + src/gen/java + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus-plugin.version} + + + + build + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + + + + + + + + native + + + native + + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + + + + + + + + + native + + + + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..b54f2c294513 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/PetsApi.java @@ -0,0 +1,27 @@ +package org.openapitools.api; + +import org.openapitools.model.PetRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + + + +import java.io.InputStream; +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@Path("/pets") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public class PetsApi { + + @POST + @Consumes({ "application/json" }) + public Response createPet(@Valid @NotNull PetRequest petRequest) { + return Response.ok().entity("magic!").build(); + } + +} diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestApplication.java @@ -0,0 +1,9 @@ +package org.openapitools.api; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath(RestResourceRoot.APPLICATION_PATH) +public class RestApplication extends Application { + +} diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/api/RestResourceRoot.java @@ -0,0 +1,5 @@ +package org.openapitools.api; + +public class RestResourceRoot { + public static final String APPLICATION_PATH = ""; +} diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..569a3be25729 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record CatRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..8a0218af0848 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record DogRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "trained") @NotNull Boolean trained +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..217f439bfee5 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetBase.java @@ -0,0 +1,109 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; +import org.openapitools.jackson.nullable.JsonNullable; + + + +@JsonTypeName("PetBase") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public final class PetBase { + private PetType petType; + private String name; + + public PetBase() { + } + + @JsonCreator + public PetBase( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name + ) { + this.petType = petType; + this.name = name; + } + + /** + **/ + public PetBase petType(PetType petType) { + this.petType = petType; + return this; + } + + + @JsonProperty(required = true, value = "petType") + @NotNull public PetType getPetType() { + return petType; + } + + @JsonProperty(required = true, value = "petType") + public void setPetType(PetType petType) { + this.petType = petType; + } + + /** + **/ + public PetBase name(String name) { + this.name = name; + return this; + } + + + @JsonProperty(required = true, value = "name") + @NotNull public String getName() { + return name; + } + + @JsonProperty(required = true, value = "name") + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetBase petBase = (PetBase) o; + return Objects.equals(this.petType, petBase.petType) && + Objects.equals(this.name, petBase.name); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetBase {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + +} diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..af2810f3fb63 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.openapitools.model.CatRequest; +import org.openapitools.model.DogRequest; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@JsonIgnoreProperties( + value = "petType", // ignore manually set petType, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the petType to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRequest.class, name = "CAT"), + @JsonSubTypes.Type(value = DogRequest.class, name = "DOG"), +}) + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public sealed interface PetRequest permits CatRequest, DogRequest { + PetType petType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..22f34b78056c --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/gen/java/org/openapitools/model/PetType.java @@ -0,0 +1,57 @@ +package org.openapitools.model; + +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Discriminator value identifying the type of pet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public enum PetType { + + CAT("CAT"), + + DOG("DOG"); + + private String value; + + PetType(String value) { + this.value = value; + } + + /** + * Convert a String into String, as specified in the + * See JAX RS 2.0 Specification, section 3.2, p. 12 + */ + public static PetType fromString(String s) { + for (PetType b : PetType.values()) { + // using Objects.toString() to be safe if value type non-object type + // because types like 'int' etc. will be auto-boxed + if (java.util.Objects.toString(b.value).equals(s)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected string value '" + s + "'"); + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PetType fromValue(String value) { + for (PetType b : PetType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.jvm b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.jvm new file mode 100644 index 000000000000..6819cef84d90 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.jvm @@ -0,0 +1,34 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode +# +# Before building the docker image run: +# +# mvn package +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/jaxrs-spec-records-quarkus-petstore-server-jvm . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/jaxrs-spec-records-quarkus-petstore-server-jvm +# +### +FROM fabric8/java-alpine-openjdk8-jre:1.6.5 +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV AB_ENABLED=jmx_exporter + +# Be prepared for running in OpenShift too +RUN adduser -G root --no-create-home --disabled-password 1001 \ + && chown -R 1001 /deployments \ + && chmod -R "g+rwX" /deployments \ + && chown -R 1001:root /deployments + +COPY target/lib/* /deployments/lib/ +COPY target/*-runner.jar /deployments/app.jar +EXPOSE 8080 + +# run with user 1001 +USER 1001 + +ENTRYPOINT [ "/deployments/run-java.sh" ] \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.native b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.native new file mode 100644 index 000000000000..5745e70104b3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/docker/Dockerfile.native @@ -0,0 +1,22 @@ +#### +# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode +# +# Before building the docker image run: +# +# mvn package -Pnative -Dquarkus.native.container-build=true +# +# Then, build the image with: +# +# docker build -f src/main/docker/Dockerfile.native -t quarkus/jaxrs-spec-records-quarkus-petstore-server . +# +# Then run the container using: +# +# docker run -i --rm -p 8080:8080 quarkus/jaxrs-spec-records-quarkus-petstore-server +# +### +FROM registry.access.redhat.com/ubi8/ubi-minimal +WORKDIR /work/ +COPY target/*-runner /work/application +RUN chmod 775 /work +EXPOSE 8080 +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] \ No newline at end of file diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/META-INF/openapi.yaml b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/META-INF/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/META-INF/openapi.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.3 +info: + description: | + A oneOf interface whose subtypes inherit shared properties from a base schema (acyclic pattern). The discriminator property is declared on the oneOf container and on the shared base the subtypes inherit via allOf, so the interface getter type resolves to the enum from the container's own properties. + title: oneOf interface + version: 1.0.0 +servers: +- url: / +paths: + /pets: + post: + operationId: createPet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PetRequest" + required: true + responses: + "201": + description: created + x-content-type: application/json + x-accepts: + - application/json +components: + schemas: + PetType: + description: Discriminator value identifying the type of pet + enum: + - CAT + - DOG + type: string + PetRequest: + discriminator: + mapping: + CAT: "#/components/schemas/CatRequest" + DOG: "#/components/schemas/DogRequest" + propertyName: petType + example: + petType: CAT + oneOf: + - $ref: "#/components/schemas/CatRequest" + - $ref: "#/components/schemas/DogRequest" + properties: + petType: + $ref: "#/components/schemas/PetType" + type: object + x-one-of-name: PetRequest + PetBase: + properties: + petType: + $ref: "#/components/schemas/PetType" + name: + type: string + required: + - name + - petType + type: object + CatRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + indoor: + type: boolean + required: + - indoor + type: object + type: object + DogRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + trained: + type: boolean + required: + - trained + type: object + type: object diff --git a/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/application.properties b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/application.properties new file mode 100644 index 000000000000..83b16e96d391 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-quarkus/src/main/resources/application.properties @@ -0,0 +1,5 @@ +# Configuration file +# key = value + +mp.openapi.scan.disable=true + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/FILES new file mode 100644 index 000000000000..d85716c1f383 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/FILES @@ -0,0 +1,11 @@ +README.md +pom.xml +src/gen/java/org/openapitools/api/PetsApi.java +src/gen/java/org/openapitools/api/RestApplication.java +src/gen/java/org/openapitools/api/RestResourceRoot.java +src/gen/java/org/openapitools/model/CatRequest.java +src/gen/java/org/openapitools/model/DogRequest.java +src/gen/java/org/openapitools/model/PetBase.java +src/gen/java/org/openapitools/model/PetRequest.java +src/gen/java/org/openapitools/model/PetType.java +src/main/resources/META-INF/openapi.yaml diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/VERSION new file mode 100644 index 000000000000..8fc8df61083a --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.25.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/README.md b/samples/server/petstore/jaxrs-spec-records-thorntail/README.md new file mode 100644 index 000000000000..44736f11a380 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/README.md @@ -0,0 +1,31 @@ +# JAX-RS server with OpenAPI using Thorntail + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using an +[OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. + +This is an example of building a OpenAPI-enabled JAX-RS server. +This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework and +the [Eclipse-MicroProfile-OpenAPI](https://github.com/eclipse/microprofile-open-api) addition. + +The pom file is configured to use [Thorntail](https://thorntail.io) as application server. + + +To start the server with maven, run this command: + +```bash +mvn thorntail:run +``` + +You can then call your server endpoints under: + +``` +http://localhost:8080/ +``` + +The OpenAPI specification is available at: + +``` +http://localhost:8080/openapi +``` + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/pom.xml b/samples/server/petstore/jaxrs-spec-records-thorntail/pom.xml new file mode 100644 index 000000000000..a3b9d0c69b71 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + org.openapitools + jaxrs-spec-records-thorntail-petstore-server + jaxrs-spec-records-thorntail-petstore-server + 1.0.0 + war + + + + 2.5.0.Final + 5.14.4 + 17 + 17 + false + UTF-8 + + + + + io.thorntail + bom-all + ${version.thorntail} + import + pom + + + + + + io.thorntail + jaxrs + + + io.thorntail + microprofile-openapi + + + org.junit.jupiter + junit-jupiter-engine + ${version.junit} + test + + + + jaxrs-spec-records-thorntail-petstore-server + + + org.codehaus.mojo + build-helper-maven-plugin + 1.9.1 + + + add-source + generate-sources + + add-source + + + + src/gen/java + + + + + + + io.thorntail + thorntail-maven-plugin + ${version.thorntail} + + + + package + + + + + + + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..cbfb8b5c4fbb --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/PetsApi.java @@ -0,0 +1,27 @@ +package org.openapitools.api; + +import org.openapitools.model.PetRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + + +import java.io.InputStream; +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +import javax.validation.Valid; + +/** +* Represents a collection of functions to interact with the API endpoints. +*/ +@Path("/pets") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public class PetsApi { + + @POST + @Consumes({ "application/json" }) + public Response createPet(@Valid @NotNull PetRequest petRequest) { + return Response.ok().entity("magic!").build(); + } +} diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestApplication.java @@ -0,0 +1,9 @@ +package org.openapitools.api; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath(RestResourceRoot.APPLICATION_PATH) +public class RestApplication extends Application { + +} diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/api/RestResourceRoot.java @@ -0,0 +1,5 @@ +package org.openapitools.api; + +public class RestResourceRoot { + public static final String APPLICATION_PATH = ""; +} diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..569a3be25729 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record CatRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "indoor") @NotNull Boolean indoor +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..8a0218af0848 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,25 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public record DogRequest( + @JsonProperty(required = true, value = "petType") @NotNull PetType petType, + @JsonProperty(required = true, value = "name") @NotNull String name, + @JsonProperty(required = true, value = "trained") @NotNull Boolean trained +) implements PetRequest { +} + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..0e258ba99762 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetBase.java @@ -0,0 +1,108 @@ +package org.openapitools.model; + +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonTypeName; + + + +@JsonTypeName("PetBase") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public final class PetBase { + private PetType petType; + private String name; + + public PetBase() { + } + + @JsonCreator + public PetBase( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name + ) { + this.petType = petType; + this.name = name; + } + + /** + **/ + public PetBase petType(PetType petType) { + this.petType = petType; + return this; + } + + + @JsonProperty(required = true, value = "petType") + @NotNull public PetType getPetType() { + return petType; + } + + @JsonProperty(required = true, value = "petType") + public void setPetType(PetType petType) { + this.petType = petType; + } + + /** + **/ + public PetBase name(String name) { + this.name = name; + return this; + } + + + @JsonProperty(required = true, value = "name") + @NotNull public String getName() { + return name; + } + + @JsonProperty(required = true, value = "name") + public void setName(String name) { + this.name = name; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetBase petBase = (PetBase) o; + return Objects.equals(this.petType, petBase.petType) && + Objects.equals(this.name, petBase.name); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetBase {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + +} diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..af2810f3fb63 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,27 @@ +package org.openapitools.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.openapitools.model.CatRequest; +import org.openapitools.model.DogRequest; +import org.openapitools.model.PetType; +import javax.validation.constraints.*; +import javax.validation.Valid; + + +@JsonIgnoreProperties( + value = "petType", // ignore manually set petType, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the petType to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "petType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CatRequest.class, name = "CAT"), + @JsonSubTypes.Type(value = DogRequest.class, name = "DOG"), +}) + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public sealed interface PetRequest permits CatRequest, DogRequest { + PetType petType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..22f34b78056c --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/gen/java/org/openapitools/model/PetType.java @@ -0,0 +1,57 @@ +package org.openapitools.model; + +import javax.validation.constraints.*; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Discriminator value identifying the type of pet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.25.0-SNAPSHOT") +public enum PetType { + + CAT("CAT"), + + DOG("DOG"); + + private String value; + + PetType(String value) { + this.value = value; + } + + /** + * Convert a String into String, as specified in the + * See JAX RS 2.0 Specification, section 3.2, p. 12 + */ + public static PetType fromString(String s) { + for (PetType b : PetType.values()) { + // using Objects.toString() to be safe if value type non-object type + // because types like 'int' etc. will be auto-boxed + if (java.util.Objects.toString(b.value).equals(s)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected string value '" + s + "'"); + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static PetType fromValue(String value) { + for (PetType b : PetType.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + diff --git a/samples/server/petstore/jaxrs-spec-records-thorntail/src/main/resources/META-INF/openapi.yaml b/samples/server/petstore/jaxrs-spec-records-thorntail/src/main/resources/META-INF/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records-thorntail/src/main/resources/META-INF/openapi.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.3 +info: + description: | + A oneOf interface whose subtypes inherit shared properties from a base schema (acyclic pattern). The discriminator property is declared on the oneOf container and on the shared base the subtypes inherit via allOf, so the interface getter type resolves to the enum from the container's own properties. + title: oneOf interface + version: 1.0.0 +servers: +- url: / +paths: + /pets: + post: + operationId: createPet + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PetRequest" + required: true + responses: + "201": + description: created + x-content-type: application/json + x-accepts: + - application/json +components: + schemas: + PetType: + description: Discriminator value identifying the type of pet + enum: + - CAT + - DOG + type: string + PetRequest: + discriminator: + mapping: + CAT: "#/components/schemas/CatRequest" + DOG: "#/components/schemas/DogRequest" + propertyName: petType + example: + petType: CAT + oneOf: + - $ref: "#/components/schemas/CatRequest" + - $ref: "#/components/schemas/DogRequest" + properties: + petType: + $ref: "#/components/schemas/PetType" + type: object + x-one-of-name: PetRequest + PetBase: + properties: + petType: + $ref: "#/components/schemas/PetType" + name: + type: string + required: + - name + - petType + type: object + CatRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + indoor: + type: boolean + required: + - indoor + type: object + type: object + DogRequest: + allOf: + - $ref: "#/components/schemas/PetBase" + - properties: + trained: + type: boolean + required: + - trained + type: object + type: object diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java index c4e0c79bbed9..ec98ae0796cc 100644 --- a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java @@ -14,7 +14,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonTypeName; -import org.openapitools.jackson.nullable.JsonNullable; diff --git a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java index 2a6daca300bf..b675d07efa5e 100644 --- a/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java @@ -14,7 +14,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonTypeName; -import org.openapitools.jackson.nullable.JsonNullable;