From 0f9d879580cee5187d63c132cd40293542522fa3 Mon Sep 17 00:00:00 2001 From: Ignacio Vidal Date: Wed, 1 Jul 2026 00:56:26 +0100 Subject: [PATCH] [jaxrs-spec] Support useSealed Adds a useSealed option to the jaxrs-spec generator. - With useOneOfInterfaces=true, the generated oneOf interface is sealed and permits its subtypes, which become final classes implementing the interface. - On its own, an allOf class hierarchy driven by a parent discriminator becomes a sealed parent class permitting its subclasses, which extend it and become final; standalone models become final. - JavaJAXRSSpecServerCodegen: useSealed option (constant/field/CliOption/processOpts); postProcessAllModels drops oneOf-derived permits from models rendered as plain classes (their oneOf members do not extend them, so a permits clause would not compile). - sealed.mustache / permits.mustache emit the sealed/permits/final modifiers, gated on useSealed; oneof_interface.mustache and pojo.mustache reference them. - pom.mustache bumps java.version to 17 when useSealed (sealed types need JDK 17+); the default stays 1.8. - Tests: sealed oneOf interface, sealed allOf class hierarchy, useSealed without useOneOfInterfaces (compilable output), defaults unchanged without useSealed. - Adds a jaxrs-spec-sealed sample (registered in the JDK17 samples workflow). The feature stays opt-in; default jaxrs-spec output is unchanged. --- .github/workflows/samples-jdk17.yaml | 3 + bin/configs/jaxrs-spec-sealed.yaml | 10 ++ docs/generators/jaxrs-cxf-cdi.md | 1 + docs/generators/jaxrs-spec.md | 1 + .../languages/JavaJAXRSSpecServerCodegen.java | 13 ++ .../JavaJaxRS/spec/oneof_interface.mustache | 2 +- .../resources/JavaJaxRS/spec/permits.mustache | 1 + .../resources/JavaJaxRS/spec/pojo.mustache | 2 +- .../resources/JavaJaxRS/spec/pom.mustache | 2 +- .../resources/JavaJaxRS/spec/sealed.mustache | 1 + .../jaxrs/JavaJAXRSSpecServerCodegenTest.java | 161 ++++++++++++++++++ .../3_0/jaxrs-spec/sealed_hierarchy.yaml | 77 +++++++++ .../.openapi-generator-ignore | 23 +++ .../.openapi-generator/FILES | 11 ++ .../.openapi-generator/VERSION | 1 + .../petstore/jaxrs-spec-sealed/README.md | 27 +++ .../server/petstore/jaxrs-spec-sealed/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 | 142 +++++++++++++++ .../org/openapitools/model/DogRequest.java | 142 +++++++++++++++ .../java/org/openapitools/model/PetBase.java | 115 +++++++++++++ .../org/openapitools/model/PetRequest.java | 30 ++++ .../java/org/openapitools/model/PetType.java | 59 +++++++ .../src/main/openapi/openapi.yaml | 78 +++++++++ 26 files changed, 1095 insertions(+), 3 deletions(-) create mode 100644 bin/configs/jaxrs-spec-sealed.yaml create mode 100644 modules/openapi-generator/src/main/resources/JavaJaxRS/spec/permits.mustache create mode 100644 modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache create mode 100644 modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/sealed_hierarchy.yaml create mode 100644 samples/server/petstore/jaxrs-spec-sealed/.openapi-generator-ignore create mode 100644 samples/server/petstore/jaxrs-spec-sealed/.openapi-generator/FILES create mode 100644 samples/server/petstore/jaxrs-spec-sealed/.openapi-generator/VERSION create mode 100644 samples/server/petstore/jaxrs-spec-sealed/README.md create mode 100644 samples/server/petstore/jaxrs-spec-sealed/pom.xml create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/PetsApi.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/RestApplication.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/RestResourceRoot.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/CatRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/DogRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetBase.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetRequest.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetType.java create mode 100644 samples/server/petstore/jaxrs-spec-sealed/src/main/openapi/openapi.yaml diff --git a/.github/workflows/samples-jdk17.yaml b/.github/workflows/samples-jdk17.yaml index f55a606e47df..e4ea6b9d299c 100644 --- a/.github/workflows/samples-jdk17.yaml +++ b/.github/workflows/samples-jdk17.yaml @@ -22,6 +22,7 @@ on: - samples/server/petstore/java-camel/** - samples/server/petstore/java-helidon-server/v3/mp/** - samples/server/petstore/java-helidon-server/v3/se/** + - samples/server/petstore/jaxrs-spec-sealed/** pull_request: paths: # clients @@ -44,6 +45,7 @@ on: - samples/server/petstore/java-camel/** - samples/server/petstore/java-helidon-server/v3/mp/** - samples/server/petstore/java-helidon-server/v3/se/** + - samples/server/petstore/jaxrs-spec-sealed/** jobs: build: name: Build with JDK17 @@ -72,6 +74,7 @@ jobs: - samples/server/petstore/java-camel/ - samples/server/petstore/java-helidon-server/v3/mp/ - samples/server/petstore/java-helidon-server/v3/se + - samples/server/petstore/jaxrs-spec-sealed steps: - uses: actions/checkout@v7 - uses: actions/setup-java@v5 diff --git a/bin/configs/jaxrs-spec-sealed.yaml b/bin/configs/jaxrs-spec-sealed.yaml new file mode 100644 index 000000000000..cd23825b19a4 --- /dev/null +++ b/bin/configs/jaxrs-spec-sealed.yaml @@ -0,0 +1,10 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-sealed +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-sealed-petstore-server + useOneOfInterfaces: "true" + useSealed: "true" + serializableModel: "true" + hideGenerationTimestamp: "true" diff --git a/docs/generators/jaxrs-cxf-cdi.md b/docs/generators/jaxrs-cxf-cdi.md index e849be2f56dc..d7be87c2a622 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| +|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| |useTags|use tags for creating interface and controller classnames| |false| diff --git a/docs/generators/jaxrs-spec.md b/docs/generators/jaxrs-spec.md index 542c7bc4c019..c3bb79c787cc 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| +|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| |useTags|use tags for creating interface and controller classnames| |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 bd21c46cb228..a19abc67b903 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 @@ -59,6 +59,7 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen { public static final String GENERATE_JSON_CREATOR = "generateJsonCreator"; 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 QUARKUS_LIBRARY = "quarkus"; public static final String THORNTAIL_LIBRARY = "thorntail"; @@ -79,6 +80,9 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen { @Setter private boolean useEnumCaseInsensitive = false; + @Setter + protected boolean useSealed = false; + private final JakartaSecurityAnnotationProcessor jakartaSecurityAnnotationProcessor = new JakartaSecurityAnnotationProcessor(); @Getter @Setter @@ -162,6 +166,7 @@ public JavaJAXRSSpecServerCodegen() { cliOptions.add(CliOption.newBoolean(USE_JAKARTA_SECURITY_ANNOTATIONS, "Whether to generate Jakarta security annotations (@RolesAllowed, @PermitAll). Requires useJakartaEe=true. Currently only supported when library is set to quarkus.", useJakartaSecurityAnnotations)); 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)); } @Override @@ -205,6 +210,7 @@ public void processOpts() { convertPropertyToBooleanAndWriteBack(GENERATE_JSON_CREATOR, this::setGenerateJsonCreator); convertPropertyToBooleanAndWriteBack(USE_ENUM_CASE_INSENSITIVE, this::setUseEnumCaseInsensitive); + convertPropertyToBooleanAndWriteBack(USE_SEALED, this::setUseSealed); if (additionalProperties.containsKey(OPEN_API_SPEC_FILE_LOCATION)) { openApiSpecFileLocation = additionalProperties.get(OPEN_API_SPEC_FILE_LOCATION).toString(); @@ -424,6 +430,13 @@ public Map postProcessAllModels(Map objs) } } } + // A oneOf container rendered as a plain class (useOneOfInterfaces disabled or the model + // not selected for interface generation) must not be sealed over its oneOf members: they + // do not extend it, so a permits clause would not compile. Only child-derived permits + // (subclasses that actually extend the model) may remain. + if (useSealed && !Boolean.TRUE.equals(model.getVendorExtensions().get("x-is-one-of-interface"))) { + model.permits.removeAll(model.oneOf); + } } } return result; 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 b62c5629c9b7..34d601b12c5f 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 @@ -14,7 +14,7 @@ {{/discriminator}} {{>generatedAnnotation}} -public interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { +public {{>sealed}}interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {{>permits}}{ {{#discriminator}} {{propertyType}} {{propertyGetter}}(); {{/discriminator}} diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/permits.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/permits.mustache new file mode 100644 index 000000000000..9583d443a1d5 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/permits.mustache @@ -0,0 +1 @@ +{{#useSealed}}{{#permits}}{{#-first}}permits {{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{#-last}} {{/-last}}{{/permits}}{{/useSealed}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pojo.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pojo.mustache index f89bf42dc9b8..0f10c01b3273 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pojo.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pojo.mustache @@ -53,7 +53,7 @@ import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue; {{#vendorExtensions.x-class-extra-annotation}} {{{.}}} {{/vendorExtensions.x-class-extra-annotation}} -public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { +public {{>sealed}}class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {{>permits}}{ {{#vars}} {{#isEnum}} {{^isContainer}} 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 84955211fac7..1bb91b263368 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}} - 1.8 + {{#useSealed}}17{{/useSealed}}{{^useSealed}}1.8{{/useSealed}} ${java.version} ${java.version} UTF-8 diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache new file mode 100644 index 000000000000..a5c0af002702 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/sealed.mustache @@ -0,0 +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 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 93eb79502a70..0e341bad2fee 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 @@ -1371,6 +1371,167 @@ public void testDiscriminatorJsonIgnorePropertiesPropagatesToChildren_whenLegacy } } + /** + * With {@code useOneOfInterfaces=true} a oneOf schema is generated as a Java interface, and the + * concrete subtypes implement it. With {@code useSealed=true} the interface is {@code sealed} and + * {@code permits} its subtypes, which become {@code final} and {@code implements} the interface. + * The discriminator property is declared only on a shared non-discriminator base (acyclic pattern), + * so the interface getter type must resolve to the enum model (PetType) from the mapped children. + * Assertions use {@code assertFileContains} rather than {@code JavaFileAssert} because the latter + * parses the source with a JavaParser language level that predates the sealed/permits keywords. + */ + @Test + public void testOneOfSealedInterfaceGeneration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "true"); + properties.put("useSealed", "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 + "PetRequest.java"), + "public sealed interface PetRequest", + "permits CatRequest, DogRequest", + "PetType getPetType();"); + assertFileNotContains(Paths.get(modelDir + "PetRequest.java"), "class PetRequest"); + + assertFileContains(Paths.get(modelDir + "CatRequest.java"), + "public final class CatRequest", + "implements PetRequest", + "public PetType getPetType()"); + assertFileNotContains(Paths.get(modelDir + "CatRequest.java"), "extends PetRequest"); + + assertFileContains(Paths.get(modelDir + "DogRequest.java"), + "public final class DogRequest", + "implements PetRequest", + "public PetType getPetType()"); + assertFileNotContains(Paths.get(modelDir + "DogRequest.java"), "extends PetRequest"); + } + + /** + * With {@code useSealed=true} an allOf class hierarchy driven by a parent discriminator is + * generated as a sealed parent class that permits its subclasses; the subclasses extend the + * parent and become final. A middle tier with its own discriminator stays open downwards but + * closed to outsiders: it is sealed over its own subclasses while extending its parent. A + * standalone model with no subtypes becomes final, and the generated pom targets Java 17 + * (sealed types need JDK 17+). + */ + @Test + public void testSealedClassHierarchyGeneration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useSealed", "true"); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-spec") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/jaxrs-spec/sealed_hierarchy.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/"; + + assertFileContains(Paths.get(modelDir + "Pet.java"), + "public sealed class Pet", + "permits Cat, Dog"); + assertFileContains(Paths.get(modelDir + "Cat.java"), + "public sealed class Cat", + "extends Pet", + "permits PersianCat"); + assertFileNotContains(Paths.get(modelDir + "Cat.java"), "final class Cat"); + assertFileContains(Paths.get(modelDir + "PersianCat.java"), + "public final class PersianCat", + "extends Cat"); + assertFileContains(Paths.get(modelDir + "Dog.java"), + "public final class Dog", + "extends Pet"); + assertFileContains(Paths.get(modelDir + "Toy.java"), "public final class Toy"); + assertFileNotContains(Paths.get(modelDir + "Toy.java"), "sealed ", "permits "); + + assertFileContains(Paths.get(outputDir + "/pom.xml"), "17"); + } + + /** + * {@code useSealed=true} without {@code useOneOfInterfaces}: the oneOf container is rendered as + * a plain class whose oneOf members do not extend it, so it must not carry a sealed/permits + * clause over them (the generated code would not compile). Like any other model without + * subclasses it becomes final. + */ + @Test + public void testUseSealedWithoutOneOfInterfaces() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useSealed", "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 + "PetRequest.java"), "public final class PetRequest"); + assertFileNotContains(Paths.get(modelDir + "PetRequest.java"), "sealed ", "permits "); + assertFileContains(Paths.get(modelDir + "CatRequest.java"), "public final class CatRequest"); + assertFileContains(Paths.get(modelDir + "DogRequest.java"), "public final class DogRequest"); + assertFileContains(Paths.get(modelDir + "PetBase.java"), "public final class PetBase"); + } + + /** + * Without {@code useSealed} the output is unchanged: no sealed/final/permits modifiers are + * emitted (even though the permits list is populated on the models) and the generated pom + * still targets Java 1.8. + */ + @Test + public void testWithoutUseSealedOutputIsUnchanged() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + Map properties = new HashMap<>(); + properties.put("useOneOfInterfaces", "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 outputDir = output.getAbsolutePath().replace("\\", "/"); + String modelDir = outputDir + "/src/gen/java/org/openapitools/model/"; + + assertFileContains(Paths.get(modelDir + "PetRequest.java"), "public interface PetRequest"); + assertFileNotContains(Paths.get(modelDir + "PetRequest.java"), "sealed ", "permits "); + assertFileContains(Paths.get(modelDir + "CatRequest.java"), "public class CatRequest"); + assertFileNotContains(Paths.get(modelDir + "CatRequest.java"), "final class"); + + assertFileContains(Paths.get(outputDir + "/pom.xml"), "1.8"); + } + @Test public void testGenerateJsonNullableListFieldsHelperMethodReferences_issue23251() throws Exception { Map properties = new HashMap<>(); diff --git a/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/sealed_hierarchy.yaml b/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/sealed_hierarchy.yaml new file mode 100644 index 000000000000..b155857c7245 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/sealed_hierarchy.yaml @@ -0,0 +1,77 @@ +openapi: 3.0.3 +info: + title: sealed class hierarchy + description: > + An allOf class hierarchy driven by a parent discriminator. Under useSealed the + parent class is sealed and permits its subclasses, which extend it and become final. + Cat is a middle tier with its own discriminator: it is both a permitted subclass of + Pet and a sealed parent of PersianCat. + version: 1.0.0 +paths: + /pets: + post: + operationId: createPet + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + responses: + '201': + description: created +components: + schemas: + Pet: + type: object + required: + - petType + - name + properties: + petType: + type: string + name: + type: string + discriminator: + propertyName: petType + mapping: + CAT: '#/components/schemas/Cat' + DOG: '#/components/schemas/Dog' + + Cat: + allOf: + - $ref: '#/components/schemas/Pet' + - type: object + required: + - catType + properties: + catType: + type: string + indoor: + type: boolean + discriminator: + propertyName: catType + mapping: + PERSIAN: '#/components/schemas/PersianCat' + + PersianCat: + allOf: + - $ref: '#/components/schemas/Cat' + - type: object + properties: + longHair: + type: boolean + + Dog: + allOf: + - $ref: '#/components/schemas/Pet' + - type: object + properties: + trained: + type: boolean + + Toy: + type: object + properties: + name: + type: string diff --git a/samples/server/petstore/jaxrs-spec-sealed/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-sealed/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/.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-sealed/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-sealed/.openapi-generator/FILES new file mode 100644 index 000000000000..a83382320388 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/.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-sealed/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-sealed/.openapi-generator/VERSION new file mode 100644 index 000000000000..186c33c96ed8 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.24.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-sealed/README.md b/samples/server/petstore/jaxrs-spec-sealed/README.md new file mode 100644 index 000000000000..b9d190efc443 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/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-sealed/pom.xml b/samples/server/petstore/jaxrs-spec-sealed/pom.xml new file mode 100644 index 000000000000..ff879322dd21 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/pom.xml @@ -0,0 +1,149 @@ + + 4.0.0 + org.openapitools + jaxrs-spec-sealed-petstore-server + war + jaxrs-spec-sealed-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.19.2 + 5.14.4 + 2.10.13 + 1.3.2 + 2.0.2 + 2.1.6 + 0.2.10 + + diff --git a/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..29a135a553cf --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/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.24.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-sealed/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/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-sealed/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/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-sealed/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..3bd9a9080e81 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,142 @@ +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 java.io.Serializable; +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("CAT") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.24.0-SNAPSHOT") +public final class CatRequest implements Serializable, PetRequest { + private PetType petType; + private String name; + private Boolean indoor; + + public CatRequest() { + } + + @JsonCreator + public CatRequest( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name, + @JsonProperty(required = true, value = "indoor") Boolean indoor + ) { + this.petType = petType; + this.name = name; + this.indoor = indoor; + } + + /** + **/ + public CatRequest 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 CatRequest 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; + } + + /** + **/ + public CatRequest indoor(Boolean indoor) { + this.indoor = indoor; + return this; + } + + + @ApiModelProperty(required = true, value = "") + @JsonProperty(required = true, value = "indoor") + @NotNull public Boolean getIndoor() { + return indoor; + } + + @JsonProperty(required = true, value = "indoor") + public void setIndoor(Boolean indoor) { + this.indoor = indoor; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CatRequest catRequest = (CatRequest) o; + return Objects.equals(this.petType, catRequest.petType) && + Objects.equals(this.name, catRequest.name) && + Objects.equals(this.indoor, catRequest.indoor); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name, indoor); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CatRequest {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" indoor: ").append(toIndentedString(indoor)).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-sealed/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..20239c29c586 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,142 @@ +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 java.io.Serializable; +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("DOG") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", comments = "Generator version: 7.24.0-SNAPSHOT") +public final class DogRequest implements Serializable, PetRequest { + private PetType petType; + private String name; + private Boolean trained; + + public DogRequest() { + } + + @JsonCreator + public DogRequest( + @JsonProperty(required = true, value = "petType") PetType petType, + @JsonProperty(required = true, value = "name") String name, + @JsonProperty(required = true, value = "trained") Boolean trained + ) { + this.petType = petType; + this.name = name; + this.trained = trained; + } + + /** + **/ + public DogRequest 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 DogRequest 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; + } + + /** + **/ + public DogRequest trained(Boolean trained) { + this.trained = trained; + return this; + } + + + @ApiModelProperty(required = true, value = "") + @JsonProperty(required = true, value = "trained") + @NotNull public Boolean getTrained() { + return trained; + } + + @JsonProperty(required = true, value = "trained") + public void setTrained(Boolean trained) { + this.trained = trained; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DogRequest dogRequest = (DogRequest) o; + return Objects.equals(this.petType, dogRequest.petType) && + Objects.equals(this.name, dogRequest.name) && + Objects.equals(this.trained, dogRequest.trained); + } + + @Override + public int hashCode() { + return Objects.hash(petType, name, trained); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class DogRequest {\n"); + + sb.append(" petType: ").append(toIndentedString(petType)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" trained: ").append(toIndentedString(trained)).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-sealed/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..2ad4e6c717b4 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetBase.java @@ -0,0 +1,115 @@ +package org.openapitools.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.openapitools.model.PetType; +import java.io.Serializable; +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.24.0-SNAPSHOT") +public final class PetBase implements Serializable { + 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-sealed/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..a439f7536bc2 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetRequest.java @@ -0,0 +1,30 @@ +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 java.io.Serializable; +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.24.0-SNAPSHOT") +public sealed interface PetRequest extends Serializable permits CatRequest, DogRequest { + PetType getPetType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..d1640b03bdde --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/src/gen/java/org/openapitools/model/PetType.java @@ -0,0 +1,59 @@ +package org.openapitools.model; + +import io.swagger.annotations.ApiModel; +import java.io.Serializable; +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.24.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-sealed/src/main/openapi/openapi.yaml b/samples/server/petstore/jaxrs-spec-sealed/src/main/openapi/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/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