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

[Java/Spring] all-of and one-of Improvements and Fixes #12075

Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
da4712c
Add config to reproduce the issue
cachescrubber Apr 5, 2022
af9d7b3
Add test case to reproduce issue.
cachescrubber Apr 5, 2022
628de7d
Debug Session: identify critical codep path
cachescrubber Apr 6, 2022
3a26775
Works exactly as needed for oneOf/allOf in Java/Spring
cachescrubber Apr 6, 2022
ca6ee6e
Add allVars to omit list in OneOfImplementorAdditionalData
cachescrubber Apr 7, 2022
a4d79b3
SpringCodegen: Support parentVars in order to support fluent setter w…
cachescrubber Apr 7, 2022
34fe8af
Generate Samples
cachescrubber Apr 7, 2022
751455f
Add imports for inherited Properties
cachescrubber Apr 7, 2022
3fd8712
Add JavaDoc
cachescrubber Apr 7, 2022
3bb412a
Polishing
cachescrubber Apr 7, 2022
e224d61
add a link to zozo tech blog post
wing328 Apr 5, 2022
e7075d2
[java] Add jersey3 support to the Java client (#12046)
wing328 Apr 5, 2022
10e1a60
more checks in validateJsonObject (#12041)
wing328 Apr 5, 2022
4827d74
add response headers to api exception (#12042)
wing328 Apr 5, 2022
91bfb2f
[Ruby] Fix incorrectly capitalized identifier in apis template (#12045)
harmony7 Apr 5, 2022
726dcc0
update jackson databind to newer version (#12053)
wing328 Apr 5, 2022
7ebd09e
[PowerShell] add more tests to powershell client (#12057)
wing328 Apr 6, 2022
0924cab
comment out error message debug (#12056)
wing328 Apr 6, 2022
3f197e4
Reduce casting for operations processing (#12002)
borsch Apr 6, 2022
4e2995d
[typescript] Support esbuild, second attempt (#11465)
bodograumann Apr 6, 2022
13dbbc7
Fix the null pointer exception when generating examples for schemas i…
spacether Apr 7, 2022
6f3bf90
surefire plugin 3.0.0-M6 (#12076)
sullis Apr 7, 2022
852f8c3
[python-experimental] adds missing init files in endpoint modules (#1…
spacether Apr 7, 2022
1ed0ba7
testng 7.5 (#11380)
sullis Apr 7, 2022
1cee11e
Eliminates handlebars helper warnings (#12078)
spacether Apr 7, 2022
324d000
Adds postProcess method to python-experimental (#12079)
spacether Apr 7, 2022
231364f
[PowerShell] better enum model support (#12082)
wing328 Apr 8, 2022
9cf3029
docs: updated supported angular version (#12072)
takkiraz Apr 8, 2022
a5b7900
Fixed typo in readme which caused the project link to be broken (#12083)
lukacsaronzs Apr 8, 2022
1643c55
Bump actions/setup-java from 2 to 3 (#12087)
dependabot[bot] Apr 9, 2022
a1c4e37
Configure apiNameSuffix via plugins (#12062)
borsch Apr 9, 2022
940d240
[dart-dio] Adds support for enumUnknownDefaultCase to dart builtvalue…
josh-burton Apr 9, 2022
23995be
[php-slim4] Add Mock Server (#12044)
ybelenko Apr 9, 2022
5f4eccd
Adds 'params_encoder' config option for Ruby clients using Faraday (#…
dkliban Apr 9, 2022
eb4c696
Remove restrictions for additional property types (#11802)
impl Apr 9, 2022
bd9f1b6
Specify source encoding in java/kotlin sample poms templates (#12088)
wing328 Apr 9, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -989,17 +989,17 @@ hasChildren, isMap, isDeprecated, hasOnlyReadOnly, getExternalDocumentation(), g
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("CodegenModel{");
sb.append("parent='").append(parent).append('\'');
sb.append("name='").append(name).append('\'');
sb.append(", parent='").append(parent).append('\'');
sb.append(", parentSchema='").append(parentSchema).append('\'');
sb.append(", interfaces=").append(interfaces);
sb.append(", interfaceModels=").append(interfaceModels!=null?interfaceModels.size():"[]");
sb.append(", allParents=").append(allParents);
sb.append(", parentModel=").append(parentModel);
sb.append(", interfaceModels=").append(interfaceModels);
sb.append(", children=").append(children);
sb.append(", children=").append(children!=null?children.size():"[]");
sb.append(", anyOf=").append(anyOf);
sb.append(", oneOf=").append(oneOf);
sb.append(", allOf=").append(allOf);
sb.append(", name='").append(name).append('\'');
sb.append(", classname='").append(classname).append('\'');
sb.append(", title='").append(title).append('\'');
sb.append(", description='").append(description).append('\'');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3192,7 +3192,7 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
// FIXME: for now, we assume that the discriminator property is String
discriminator.setPropertyType(typeMapping.get("string"));
discriminator.setMapping(sourceDiscriminator.getMapping());
List<MappedModel> uniqueDescendants = new ArrayList();
List<MappedModel> uniqueDescendants = new ArrayList<>();
if (sourceDiscriminator.getMapping() != null && !sourceDiscriminator.getMapping().isEmpty()) {
for (Entry<String, String> e : sourceDiscriminator.getMapping().entrySet()) {
String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
Expand Down Expand Up @@ -882,9 +885,67 @@ public CodegenModel fromModel(String name, Schema model) {
codegenModel.imports.remove("ApiModelProperty");
codegenModel.imports.remove("ApiModel");
}

return codegenModel;
}

/**
* Analyse and post process all Models.
* Add parentVars to every Model which has a parent. This allows to generate
* fluent setter methods for inherited properties.
* @param objs the models map.
* @return the processed models map.
*/
@Override
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
objs = super.postProcessAllModels(objs);
objs = super.updateAllModels(objs);

for (ModelsMap modelsAttrs : objs.values()) {
for (ModelMap mo : modelsAttrs.getModels()) {
CodegenModel codegenModel = mo.getModel();
Set<String> inheritedImports = new HashSet<>();
Map<String, CodegenProperty> propertyHash = new HashMap<>(codegenModel.vars.size());
for (final CodegenProperty property : codegenModel.vars) {
propertyHash.put(property.name, property);
}
CodegenModel parentCodegenModel = codegenModel.parentModel;
while (parentCodegenModel != null) {
for (final CodegenProperty property : parentCodegenModel.vars) {
// helper list of parentVars simplifies templating
if (!propertyHash.containsKey(property.name)) {
propertyHash.put(property.name, property);
final CodegenProperty parentVar = property.clone();
parentVar.isInherited = true;
LOGGER.info("adding parent variable {}", property.name);
codegenModel.parentVars.add(parentVar);
Set<String> imports = parentVar.getImports(true).stream().filter(Objects::nonNull).collect(Collectors.toSet());
for (String imp: imports) {
// Avoid dupes
if (!codegenModel.getImports().contains(imp)) {
inheritedImports.add(imp);
codegenModel.getImports().add(imp);
}
}
}
}
parentCodegenModel = parentCodegenModel.getParentModel();
}
// There must be a better way ...
for (String imp: inheritedImports) {
String qimp = importMapping().get(imp);
if (qimp != null) {
Map<String,String> toAdd = new HashMap<>();
toAdd.put("import", qimp);
modelsAttrs.getImports().add(toAdd);
}
}
}
}
return objs;
}


/*
* Add dynamic imports based on the parameters and vendor extensions of an operation.
* The imports are expanded by the mustache {{import}} tag available to model and api
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package org.openapitools.codegen.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* This class holds data to add to `oneOf` members. Let's consider this example:
*
Expand Down Expand Up @@ -69,15 +70,19 @@ public void addFromInterfaceModel(CodegenModel cm, List<Map<String, String>> mod
// Add all vars defined on cm
// a "oneOf" model (cm) by default inherits all properties from its "interfaceModels",
// but we only want to add properties defined on cm itself
List<CodegenProperty> toAdd = new ArrayList<CodegenProperty>(cm.vars);
List<CodegenProperty> toAdd = new ArrayList<>(cm.vars);

// note that we can't just toAdd.removeAll(m.vars) for every interfaceModel,
// as they might have different value of `hasMore` and thus are not equal
List<String> omitAdding = new ArrayList<String>();
Set<String> omitAdding = new HashSet<>();
if (cm.interfaceModels != null) {
for (CodegenModel m : cm.interfaceModels) {
for (CodegenProperty v : m.vars) {
omitAdding.add(v.baseName);
}
for (CodegenProperty v : m.allVars) {
omitAdding.add(v.baseName);
}
}
}
for (CodegenProperty v : toAdd) {
Expand All @@ -89,7 +94,7 @@ public void addFromInterfaceModel(CodegenModel cm, List<Map<String, String>> mod
// Add all imports of cm
for (Map<String, String> importMap : modelsImports) {
// we're ok with shallow clone here, because imports are strings only
additionalImports.add(new HashMap<String, String>(importMap));
additionalImports.add(new HashMap<>(importMap));
}
}

Expand Down Expand Up @@ -120,6 +125,7 @@ public void addToImplementor(CodegenConfig cc, CodegenModel implcm, List<Map<Str

// Add oneOf-containing models properties - we need to properly set the hasMore values to make rendering correct
implcm.vars.addAll(additionalProps);
implcm.hasVars = ! implcm.vars.isEmpty();

// Add imports
for (Map<String, String> oneImport : additionalImports) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,29 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}
}
{{! end feature: getter and setter }}
{{/vars}}
{{#parentVars}}

{{! begin feature: fluent setter methods }}
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
super.{{setter}}({{name}});
return this;
}
{{#isArray}}

public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
super.add{{nameInCamelCase}}Item({{name}}Item);
return this;
}
{{/isArray}}
{{#isMap}}

public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
super.put{{nameInCamelCase}}Item({{name}}Item);
return this;
}
{{/isMap}}
{{! end feature: fluent setter methods }}
{{/parentVars}}

@Override
public boolean equals(Object o) {
Expand All @@ -178,23 +201,27 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}
{{/-last}}{{/vars}}{{#parent}} &&
super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}}
return true;{{/hasVars}}
}{{#vendorExtensions.x-jackson-optional-nullable-helpers}}
}
{{#vendorExtensions.x-jackson-optional-nullable-helpers}}

private static <T> boolean equalsNullable(JsonNullable<T> a, JsonNullable<T> b) {
return a == b || (a != null && b != null && a.isPresent() && b.isPresent() && Objects.deepEquals(a.get(), b.get()));
}{{/vendorExtensions.x-jackson-optional-nullable-helpers}}
}
{{/vendorExtensions.x-jackson-optional-nullable-helpers}}

@Override
public int hashCode() {
return Objects.hash({{#vars}}{{#vendorExtensions.x-is-jackson-optional-nullable}}hashCodeNullable({{name}}){{/vendorExtensions.x-is-jackson-optional-nullable}}{{^vendorExtensions.x-is-jackson-optional-nullable}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{/vendorExtensions.x-is-jackson-optional-nullable}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}});
}{{#vendorExtensions.x-jackson-optional-nullable-helpers}}
}
{{#vendorExtensions.x-jackson-optional-nullable-helpers}}

private static <T> int hashCodeNullable(JsonNullable<T> a) {
if (a == null) {
return 1;
}
return a.isPresent() ? Arrays.deepHashCode(new Object[]{a.get()}) : 31;
}{{/vendorExtensions.x-jackson-optional-nullable-helpers}}
}
{{/vendorExtensions.x-jackson-optional-nullable-helpers}}

@Override
public String toString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,49 @@ public void oneOf_5381() throws IOException {
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRefOrValue.java"), "public interface FooRefOrValue");
}

@Test
public void oneOf_allOf() 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/oneof_polymorphism_and_inheritance.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 extends Entity implements FooRefOrValue");
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRef.java"), "public class FooRef extends EntityRef implements FooRefOrValue");
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/FooRefOrValue.java"), "public interface FooRefOrValue");
// previous bugs
assertFileNotContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/BarRef.java"), "atTypesuper.hashCode");
assertFileNotContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/BarRef.java"), "private String atBaseType");
// imports for inherited properties
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/PizzaSpeziale.java"), "import java.math.BigDecimal");
}

@Test
public void testTypeMappings() {
final SpringCodegen codegen = new SpringCodegen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,15 @@ components:
- $ref: '#/components/schemas/Entity'
FooRef:
type: object
discriminator:
propertyName: '@type'
properties:
foorefPropA:
type: string
allOf:
- $ref: '#/components/schemas/EntityRef'
BarRef:
type: object
allOf:
- $ref: '#/components/schemas/EntityRef'
Bar_Create:
type: object
properties:
Expand All @@ -149,6 +151,32 @@ components:
$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'

requestBodies:
Foo:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ public void setKind(KindEnum kind) {
this.kind = kind;
}

public BigCat declawed(Boolean declawed) {
super.setDeclawed(declawed);
return this;
}

public BigCat className(String className) {
super.setClassName(className);
return this;
}

public BigCat color(String color) {
super.setColor(color);
return this;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ public void setDeclawed(Boolean declawed) {
this.declawed = declawed;
}

public Cat className(String className) {
super.setClassName(className);
return this;
}

public Cat color(String color) {
super.setColor(color);
return this;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ public void setBreed(String breed) {
this.breed = breed;
}

public Dog className(String className) {
super.setClassName(className);
return this;
}

public Dog color(String color) {
super.setColor(color);
return this;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Loading