Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/samples-java-client-jdk17.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
- samples/client/petstore/java/webclient-jakarta/**
- samples/client/petstore/java/restclient-*/**
- samples/client/others/java/webclient-sealedInterface/**
- samples/client/others/java/webclient-sealedInterface_3_1/**
- samples/client/petstore/java/webclient-useSingleRequestParameter/**
- samples/client/others/java/restclient-enum-in-multipart/**
pull_request:
Expand All @@ -15,6 +16,7 @@ on:
- samples/client/petstore/java/webclient-jakarta/**
- samples/client/petstore/java/restclient-*/**
- samples/client/others/java/webclient-sealedInterface/**
- samples/client/others/java/webclient-sealedInterface_3_1/**
- samples/client/petstore/java/webclient-useSingleRequestParameter/**
- samples/client/others/java/restclient-enum-in-multipart/**
jobs:
Expand All @@ -34,6 +36,7 @@ jobs:
- samples/client/petstore/java/restclient-useSingleRequestParameter
- samples/client/petstore/java/restclient-useSingleRequestParameter-static
- samples/client/others/java/webclient-sealedInterface
- samples/client/others/java/webclient-sealedInterface_3_1
- samples/client/petstore/java/webclient-useSingleRequestParameter
- samples/client/others/java/restclient-enum-in-multipart
steps:
Expand Down
10 changes: 10 additions & 0 deletions bin/configs/java-webclient-sealedInterface-3.1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
generatorName: java
outputDir: samples/client/others/java/webclient-sealedInterface_3_1
library: webclient
inputSpec: modules/openapi-generator/src/test/resources/3_1/oneof_polymorphism_and_inheritance.yaml
templateDir: modules/openapi-generator/src/main/resources/Java
additionalProperties:
artifactId: sealed-interface-webclient
hideGenerationTimestamp: "true"
useOneOfInterfaces: true
useSealedOneOfInterfaces: true
Original file line number Diff line number Diff line change
Expand Up @@ -3301,7 +3301,7 @@ private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc,
}

if (refSchema.getProperties() != null && refSchema.getProperties().get(discPropName) != null) {
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, (Schema) refSchema.getProperties().get(discPropName));
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, getDiscriminatorSchema(refSchema, discPropName));
CodegenProperty cp = new CodegenProperty();
if (ModelUtils.isStringSchema(discSchema)) {
cp.isString = true;
Expand Down Expand Up @@ -3632,14 +3632,7 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
// FIXME: there are other ways to define the type of the discriminator property (inline
// for example). Handling those scenarios is too complicated for me, I'm leaving it for
// the future..
String propertyType =
Optional.ofNullable(schema.getProperties())
.map(p -> (Schema<?>) p.get(discriminatorPropertyName))
.map(Schema::get$ref)
.map(ModelUtils::getSimpleRef)
.map(this::toModelName)
.orElseGet(() -> typeMapping.get("string"));
discriminator.setPropertyType(propertyType);
discriminator.setPropertyType(getDiscriminatorPropertyType(schema, discriminatorPropertyName));

// check to see if the discriminator property is an enum string
boolean isEnum = Optional
Expand Down Expand Up @@ -3703,6 +3696,39 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
return discriminator;
}

/**
* Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
* An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
* referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
*
* @param schema The input OAS schema.
* @param discriminatorName The name of the discriminator property.
*/
protected Schema getDiscriminatorSchema(Schema schema, String discriminatorName) {
if (schema.getProperties() == null) {
return null;
}
Schema discSchema = (Schema) schema.getProperties().get(discriminatorName);
if (ModelUtils.isAllOf(discSchema)) {
discSchema = (Schema) discSchema.getAllOf().get(0);
}
return discSchema;
}

/**
* Get the property type for the discriminator
*
* @param schema The input OAS schema.
* @param discriminatorPropertyName The name of the discriminator property.
*/
protected String getDiscriminatorPropertyType(Schema schema, String discriminatorPropertyName) {
return Optional.ofNullable(getDiscriminatorSchema(schema, discriminatorPropertyName))
.map(Schema::get$ref)
.map(ModelUtils::getSimpleRef)
.map(this::toModelName)
.orElseGet(() -> typeMapping.get("string"));
}

/**
* Handle the model for the 'additionalProperties' keyword in the OAS schema.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,23 @@ public void testDiscriminatorWithCustomMapping() {
assertTrue(personModel.getHasDiscriminatorWithNonEmptyMapping());
}

@Test
public void testEnumDiscriminatorWithDescriptionOverridden3_1() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_1/oneof_polymorphism_and_inheritance.yaml");
new OpenAPINormalizer(openAPI, Map.of()).normalize();
DefaultCodegen codegen = new DefaultCodegen();
codegen.setUseOneOfInterfaces(true);

Schema fruit = openAPI.getComponents().getSchemas().get("Fruit");
codegen.setOpenAPI(openAPI);
CodegenModel fruitModel = codegen.fromModel("Fruit", fruit);
assertTrue(fruitModel.getHasDiscriminatorWithNonEmptyMapping());
assertTrue(fruitModel.discriminator.getIsEnum());
assertEquals("FruitType", fruitModel.discriminator.getPropertyType());
assertEquals("test", fruitModel.getVars().get(0).description);
assertTrue(fruitModel.getVars().get(0).isEnumRef);
}

@Test
public void testParentName() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/allOf.yaml");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4063,4 +4063,13 @@ public void testOneOfInterfaceWithAnnotation() {
.isInterface()
.assertTypeAnnotations().containsWithName("SuppressWarnings");
}

@Test
public void testOneOfInterfaceWithEnumDiscriminatorHavingCustomDescription3_1() {
final Map<String, File> files = generateFromContract("src/test/resources/3_1/oneof_polymorphism_and_inheritance.yaml", WEBCLIENT,
Map.of(USE_ONE_OF_INTERFACES, "true"));
JavaFileAssert.assertThat(files.get("Fruit.java"))
.isInterface()
.fileContains("public FruitType getFruitType()");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
openapi: 3.1.0
info:
title: ByRefOrValue
description: >
This tests for a oneOf interface representation
version: 0.0.1
servers:
- url: "http://localhost:8080"
tags:
- name: Foo
- name: Bar
paths:
/foo:
get:
tags:
- Foo
summary: GET all Foos
operationId: getAllFoos
responses:
'200':
$ref: '#/components/responses/200FooArray'
post:
tags:
- Foo
summary: Create a Foo
operationId: createFoo
requestBody:
$ref: '#/components/requestBodies/Foo'
responses:
'201':
$ref: '#/components/responses/201Foo'
/bar:
post:
tags:
- Bar
summary: Create a Bar
operationId: createBar
requestBody:
required: true
content:
'application/json':
schema:
$ref: '#/components/schemas/Bar_Create'
responses:
200:
description: Bar created
content:
'application/json':
schema:
$ref: '#/components/schemas/Bar'

components:
schemas:
Addressable:
type: object
properties:
href:
type: string
description: Hyperlink reference
id:
type: string
description: unique identifier
description: Base schema for addressable entities
Extensible:
type: object
properties:
"@schemaLocation":
type: string
description: A URI to a JSON-Schema file that defines additional attributes
and relationships
"@baseType":
type: string
description: When sub-classing, this defines the super-class
"@type":
type: string
description: When sub-classing, this defines the sub-class Extensible name
required:
- '@type'
Entity:
type: object
discriminator:
propertyName: '@type'
allOf:
- "$ref": "#/components/schemas/Addressable"
- "$ref": "#/components/schemas/Extensible"
EntityRef:
type: object
discriminator:
propertyName: '@type'
description: Entity reference schema to be use for all entityRef class.
properties:
name:
type: string
description: Name of the related entity.
'@referredType':
type: string
description: The actual type of the target instance when needed for disambiguation.
allOf:
- $ref: '#/components/schemas/Addressable'
- "$ref": "#/components/schemas/Extensible"
FooRefOrValue:
type: object
oneOf:
- $ref: "#/components/schemas/Foo"
- $ref: "#/components/schemas/FooRef"
discriminator:
propertyName: "@type"
Foo:
type: object
properties:
fooPropA:
type: string
fooPropB:
type: string
allOf:
- $ref: '#/components/schemas/Entity'
FooRef:
type: object
properties:
foorefPropA:
type: string
allOf:
- $ref: '#/components/schemas/EntityRef'
BarRef:
type: object
allOf:
- $ref: '#/components/schemas/EntityRef'
Bar_Create:
type: object
properties:
barPropA:
type: string
fooPropB:
type: string
foo:
$ref: '#/components/schemas/FooRefOrValue'
allOf:
- $ref: '#/components/schemas/Entity'
Bar:
type: object
required:
- id
properties:
id:
type: string
barPropA:
type: string
fooPropB:
type: string
foo:
$ref: '#/components/schemas/FooRefOrValue'
allOf:
- $ref: '#/components/schemas/Entity'
BarRefOrValue:
type: object
oneOf:
- $ref: "#/components/schemas/Bar"
- $ref: "#/components/schemas/BarRef"
Pizza:
type: object
properties:
pizzaSize:
type: number
allOf:
- $ref: '#/components/schemas/Entity'
Pasta:
type: object
properties:
vendor:
type: string
allOf:
- $ref: '#/components/schemas/Entity'
PizzaSpeziale:
type: object
properties:
toppings:
type: string
allOf:
- $ref: '#/components/schemas/Pizza'
FruitType:
type: string
enum: [APPLE, BANANA]
Fruit:
type: object
properties:
fruitType:
$ref: "#/components/schemas/FruitType"
description: "test"
required:
- fruitType
oneOf:
- $ref: '#/components/schemas/Apple'
- $ref: '#/components/schemas/Banana'
discriminator:
propertyName: fruitType
mapping:
APPLE: '#/components/schemas/Apple'
BANANA: '#/components/schemas/Banana'
Apple:
type: object
required:
- seeds
properties:
seeds:
type: integer
Banana:
type: object
required:
- length
properties:
length:
type: integer
Animal:
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
Cat:
type: object
properties:
declawed:
type: boolean
Dog:
type: object
properties:
bark:
type: boolean

requestBodies:
Foo:
description: The Foo to be created
content:
application/json;charset=utf-8:
schema:
$ref: '#/components/schemas/Foo'

responses:
'204':
description: Deleted
content: { }
201Foo:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/FooRefOrValue'
200FooArray:
description: Success
content:
application/json;charset=utf-8:
schema:
type: array
items:
$ref: '#/components/schemas/FooRefOrValue'
Loading
Loading