Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@
# @return [Object] Returns the model itself
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
{{#parent}}
super(attributes)
{{/parent}}
attributes = attributes.transform_keys(&:to_sym)
# include attributes inherited from allOf parents (the nearest declaration wins)
map = acceptable_attribute_map
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
acceptable_openapi_types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -27,11 +26,12 @@
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = {{^parent}}{}{{/parent}}{{#parent}}super{{/parent}}
self.class.attribute_map.each_pair do |attr, param|
hash = {}
# include attributes inherited from allOf parents (the nearest declaration wins)
self.class.acceptable_attribute_map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = self.class.acceptable_openapi_nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@
}
end

# Returns attribute mapping this model knows about{{#parent}}, including the ones defined in its parent(s){{/parent}}
# Returns attribute mapping this model knows about{{#parentModel}}, including the ones defined in its parent(s){{/parentModel}}
def self.acceptable_attribute_map
{{^parent}}
{{^parentModel}}
attribute_map
{{/parent}}
{{#parent}}
{{/parentModel}}
{{#parentModel}}
superclass.acceptable_attribute_map.merge(attribute_map)
{{/parent}}
{{/parentModel}}
end

# Returns all the JSON keys this model knows about{{#parent}}, including the ones defined in its parent(s){{/parent}}
# Returns all the JSON keys this model knows about{{#parentModel}}, including the ones defined in its parent(s){{/parentModel}}
def self.acceptable_attributes
acceptable_attribute_map.values
end
Expand All @@ -77,6 +77,26 @@
])
end

# Returns attribute type mapping{{#parentModel}}, including the ones defined in its parent(s){{/parentModel}}
def self.acceptable_openapi_types
{{^parentModel}}
openapi_types
{{/parentModel}}
{{#parentModel}}
superclass.acceptable_openapi_types.merge(openapi_types)
{{/parentModel}}
end

# Returns the nullable attributes{{#parentModel}}, including the ones defined in its parent(s) that it does not redeclare{{/parentModel}}
def self.acceptable_openapi_nullable
{{^parentModel}}
openapi_nullable
{{/parentModel}}
{{#parentModel}}
(superclass.acceptable_openapi_nullable - attribute_map.keys) | openapi_nullable
{{/parentModel}}
end

{{#anyOf}}
{{#-first}}
# List of class defined in anyOf (OpenAPI v3)
Expand Down Expand Up @@ -127,11 +147,11 @@
end
h[k.to_sym] = v
}
{{#parent}}
{{#parentModel}}

# call parent's initialize
super(attributes)
{{/parent}}
{{/parentModel}}
{{#vars}}

if attributes.key?(:'{{{name}}}')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;
import org.openapitools.codegen.utils.ModelUtils;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -799,4 +801,61 @@ public void testQueryParamJsonSerializationSetsQueryIsJsonMimeType() {
assertTrue(op.queryParams.stream().allMatch(p -> p.queryIsJsonMimeType),
"All content:application/json query params should have queryIsJsonMimeType=true");
}

@Test(description = "an allOf child's build_from_hash and to_hash include the attributes inherited from its parents")
public void testBuildFromHashMapsInheritedAttributes() throws Exception {
final File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/allOf_composition_discriminator.yaml");
CodegenConfig codegenConfig = new RubyClientCodegen();
codegenConfig.setOutputDir(output.getAbsolutePath());

ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegenConfig);
new DefaultGenerator().opts(clientOptInput).generate();

// Lizard < Reptile < Pet: types and nullability merge along the ancestry, the nearest declaration wins
Path lizard = new File(output, "lib/openapi_client/models/lizard.rb").toPath();
TestUtils.assertFileContains(lizard,
"superclass.acceptable_openapi_types.merge(openapi_types)",
"(superclass.acceptable_openapi_nullable - attribute_map.keys) | openapi_nullable");
// build_from_hash and to_hash use the merged maps
TestUtils.assertFileContains(lizard,
"acceptable_openapi_types.each_pair do |key, type|",
"self.class.acceptable_attribute_map.each_pair do |attr, param|",
"is_nullable = self.class.acceptable_openapi_nullable.include?(attr)");
// the super call that built and discarded a second instance is gone
TestUtils.assertFileNotContains(lizard, "super(attributes)\n attributes = attributes.transform_keys(&:to_sym)");
// a root model has no parent to merge
TestUtils.assertFileNotContains(new File(output, "lib/openapi_client/models/pet.rb").toPath(), "superclass.acceptable_openapi_types");
// a generated parent still receives the initializer call
TestUtils.assertFileContains(lizard, "# call parent's initialize\n super(attributes)");
}

@Test(description = "a model whose superclass is not a generated model (an alias to an array) does not delegate to it")
public void testAliasModelDoesNotDelegateToItsBuiltInSuperclass() throws Exception {
final File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/features/generate-alias-as-model.yaml");
CodegenConfig codegenConfig = new RubyClientCodegen();
codegenConfig.setOutputDir(output.getAbsolutePath());

ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegenConfig);
ModelUtils.setGenerateAliasAsModel(true);
try {
new DefaultGenerator().opts(clientOptInput).generate();
} finally {
ModelUtils.setGenerateAliasAsModel(false);
}

// ArrayAlias < Array: Array has none of the helpers, so each one is its own base case
Path arrayAlias = new File(output, "lib/openapi_client/models/array_alias.rb").toPath();
TestUtils.assertFileContains(arrayAlias,
"class ArrayAlias < Array",
"def self.acceptable_attribute_map\n attribute_map\n end",
"def self.acceptable_openapi_types\n openapi_types\n end",
"def self.acceptable_openapi_nullable\n openapi_nullable\n end");
TestUtils.assertFileNotContains(arrayAlias, "superclass.", "super(attributes)");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ def self.openapi_nullable
])
end

# Returns attribute type mapping
def self.acceptable_openapi_types
openapi_types
end

# Returns the nullable attributes
def self.acceptable_openapi_nullable
openapi_nullable
end

# Initializes the object
# @param [Hash] attributes Model attributes in the form of hash
def initialize(attributes = {})
Expand Down Expand Up @@ -118,18 +128,20 @@ def hash
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
attributes = attributes.transform_keys(&:to_sym)
# include attributes inherited from allOf parents (the nearest declaration wins)
map = acceptable_attribute_map
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
acceptable_openapi_types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -139,10 +151,11 @@ def self.build_from_hash(attributes)
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = {}
self.class.attribute_map.each_pair do |attr, param|
# include attributes inherited from allOf parents (the nearest declaration wins)
self.class.acceptable_attribute_map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = self.class.acceptable_openapi_nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ def self.openapi_nullable
])
end

# Returns attribute type mapping
def self.acceptable_openapi_types
openapi_types
end

# Returns the nullable attributes
def self.acceptable_openapi_nullable
openapi_nullable
end

# Initializes the object
# @param [Hash] attributes Model attributes in the form of hash
def initialize(attributes = {})
Expand Down Expand Up @@ -118,18 +128,20 @@ def hash
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
attributes = attributes.transform_keys(&:to_sym)
# include attributes inherited from allOf parents (the nearest declaration wins)
map = acceptable_attribute_map
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
acceptable_openapi_types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -139,10 +151,11 @@ def self.build_from_hash(attributes)
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = {}
self.class.attribute_map.each_pair do |attr, param|
# include attributes inherited from allOf parents (the nearest declaration wins)
self.class.acceptable_attribute_map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = self.class.acceptable_openapi_nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ def self.openapi_nullable
])
end

# Returns attribute type mapping, including the ones defined in its parent(s)
def self.acceptable_openapi_types
superclass.acceptable_openapi_types.merge(openapi_types)
end

# Returns the nullable attributes, including the ones defined in its parent(s) that it does not redeclare
def self.acceptable_openapi_nullable
(superclass.acceptable_openapi_nullable - attribute_map.keys) | openapi_nullable
end

# List of class defined in allOf (OpenAPI v3)
def self.openapi_all_of
[
Expand Down Expand Up @@ -161,20 +171,21 @@ def hash
# @return [Object] Returns the model itself
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
super(attributes)
attributes = attributes.transform_keys(&:to_sym)
# include attributes inherited from allOf parents (the nearest declaration wins)
map = acceptable_attribute_map
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
acceptable_openapi_types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -183,11 +194,12 @@ def self.build_from_hash(attributes)
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = super
self.class.attribute_map.each_pair do |attr, param|
hash = {}
# include attributes inherited from allOf parents (the nearest declaration wins)
self.class.acceptable_attribute_map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = self.class.acceptable_openapi_nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Loading
Loading