diff --git a/.github/workflows/samples-jaxrs.yaml b/.github/workflows/samples-jaxrs.yaml index 9153832bb828..cffa7b7b3a70 100644 --- a/.github/workflows/samples-jaxrs.yaml +++ b/.github/workflows/samples-jaxrs.yaml @@ -23,6 +23,7 @@ jobs: - samples/server/petstore/jaxrs-spec-withxml - samples/server/petstore/jaxrs-spec-interface - samples/server/petstore/jaxrs-spec-interface-response + - samples/server/petstore/jaxrs-spec-oneof-interface - samples/server/petstore/jaxrs-datelib-j8 - samples/server/petstore/jaxrs-resteasy/default - samples/server/petstore/jaxrs-resteasy/eap diff --git a/.github/workflows/samples-jdk17.yaml b/.github/workflows/samples-jdk17.yaml index f55a606e47df..82d57c817434 100644 --- a/.github/workflows/samples-jdk17.yaml +++ b/.github/workflows/samples-jdk17.yaml @@ -22,6 +22,8 @@ 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/** + - samples/server/petstore/jaxrs-spec-records/** pull_request: paths: # clients @@ -44,6 +46,8 @@ 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/** + - samples/server/petstore/jaxrs-spec-records/** jobs: build: name: Build with JDK17 @@ -72,6 +76,8 @@ 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 + - samples/server/petstore/jaxrs-spec-records steps: - uses: actions/checkout@v7 - uses: actions/setup-java@v5 diff --git a/bin/configs/jaxrs-spec-oneof-interface.yaml b/bin/configs/jaxrs-spec-oneof-interface.yaml new file mode 100644 index 000000000000..d10ccaa50a56 --- /dev/null +++ b/bin/configs/jaxrs-spec-oneof-interface.yaml @@ -0,0 +1,9 @@ +generatorName: jaxrs-spec +outputDir: samples/server/petstore/jaxrs-spec-oneof-interface +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-oneof-interface-petstore-server + useOneOfInterfaces: "true" + serializableModel: "true" + hideGenerationTimestamp: "true" diff --git a/bin/configs/jaxrs-spec-records.yaml b/bin/configs/jaxrs-spec-records.yaml new file mode 100644 index 000000000000..81b72cffee16 --- /dev/null +++ b/bin/configs/jaxrs-spec-records.yaml @@ -0,0 +1,11 @@ +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" + serializableModel: "true" + hideGenerationTimestamp: "true" 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/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 c48002c8ba3c..1bd84f5f172d 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 @@ -32,8 +32,12 @@ import org.openapitools.codegen.model.OperationsMap; 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; @@ -56,6 +60,8 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen { public static final String OPEN_API_SPEC_FILE_LOCATION = "openApiSpecFileLocation"; public static final String GENERATE_JSON_CREATOR = "generateJsonCreator"; public static final String USE_JAKARTA_SECURITY_ANNOTATIONS = "useJakartaSecurityAnnotations"; + 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"; @@ -73,6 +79,12 @@ public class JavaJAXRSSpecServerCodegen extends AbstractJavaJAXRSServerCodegen { private boolean useMutiny = false; private boolean useJakartaSecurityAnnotations = false; + @Setter + protected boolean useSealed = false; + + @Setter + protected boolean useRecords = false; + private final JakartaSecurityAnnotationProcessor jakartaSecurityAnnotationProcessor = new JakartaSecurityAnnotationProcessor(); @Getter @Setter @@ -155,6 +167,8 @@ public JavaJAXRSSpecServerCodegen() { cliOptions.add(CliOption.newBoolean(USE_MUTINY, "Whether to use Smallrye Mutiny instead of CompletionStage for asynchronous computation. Only valid when library is set to quarkus.", useMutiny)); 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_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.", useRecords)); } @Override @@ -197,6 +211,8 @@ public void processOpts() { } convertPropertyToBooleanAndWriteBack(GENERATE_JSON_CREATOR, this::setGenerateJsonCreator); + 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(); @@ -385,25 +401,96 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List postProcessAllModels(Map objs) { Map result = super.postProcessAllModels(objs); + + // 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 (model.parentModel != null) { - CodegenDiscriminator discriminator = model.parentModel.getDiscriminator(); - if (discriminator != null) { - for (CodegenDiscriminator.MappedModel mappedModel : discriminator.getMappedModels()) { - if (mappedModel.getSchemaName().equals(model.schemaName)) { - model.getVendorExtensions().put("x-discriminator-value", mappedModel.getMappingName()); - break; - } + 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()); + } + } + } + } + + for (ModelsMap modelsMap : result.values()) { + for (ModelMap modelMap : modelsMap.getModels()) { + CodegenModel model = modelMap.getModel(); + // Resolve the @JsonTypeName mapping value from the Java parent's discriminator, if any, + // otherwise from the discriminator of the oneOf interface the model implements. + CodegenDiscriminator discriminator = model.parentModel != null + ? model.parentModel.getDiscriminator() + : discriminatorOfImplementedOneOfInterface(model, oneOfInterfaceDiscriminators); + if (discriminator != null) { + for (CodegenDiscriminator.MappedModel mappedModel : discriminator.getMappedModels()) { + if (mappedModel.getSchemaName().equals(model.schemaName)) { + model.getVendorExtensions().put("x-discriminator-value", mappedModel.getMappingName()); + break; } } } + if (useRecords && isOneOfInterfaceRecordCandidate(model, oneOfInterfaceNames)) { + model.getVendorExtensions().put("x-jaxrs-record", true); + } } } return result; } + /** + * Returns the discriminator of the oneOf interface (produced by useOneOfInterfaces) that the given + * model implements, or {@code null} if the model does not implement such an interface. The interface + * name is read from the model's {@code x-implements} vendor extension. + */ + @SuppressWarnings("unchecked") + private CodegenDiscriminator discriminatorOfImplementedOneOfInterface( + CodegenModel model, Map oneOfInterfaceDiscriminators) { + Object implementsExtension = model.getVendorExtensions().get("x-implements"); + if (!(implementsExtension instanceof Collection)) { + return null; + } + for (Object intf : (Collection) implementsExtension) { + CodegenDiscriminator discriminator = oneOfInterfaceDiscriminators.get(String.valueOf(intf)); + if (discriminator != null) { + return discriminator; + } + } + return null; + } + + /** + * A concrete model is rendered as a record only when it implements a oneOf interface produced by the + * useOneOfInterfaces feature, and it is structurally record-compatible: it has no Java parent (records + * cannot extend) and no additional (undeclared) properties (those require a mutable map-backed pojo). + * + * @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.getParent() != null || model.getAdditionalPropertiesType() != null) { + 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/additionalOneOfTypeAnnotations.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/additionalOneOfTypeAnnotations.mustache new file mode 100644 index 000000000000..283f8f91e746 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/additionalOneOfTypeAnnotations.mustache @@ -0,0 +1,2 @@ +{{#additionalOneOfTypeAnnotations}}{{{.}}} +{{/additionalOneOfTypeAnnotations}} \ No newline at end of file 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 03d5488e4bc3..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}}{{>pojo}}{{/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 new file mode 100644 index 000000000000..9bc84ee88a29 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/oneof_interface.mustache @@ -0,0 +1,21 @@ +{{>additionalOneOfTypeAnnotations}} +{{#discriminator}} +{{>typeInfoAnnotation}} + +{{/discriminator}}{{^discriminator}}{{#useDeductionForOneOfInterfaces}} +@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) +@JsonSubTypes({ + {{#interfaceModels}} + @JsonSubTypes.Type(value = {{classname}}.class){{^-last}}, {{/-last}} + {{/interfaceModels}} +}) +{{/useDeductionForOneOfInterfaces}}{{#vendorExtensions.x-class-extra-annotation}}{{{vendorExtensions.x-class-extra-annotation}}} +{{/vendorExtensions.x-class-extra-annotation}} +{{/discriminator}} +{{>generatedAnnotation}} + +public {{>sealed}}interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {{>permits}}{ + {{#discriminator}} + {{propertyType}} {{#useRecords}}{{propertyName}}{{/useRecords}}{{^useRecords}}{{propertyGetter}}{{/useRecords}}(); + {{/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 d39597fad10d..3be93a4ff7a2 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}}} {{/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 0550dfa84f1f..cf6c589cc32b 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pom.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/spec/pom.mustache @@ -180,7 +180,7 @@ {{/openApiNullable}} - 1.8 + {{#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 new file mode 100644 index 000000000000..6c860355c15f --- /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}}{{^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 f56f80985667..51d589141c57 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,117 @@ 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. + */ + @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(); + + // assertFileContains is used rather than JavaFileAssert because the latter parses the source + // with a JavaParser language level that predates sealed types and would reject the `sealed` + // and `permits` keywords. + String modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + // The oneOf schema becomes a sealed interface that permits its subtypes, and declares the + // discriminator getter with the resolved enum type rather than String. + assertFileContains(Paths.get(modelDir + "PetRequest.java"), + "public sealed interface PetRequest", + "permits CatRequest, DogRequest", + "PetType getPetType();"); + // an interface is not a class and must not extend a parent + assertFileNotContains(Paths.get(modelDir + "PetRequest.java"), "class PetRequest"); + + // The concrete subtypes are final and implement (not extend) the interface, with a matching + // getter return type, so there is no cyclical extends/implements and no return-type clash. + 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 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"); + } + @Test public void testGenerateJsonNullableListFieldsHelperMethodReferences_issue23251() throws Exception { Map properties = new HashMap<>(); @@ -2106,4 +2217,60 @@ private String generateQuarkusItemsApi(String specPath, boolean interfaceOnly, b TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/ItemsApi.java"); return Files.readString(output.toPath().resolve("src/gen/java/org/openapitools/api/ItemsApi.java")); } + + /** + * With {@code useOneOfInterfaces=true} a oneOf schema is generated as a Java interface, and the + * concrete subtypes implement (not extend) it. The discriminator property is declared only on a + * shared non-discriminator base (acyclic pattern), so the interface getter type resolves to the + * enum model (PetType) from the mapped children rather than falling back to String. + */ + @Test + public void testOneOfInterfaceGeneration() 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 modelDir = output.getAbsolutePath().replace("\\", "/") + "/src/gen/java/org/openapitools/model/"; + + // The oneOf schema becomes an interface declaring the discriminator getter with the resolved + // enum type rather than String. + assertFileContains(Paths.get(modelDir + "PetRequest.java"), + "public interface PetRequest", + "PetType getPetType();"); + // an interface is not a class and must not extend a parent + assertFileNotContains(Paths.get(modelDir + "PetRequest.java"), "class PetRequest"); + + // The concrete subtypes implement (not extend) the interface, with a matching getter return type, + // so there is no cyclical extends/implements and no return-type clash. + assertFileContains(Paths.get(modelDir + "CatRequest.java"), + "public class CatRequest", + "implements PetRequest", + "public PetType getPetType()"); + assertFileNotContains(Paths.get(modelDir + "CatRequest.java"), "extends PetRequest"); + + assertFileContains(Paths.get(modelDir + "DogRequest.java"), + "public class DogRequest", + "implements PetRequest", + "public PetType getPetType()"); + assertFileNotContains(Paths.get(modelDir + "DogRequest.java"), "extends PetRequest"); + + // The @JsonTypeName of each subtype is the discriminator mapping value (CAT/DOG), resolved from + // the oneOf interface it implements, not the class name - so polymorphic (de)serialization keys + // off the discriminator value and round-trips with the @JsonSubTypes mapping on the interface. + assertFileContains(Paths.get(modelDir + "CatRequest.java"), "@JsonTypeName(\"CAT\")"); + assertFileNotContains(Paths.get(modelDir + "CatRequest.java"), "@JsonTypeName(\"CatRequest\")"); + assertFileContains(Paths.get(modelDir + "DogRequest.java"), "@JsonTypeName(\"DOG\")"); + assertFileNotContains(Paths.get(modelDir + "DogRequest.java"), "@JsonTypeName(\"DogRequest\")"); + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml b/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml new file mode 100644 index 000000000000..44bb4ace2a97 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/jaxrs-spec/oneof_interface.yaml @@ -0,0 +1,77 @@ +openapi: 3.0.3 +info: + title: oneOf interface + 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. + version: 1.0.0 +paths: + /pets: + post: + operationId: createPet + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PetRequest' + responses: + '201': + description: created +components: + schemas: + PetType: + type: string + enum: + - CAT + - DOG + description: Discriminator value identifying the type of pet + + PetRequest: + type: object + properties: + petType: + $ref: '#/components/schemas/PetType' + oneOf: + - $ref: '#/components/schemas/CatRequest' + - $ref: '#/components/schemas/DogRequest' + discriminator: + propertyName: petType + mapping: + CAT: '#/components/schemas/CatRequest' + DOG: '#/components/schemas/DogRequest' + + PetBase: + type: object + required: + - petType + - name + properties: + petType: + $ref: '#/components/schemas/PetType' + name: + type: string + + CatRequest: + type: object + allOf: + - $ref: '#/components/schemas/PetBase' + - type: object + required: + - indoor + properties: + indoor: + type: boolean + + DogRequest: + type: object + allOf: + - $ref: '#/components/schemas/PetBase' + - type: object + required: + - trained + properties: + trained: + type: boolean diff --git a/samples/server/petstore/jaxrs-spec-oneof-interface/.openapi-generator-ignore b/samples/server/petstore/jaxrs-spec-oneof-interface/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/.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-oneof-interface/.openapi-generator/FILES b/samples/server/petstore/jaxrs-spec-oneof-interface/.openapi-generator/FILES new file mode 100644 index 000000000000..a83382320388 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/.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-oneof-interface/.openapi-generator/VERSION b/samples/server/petstore/jaxrs-spec-oneof-interface/.openapi-generator/VERSION new file mode 100644 index 000000000000..186c33c96ed8 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.24.0-SNAPSHOT diff --git a/samples/server/petstore/jaxrs-spec-oneof-interface/README.md b/samples/server/petstore/jaxrs-spec-oneof-interface/README.md new file mode 100644 index 000000000000..b9d190efc443 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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-oneof-interface/pom.xml b/samples/server/petstore/jaxrs-spec-oneof-interface/pom.xml new file mode 100644 index 000000000000..1386909ba560 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/pom.xml @@ -0,0 +1,145 @@ + + 4.0.0 + org.openapitools + jaxrs-spec-oneof-interface-petstore-server + war + jaxrs-spec-oneof-interface-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-failsafe-plugin + 2.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 + + + junit + junit + ${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} + + + + 1.8 + ${java.version} + ${java.version} + UTF-8 + 2.19.2 + 4.13.2 + 2.10.13 + 1.3.2 + 2.0.2 + 2.1.6 + 0.2.10 + + diff --git a/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/api/PetsApi.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/api/PetsApi.java new file mode 100644 index 000000000000..29a135a553cf --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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-oneof-interface/src/gen/java/org/openapitools/api/RestApplication.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/api/RestApplication.java new file mode 100644 index 000000000000..7df2d0fe3334 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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-oneof-interface/src/gen/java/org/openapitools/api/RestResourceRoot.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/api/RestResourceRoot.java new file mode 100644 index 000000000000..727f0dfe3fb3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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-oneof-interface/src/gen/java/org/openapitools/model/CatRequest.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/model/CatRequest.java new file mode 100644 index 000000000000..f66686622fce --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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 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-oneof-interface/src/gen/java/org/openapitools/model/DogRequest.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/model/DogRequest.java new file mode 100644 index 000000000000..8aa6f2994ed3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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 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-oneof-interface/src/gen/java/org/openapitools/model/PetBase.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/model/PetBase.java new file mode 100644 index 000000000000..71f101fe459e --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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 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-oneof-interface/src/gen/java/org/openapitools/model/PetRequest.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/model/PetRequest.java new file mode 100644 index 000000000000..f43abcdd8c44 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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 interface PetRequest extends Serializable { + PetType getPetType(); +} + diff --git a/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/model/PetType.java b/samples/server/petstore/jaxrs-spec-oneof-interface/src/gen/java/org/openapitools/model/PetType.java new file mode 100644 index 000000000000..d1640b03bdde --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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-oneof-interface/src/main/openapi/openapi.yaml b/samples/server/petstore/jaxrs-spec-oneof-interface/src/main/openapi/openapi.yaml new file mode 100644 index 000000000000..d25698f6a4c1 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-oneof-interface/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 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..186c33c96ed8 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.24.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..58b09bf19af9 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/pom.xml @@ -0,0 +1,145 @@ + + 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-failsafe-plugin + 2.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 + + + junit + junit + ${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 + 4.13.2 + 2.10.13 + 1.3.2 + 2.0.2 + 2.1.6 + 0.2.10 + + 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..29a135a553cf --- /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.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-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..896a26e7c1c3 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/CatRequest.java @@ -0,0 +1,28 @@ +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 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.24.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 Serializable, 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..081da6e277ac --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/src/gen/java/org/openapitools/model/DogRequest.java @@ -0,0 +1,28 @@ +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 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.24.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 Serializable, 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..2ad4e6c717b4 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/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-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..2875ec459566 --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/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 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..d1640b03bdde --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-records/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-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 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..a648331ff4ef --- /dev/null +++ b/samples/server/petstore/jaxrs-spec-sealed/pom.xml @@ -0,0 +1,145 @@ + + 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-failsafe-plugin + 2.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 + + + junit + junit + ${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 + 4.13.2 + 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..d48549410123 --- /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("CatRequest") +@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..9a1553c8d743 --- /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("DogRequest") +@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