Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature][Java/Spring] Support Discriminator Based OneOf Interface #11650

Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
6a8769e
Fix OpenAPITools#5381
alexsuperdev Mar 21, 2020
049359c
Fix OpenAPITools#5381
alexsuperdev Mar 22, 2020
49f13eb
Fix OpenAPITools#5381
alexsuperdev Mar 22, 2020
1a5a484
Fix OpenAPITools#5381
alexsuperdev Mar 22, 2020
66a09d2
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
alexsuperdev Mar 22, 2020
48a1a4a
Fix OpenAPITools#5381
alexsuperdev Mar 24, 2020
a811330
Fix OpenAPITools#5381
alexsuperdev Mar 24, 2020
299cdb3
Fix OpenAPITools#5381
alexsuperdev Mar 24, 2020
461cbc8
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
alexsuperdev Mar 24, 2020
dd0118d
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
alexsuperdev Mar 25, 2020
26a95f6
Fix OpenAPITools#5381
alexsuperdev Mar 25, 2020
9af7db6
Fix OpenAPITools#5381
alexsuperdev Mar 30, 2020
fbfd57d
Fix OpenAPITools#5381
alexsuperdev Mar 21, 2020
bfab304
Fix OpenAPITools#5381
alexsuperdev Mar 22, 2020
29003d8
Fix OpenAPITools#5381
alexsuperdev Apr 1, 2020
d864831
Fix OpenAPITools#5381
alexsuperdev Apr 1, 2020
6d54799
Fix OpenAPITools#5381
alexsuperdev Apr 2, 2020
c6a5c6b
Merge remote-tracking branch 'super/master' into spring_fix_5381_jb
jburgess Dec 1, 2020
d96cd2e
Merge remote-tracking branch 'super/master' into spring_fix_5381_jb
jburgess Dec 3, 2020
8f09f52
Initial merge of 5.0
jburgess Dec 3, 2020
0d31df4
Aligned with master formatting
jburgess Dec 3, 2020
397e711
Corrected spacing for class names to align with samples.
jburgess Dec 4, 2020
a922217
Merge remote-tracking branch 'source/master' into spring_fix_5381_jb
jburgess Dec 5, 2020
21a98e5
Merge remote-tracking branch 'source/master' into spring_fix_5381_jb
jburgess Aug 11, 2021
1b5964e
Merge remote-tracking branch 'source/master' into spring_fix_5381_jb
jburgess Aug 11, 2021
05105fa
Merged master
jburgess Aug 11, 2021
c89a28b
Updated samples
jburgess Aug 11, 2021
4808e87
Merge branch 'spring_fix_5381_jb' of https://github.com/jburgess/open…
wing328 Sep 14, 2021
03a6210
Merge branch 'master' into jburgess-spring_fix_5381_jb
cachescrubber Jan 27, 2022
7db40af
Merge branch 'master' into jburgess-spring_fix_5381_jb
cachescrubber Jan 29, 2022
f634245
Consolidate methods from JavaClient and SpringCodegen (mov up to Abst…
cachescrubber Jan 29, 2022
921e9b8
set useLegacyDiscriminator to false, format templates
cachescrubber Jan 29, 2022
9502601
Suport JsonTypeName, fq class name for spring.io.Resource
cachescrubber Jan 30, 2022
054cfda
Generate Samples
cachescrubber Jan 30, 2022
cb998d4
Test full qualified usage of the spring Resource interface.
cachescrubber Jan 30, 2022
79e6439
Add java-camel to samples.circleci.spring profile
cachescrubber Jan 30, 2022
cbfa506
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Jan 30, 2022
7a93562
Add more complex example combining inheritance and oneof-interface
cachescrubber Jan 30, 2022
2773e1e
Remove x-implements Serializable from JavaClientCodegen (moved to Abs…
cachescrubber Jan 30, 2022
d850256
Fix spacing before opening brace after extends/implements
cachescrubber Jan 30, 2022
595fb2c
Generate Samples
cachescrubber Jan 30, 2022
6a542a0
Add more complex example combining inheritance and oneof-interface
cachescrubber Jan 30, 2022
da50e04
Generate Samples
cachescrubber Jan 30, 2022
ca1c72a
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Jan 31, 2022
e0d7905
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Jan 31, 2022
6dfe29e
Fix JsonTypeName annotation handling in Java and JavaSpring
cachescrubber Feb 2, 2022
3849661
Content mediatype is hardcoded in api.mustache #11511
cachescrubber Feb 5, 2022
79c80f8
Generate Samples
cachescrubber Feb 5, 2022
a1a4ff0
OAS3 incorrect data type when providing a default value #11367
cachescrubber Feb 5, 2022
bd6ba44
Generate Samples
cachescrubber Feb 5, 2022
4ff2187
Fix JsonTypeName annotation handling in Java and JavaSpring
cachescrubber Feb 2, 2022
45d1fd2
Generate Samples
cachescrubber Feb 5, 2022
2650814
Merge branch 'bugfix/spring_generator' into feature/java_spring_oneof…
cachescrubber Feb 5, 2022
25ac888
getIsClassnameSanitized: use null safe equals
cachescrubber Feb 5, 2022
fe29270
Merge branch 'bugfix/spring_generator' into feature/java_spring_oneof…
cachescrubber Feb 5, 2022
6e3150b
Fix JsonTypeName annotation handling in Java and JavaSpring (merge)
cachescrubber Feb 5, 2022
bcbd156
Generate Samples
cachescrubber Feb 5, 2022
5e77e8c
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 5, 2022
6202d69
Generate Samples
cachescrubber Feb 5, 2022
e20ba2c
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 9, 2022
d676188
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 10, 2022
122d414
Merge remote-tracking branch 'origin/feature/java_spring_oneof_discri…
cachescrubber Feb 10, 2022
c1ce27a
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 12, 2022
be407dc
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 15, 2022
26ae1a9
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 18, 2022
c0f153f
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 19, 2022
aaf6e99
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 23, 2022
c1a7192
Add oneof sample
cachescrubber Feb 23, 2022
925252e
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 23, 2022
58bd55b
Generate Samples
cachescrubber Feb 23, 2022
af28bbe
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Feb 25, 2022
d6558a8
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Mar 1, 2022
d03f748
Giv example oas spec a meaningful name, demo usage of oneOf in Model
cachescrubber Mar 2, 2022
b345151
Generate Samples
cachescrubber Mar 2, 2022
f8b70a8
Remove unnecessary JsonTypeName include, add example for JsonTypeName…
cachescrubber Mar 2, 2022
c161329
Generate Samples
cachescrubber Mar 2, 2022
833893a
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Mar 6, 2022
6e01140
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Mar 6, 2022
d43692e
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Mar 7, 2022
deeb394
Generate Samples
cachescrubber Mar 7, 2022
e619e73
Merge branch 'master' into feature/java_spring_oneof_discriminator_basic
cachescrubber Mar 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ public void postProcessParameter(CodegenParameter parameter) {
@Override
@SuppressWarnings("unused")
public void preprocessOpenAPI(OpenAPI openAPI) {
if (useOneOfInterfaces) {
if (useOneOfInterfaces && openAPI.getComponents() != null) {
// we process the openapi schema here to find oneOf schemas and create interface models for them
Map<String, Schema> schemas = new HashMap<>(openAPI.getComponents().getSchemas());
if (schemas == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,7 @@ public CodegenModel fromModel(String name, Schema model) {
if (codegenModel.discriminator != null && additionalProperties.containsKey(JACKSON)) {
codegenModel.imports.add("JsonSubTypes");
codegenModel.imports.add("JsonTypeInfo");
codegenModel.imports.add("JsonTypeName");
}
if (allDefinitions != null && codegenModel.parentSchema != null && codegenModel.hasEnums) {
final Schema parentModel = allDefinitions.get(codegenModel.parentSchema);
Expand Down Expand Up @@ -1316,6 +1317,16 @@ public Map<String, Object> postProcessModels(Map<String, Object> objs) {
}
}

// add x-implements for serializable to all models
List<Map<String, Object>> models = (List<Map<String, Object>>) objs.get("models");
for (Map<String, Object> mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");
if (this.serializableModel) {
cm.getVendorExtensions().putIfAbsent("x-implements", new ArrayList<String>());
((ArrayList<String>) cm.getVendorExtensions().get("x-implements")).add("Serializable");
}
}

return postProcessModelsEnum(objs);
}

Expand Down Expand Up @@ -1989,4 +2000,16 @@ protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Sc
}
}

@Override
public void addImportsToOneOfInterface(List<Map<String, String>> imports) {
if (additionalProperties.containsKey(JACKSON)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that GSON does't work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. There is a GSON implementation in okhttp-gson-nextgen and another java based generator. Does the spring generator supports GSON?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a configuration option for it, but I'm not sure how widely used ti it

for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo", "JsonTypeName")) {
Map<String, String> oneImport = new HashMap<>();
oneImport.put("import", importMapping.get(i));
if (!imports.contains(oneImport)) {
imports.add(oneImport);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -896,9 +896,6 @@ public Map<String, Object> postProcessModels(Map<String, Object> objs) {
if (this.parcelableModel) {
((ArrayList<String>) cm.getVendorExtensions().get("x-implements")).add("Parcelable");
}
if (this.serializableModel) {
cachescrubber marked this conversation as resolved.
Show resolved Hide resolved
((ArrayList<String>) cm.getVendorExtensions().get("x-implements")).add("Serializable");
}
}

return objs;
Expand Down Expand Up @@ -1036,14 +1033,4 @@ public String toApiVarName(String name) {
return apiVarName;
}

@Override
public void addImportsToOneOfInterface(List<Map<String, String>> imports) {
for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) {
Map<String, String> oneImport = new HashMap<>();
oneImport.put("import", importMapping.get(i));
if (!imports.contains(oneImport)) {
imports.add(oneImport);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ public void processOpts() {
}

super.processOpts();
useOneOfInterfaces = true;
legacyDiscriminatorBehavior = false;

if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) {
LOGGER.warn("The springfox documentation provider is deprecated for removal. Use the springdoc provider instead.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import javax.annotation.Generated;
{{>enumOuterClass}}
{{/isEnum}}
{{^isEnum}}
{{>pojo}}
{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}}
cachescrubber marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still necessary after #11784 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, very much so. It the model entity is a one-of-interface, a public interface MyModel is generated instead of a public class myModel. Or do I miss something?

{{/isEnum}}
{{/model}}
{{/models}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{>additionalModelTypeAnnotations}}
{{#withXml}}
{{>xmlAnnotation}}
{{/withXml}}
{{#discriminator}}
{{>typeInfoAnnotation}}
{{/discriminator}}
{{>generatedAnnotation}}
public interface {{classname}}{{#vendorExtensions.x-implements}}{{#-first}} extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{#discriminator}}
public {{propertyType}} {{propertyGetter}}();
{{/discriminator}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
{{>xmlAnnotation}}
{{/withXml}}
{{>generatedAnnotation}}
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{^parent}}{{#hateoas}}extends RepresentationModel<{{classname}}> {{/hateoas}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} {
public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}{{#hateoas}} extends RepresentationModel<{{classname}}> {{/hateoas}}{{/parent}}{{#vendorExtensions.x-implements}}{{#-first}} implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{#serializableModel}}

private static final long serialVersionUID = 1L;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
{{#jackson}}
{{#discriminator.mappedModels}}
{{#-first}}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
@JsonSubTypes({
{{#discriminator.mappedModels}}
@JsonSubTypes.Type(value = {{modelName}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{mappingName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"),
{{/discriminator.mappedModels}}
}){{/jackson}}
{{/-first}}
{{^vendorExtensions.x-discriminator-value}}
@JsonSubTypes.Type(value = {{modelName}}.class, name = "{{{mappingName}}}"){{^-last}},{{/-last}}
{{/vendorExtensions.x-discriminator-value}}
{{#vendorExtensions.x-discriminator-value}}
@JsonSubTypes.Type(value = {{modelName}}.class, name = "{{{vendorExtensions.x-discriminator-value}}}"){{^-last}},{{/-last}}
{{/vendorExtensions.x-discriminator-value}}
{{#-last}}
})
{{/-last}}
{{/discriminator.mappedModels}}
{{/jackson}}
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,44 @@ public void shouldNotAddNotNullOnReadOnlyAttributes() throws IOException {

}

@Test
public void oneOf_5381() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
String outputPath = output.getAbsolutePath().replace('\\', '/');
OpenAPI openAPI = new OpenAPIParser()
.readLocation("src/test/resources/3_0/issue_5381.yaml", null, new ParseOptions()).getOpenAPI();

SpringCodegen codegen = new SpringCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true");
codegen.setUseOneOfInterfaces(true);

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

DefaultGenerator generator = new DefaultGenerator();
codegen.setHateoas(true);
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
//generator.setGeneratorPropertyDefault(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false");

codegen.setUseOneOfInterfaces(true);
codegen.setLegacyDiscriminatorBehavior(false);

generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");

generator.opts(input).generate();

assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Foo.java"), "public class Foo implements FooRefOrValue");
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRef.java"), "public class FooRef implements FooRefOrValue");
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRefOrValue.java"), "public interface FooRefOrValue");
}

@Test
public void testTypeMappings() {
final SpringCodegen codegen = new SpringCodegen();
Expand Down
134 changes: 134 additions & 0 deletions modules/openapi-generator/src/test/resources/3_0/issue_5381.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
openapi: 3.0.1
info:
title: ByRefOrValue
description: >
This tests for a oneOf interface representation
version: 0.0.1
servers:
- url: "http://localhost:8080"
tags:
- name: Foo
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'

components:
schemas:
Entity:
type: object
allOf:
- "$ref": "#/components/schemas/Addressable"
- "$ref": "#/components/schemas/Extensible"

EntityRef:
description: Entity reference schema to be use for all entityRef class.
type: object
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"


Addressable:
type: object
properties:
href:
type: string
description: Hyperlink reference
id:
type: string
description: unique identifier
description: Base schema for adressable 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'

FooRefOrValue:
cachescrubber marked this conversation as resolved.
Show resolved Hide resolved
type: object
oneOf:
- $ref: "#/components/schemas/Foo"
- $ref: "#/components/schemas/FooRef"
discriminator:
propertyName: "@type"
mapping:
Foo: "#/components/schemas/Foo"
FooRef: "#/components/schemas/FooRef"

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'

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