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

Jersey2 supports additional properties with composed schema #6523

Merged
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
41e97e6
Mustache template should use invokerPackage tag to generate import
sebastien-rosset May 13, 2020
1760f6a
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 13, 2020
3ae466e
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 13, 2020
b628667
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 13, 2020
4dc915c
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 14, 2020
7a207f6
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 16, 2020
776fba6
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 18, 2020
3fac434
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 19, 2020
a96c46b
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 20, 2020
1351fd0
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 21, 2020
ba65735
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 22, 2020
9a0b89e
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 22, 2020
4c84190
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 22, 2020
94ae683
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 22, 2020
aac9f5a
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 23, 2020
93baa3d
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 23, 2020
5c313b4
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 23, 2020
cda8898
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 23, 2020
1f7e5c1
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 24, 2020
bef435e
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 25, 2020
a9cad38
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 26, 2020
877ecfe
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 27, 2020
8c055f5
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 27, 2020
d64f421
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 28, 2020
4d0edfe
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 28, 2020
afeb701
fix typo, fix script issue, add log statement for troubleshooting
sebastien-rosset May 28, 2020
ed5c165
Add java jersey2 samples with OpenAPI doc that has HTTP signature sec…
sebastien-rosset May 28, 2020
7edcb06
Add sample for Java jersey2 and HTTP signature scheme
sebastien-rosset May 28, 2020
762bdb7
Add unit test for oneOf schema deserialization
sebastien-rosset May 29, 2020
c2c6364
Add unit test for oneOf schema deserialization
sebastien-rosset May 29, 2020
4b0d0ca
Add log statements
sebastien-rosset May 29, 2020
65076bb
Add profile for jersey2
sebastien-rosset May 29, 2020
60f98e1
Temporarily disable unit test
sebastien-rosset May 29, 2020
352497b
Temporarily disable unit test
sebastien-rosset May 29, 2020
476eb01
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 29, 2020
40bb8d9
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset May 29, 2020
d227993
support for discriminator in jersey2
sebastien-rosset May 30, 2020
8ff6088
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 30, 2020
05d8718
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset May 30, 2020
ac1a061
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 30, 2020
aa27b72
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset May 30, 2020
22e6737
fix typo in pom.xml
sebastien-rosset May 30, 2020
1971f7d
Merge branch 'jersey2-misc-enhancements' of github.com:CiscoM31/opena…
sebastien-rosset May 30, 2020
90327fe
disable unit test because jersey2 deserialization is broken
sebastien-rosset May 30, 2020
5c52b6b
disable unit test because jersey2 deserialization is broken
sebastien-rosset May 30, 2020
38b8568
fix duplicate jersey2 samples
sebastien-rosset May 30, 2020
efec5a8
fix duplicate jersey2 samples
sebastien-rosset May 30, 2020
b3b4108
Merge branch 'jersey2-misc-enhancements' of github.com:CiscoM31/opena…
sebastien-rosset May 30, 2020
fac4991
Add code comments
sebastien-rosset May 30, 2020
057f1ca
fix duplicate artifact id
sebastien-rosset May 30, 2020
e94c5c8
fix duplicate jersey2 samples
sebastien-rosset May 30, 2020
99db107
run samples scripts
sebastien-rosset May 31, 2020
9671045
Merge branch 'jersey2-misc-enhancements' of github.com:CiscoM31/opena…
sebastien-rosset May 31, 2020
8579966
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 31, 2020
61e947e
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset May 31, 2020
1cb05de
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset May 31, 2020
20bd342
Merge branch 'jersey2-misc-enhancements' of github.com:CiscoM31/opena…
sebastien-rosset May 31, 2020
7c45925
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset May 31, 2020
cc61ec5
merge from master
sebastien-rosset May 31, 2020
cb6884c
resolve merge conflicts
sebastien-rosset May 31, 2020
7f52a53
Merge remote-tracking branch 'upstream/master'
vvb Jun 1, 2020
c123c91
Add unit tests
sebastien-rosset Jun 1, 2020
76d3348
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 1, 2020
797e779
Merge branch 'master' of github.com:CiscoM31/openapi-generator
sebastien-rosset Jun 1, 2020
3de8598
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset Jun 1, 2020
e7cc55d
fix unit tests
sebastien-rosset Jun 1, 2020
163e738
continue implementation of discriminator lookup
sebastien-rosset Jun 1, 2020
797f518
throw deserialization exception when value is null and schema does no…
sebastien-rosset Jun 1, 2020
3752652
continue implementation of compose schema
sebastien-rosset Jun 2, 2020
e00545e
continue implementation of compose schema
sebastien-rosset Jun 2, 2020
700e0f9
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 2, 2020
8fa6f2b
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset Jun 2, 2020
4753db4
continue implementation of compose schema
sebastien-rosset Jun 2, 2020
410a19d
Add more unit tests
sebastien-rosset Jun 2, 2020
45c10e1
Add unit tests for anyOf
sebastien-rosset Jun 2, 2020
589bfb8
Add unit tests
sebastien-rosset Jun 2, 2020
cf45a86
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 2, 2020
f3b8c05
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset Jun 2, 2020
c66892e
Set supportsAdditionalPropertiesWithComposedSchema to true for Java j…
sebastien-rosset Jun 2, 2020
effd1d3
Support additional properties as nested field
sebastien-rosset Jun 2, 2020
71b8497
Support additional properties as nested field
sebastien-rosset Jun 3, 2020
0b6291c
add code comments
sebastien-rosset Jun 3, 2020
cf845f5
add customer deserializer
sebastien-rosset Jun 3, 2020
ad3fa7e
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 4, 2020
fa6cea1
Fix 'method too big' error with generated code
sebastien-rosset Jun 4, 2020
aa79612
resolve merge conflicts
sebastien-rosset Jun 4, 2020
7e469f6
resolve merge conflicts
sebastien-rosset Jun 4, 2020
12ecf34
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 4, 2020
d48a29a
Merge branch 'jersey2-method-too-big' of github.com:CiscoM31/openapi-…
sebastien-rosset Jun 4, 2020
6321dfc
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 4, 2020
ae8e870
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 5, 2020
d1f351b
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
sebastien-rosset Jun 5, 2020
7e2868b
Merge branch 'master' of github.com:CiscoM31/openapi-generator into j…
sebastien-rosset Jun 5, 2020
2bab4c6
Merge branch 'jersey2-improvement' of https://github.com/OpenAPITools…
sebastien-rosset Jun 5, 2020
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1646,10 +1646,24 @@ public void setAdditionalModelTypeAnnotations(final List<String> additionalModel

@Override
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
super.addAdditionPropertiesToCodeGenModel(codegenModel, schema);
if (!supportsAdditionalPropertiesWithComposedSchema) {
// The additional (undeclared) propertiees are modeled in Java as a HashMap.
//
// 1. supportsAdditionalPropertiesWithComposedSchema is set to false:
// The generated model class extends from the HashMap. That does not work
// with composed schemas that also use a discriminator because the model class
// is supposed to extend from the generated parent model class.
// 2. supportsAdditionalPropertiesWithComposedSchema is set to true:
// The HashMap is a field.
super.addAdditionPropertiesToCodeGenModel(codegenModel, schema);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wing328 , this code avoids having the generated class extends from HashMap<String, T>. Instead, a additionalProperties field is added.

Copy link
Member

Choose a reason for hiding this comment

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

@sebastien-rosset I may have a better way for this. Let's have a chat via Slack today.

}

// See https://github.com/OpenAPITools/openapi-generator/pull/1729#issuecomment-449937728
codegenModel.additionalPropertiesType = getSchemaType(getAdditionalProperties(schema));
addImport(codegenModel, codegenModel.additionalPropertiesType);
Schema s = getAdditionalProperties(schema);
// 's' may be null if 'additionalProperties: false' in the OpenAPI schema.
if (s != null) {
codegenModel.additionalPropertiesType = getSchemaType(s);
addImport(codegenModel, codegenModel.additionalPropertiesType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public JavaClientCodegen() {
// inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values,
// and the discriminator mapping schemas in the OAS document.
this.setLegacyDiscriminatorBehavior(false);

}

@Override
Expand Down Expand Up @@ -371,6 +372,14 @@ public void processOpts() {
}
supportingFiles.add(new SupportingFile("AbstractOpenApiSchema.mustache", (sourceFolder + File.separator + modelPackage().replace('.', File.separatorChar)).replace('/', File.separatorChar), "AbstractOpenApiSchema.java"));
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);

// Composed schemas can have the 'additionalProperties' keyword, as specified in JSON schema.
// In principle, this should be enabled by default for all code generators. However due to limitations
// in other code generators, support needs to be enabled on a case-by-case basis.
// The flag below should be set for all Java libraries, but the templates need to be ported
// one by one for each library.
supportsAdditionalPropertiesWithComposedSchema = true;

} else if (NATIVE.equals(getLibrary())) {
setJava8Mode(true);
additionalProperties.put("java8", "true");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,29 @@ public abstract class AbstractOpenApiSchema {
this.isNullable = isNullable;
}

/***
* Get the list of schemas allowed to be stored in this object
/**
* Get the list of oneOf/anyOf composed schemas allowed to be stored in this object
*
* @return an instance of the actual schema/object
*/
public abstract Map<String, GenericType> getSchemas();

/***
/**
* Get the actual instance
*
* @return an instance of the actual schema/object
*/
@JsonValue
public Object getActualInstance() {return instance;}

/***
/**
* Set the actual instance
*
* @param instance the actual instance of the schema/object
*/
public void setActualInstance(Object instance) {this.instance = instance;}

/***
/**
* Get the schema type (e.g. anyOf, oneOf)
*
* @return the schema type
Expand Down Expand Up @@ -101,7 +101,7 @@ public abstract class AbstractOpenApiSchema {
return Objects.hash(instance, isNullable, schemaType);
}

/***
/**
* Is nullalble
*
* @return true if it's nullable
Expand All @@ -113,4 +113,7 @@ public abstract class AbstractOpenApiSchema {
return Boolean.FALSE;
}
}

{{>libraries/jersey2/additional_properties}}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ import com.fasterxml.jackson.datatype.joda.JodaModule;
{{#threetenbp}}
import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule;
{{/threetenbp}}
{{#models.0}}
import {{modelPackage}}.*;
{{/models.0}}

import java.text.DateFormat;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.ext.ContextResolver;

{{>generatedAnnotation}}
Expand Down Expand Up @@ -69,4 +76,180 @@ public class JSON implements ContextResolver<ObjectMapper> {
* @return object mapper
*/
public ObjectMapper getMapper() { return mapper; }

/**
* Returns the target model class that should be used to deserialize the input data.
* The discriminator mappings are used to determine the target model class.
*
* @param node The input data.
* @param modelClass The class that contains the discriminator mappings.
*/
public static Class getClassForElement(JsonNode node, Class modelClass) {
ClassDiscriminatorMapping cdm = modelDiscriminators.get(modelClass);
if (cdm != null) {
return cdm.getClassForElement(node, new HashSet<Class>());
}
return null;
}

/**
* Helper class to register the discriminator mappings.
*/
private static class ClassDiscriminatorMapping {
// The model class name.
Class modelClass;
// The name of the discriminator property.
String discriminatorName;
// The discriminator mappings for a model class.
Map<String, Class> discriminatorMappings;

// Constructs a new class discriminator.
ClassDiscriminatorMapping(Class cls, String name) {
modelClass = cls;
discriminatorName = name;
discriminatorMappings = new HashMap<String, Class>();
}

// Register a discriminator mapping for the specified model class.
void registerMapping(String mapping, Class cls) {
discriminatorMappings.put(mapping, cls);
}

// Return the name of the discriminator property for this model class.
String getDiscriminatorPropertyName() {
return discriminatorName;
}

// Return the discriminator value or null if the discriminator is not
// present in the payload.
String getDiscriminatorValue(JsonNode node) {
// Determine the value of the discriminator property in the input data.
if (discriminatorName != null) {
// Get the value of the discriminator property, if present in the input payload.
node = node.get(discriminatorName);
if (node != null && node.isValueNode()) {
String discrValue = node.asText();
if (discrValue != null) {
return discrValue;
}
}
}
return null;
}

/**
* Returns the target model class that should be used to deserialize the input data.
* This function can be invoked for anyOf/oneOf composed models with discriminator mappings.
* The discriminator mappings are used to determine the target model class.
*
* @param node The input data.
* @param visitedClasses The set of classes that have already been visited.
*/
Class getClassForElement(JsonNode node, Set<Class> visitedClasses) {
if (visitedClasses.contains(modelClass)) {
// Class has already been visited.
return null;
}
// Determine the value of the discriminator property in the input data.
String discrValue = getDiscriminatorValue(node);
if (discrValue == null) {
return null;
}
Class cls = discriminatorMappings.get(discrValue);
// It may not be sufficient to return this cls directly because that target class
// may itself be a composed schema, possibly with its own discriminator.
visitedClasses.add(modelClass);
for (Class childClass : discriminatorMappings.values()) {
ClassDiscriminatorMapping childCdm = modelDiscriminators.get(childClass);
if (childCdm == null) {
continue;
}
if (!discriminatorName.equals(childCdm.discriminatorName)) {
discrValue = getDiscriminatorValue(node);
if (discrValue == null) {
continue;
}
}
if (childCdm != null) {
// Recursively traverse the discriminator mappings.
Class childDiscr = childCdm.getClassForElement(node, visitedClasses);
if (childDiscr != null) {
return childDiscr;
}
}
}
return cls;
}
}

/**
* Returns true if inst is an instance of modelClass in the OpenAPI model hierarchy.
*
* The Java class hierarchy is not implemented the same way as the OpenAPI model hierarchy,
* so it's not possible to use the instanceof keyword.
*
* @param modelClass A OpenAPI model class.
* @param inst The instance object.
*/
public static boolean isInstanceOf(Class modelClass, Object inst, Set<Class> visitedClasses) {
if (modelClass.isInstance(inst)) {
// This handles the 'allOf' use case with single parent inheritance.
return true;
}
if (visitedClasses.contains(modelClass)) {
// This is to prevent infinite recursion when the composed schemas have
// a circular dependency.
return false;
}
visitedClasses.add(modelClass);

// Traverse the oneOf/anyOf composed schemas.
Map<String, GenericType> descendants = modelDescendants.get(modelClass);
if (descendants != null) {
for (GenericType childType : descendants.values()) {
if (isInstanceOf(childType.getRawType(), inst, visitedClasses)) {
return true;
}
}
}
return false;
}

private static Map<Class, ClassDiscriminatorMapping> modelDiscriminators = new HashMap<Class, ClassDiscriminatorMapping>();

/**
* Register the discriminators for all composed models.
*/
private static void registerDiscriminators() {
{{#models}}
{{#model}}
{{#discriminator}}
{
// Initialize the discriminator mappings for '{{classname}}'.
ClassDiscriminatorMapping m = new ClassDiscriminatorMapping({{classname}}.class, "{{propertyBaseName}}");
{{#mappedModels}}
m.registerMapping("{{mappingName}}", {{modelName}}.class);
{{/mappedModels}}
m.registerMapping("{{name}}", {{classname}}.class);
modelDiscriminators.put({{classname}}.class, m);
}
{{/discriminator}}
{{/model}}
{{/models}}
}

private static Map<Class, Map<String, GenericType>> modelDescendants = new HashMap<Class, Map<String, GenericType>>();

/**
* Register the oneOf/anyOf descendants.
* TODO: this should not be a public method.
*/
public static void registerDescendants(Class modelClass, Map<String, GenericType> descendants) {
modelDescendants.put(modelClass, descendants);
}

static {
registerDiscriminators();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{{#additionalPropertiesType}}
/**
* A container for additional, undeclared properties.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wing328 , this is the code that has the additionalProperties field

* This is a holder for any undeclared properties as specified with
* the 'additionalProperties' keyword in the OAS document.
*/
@JsonUnwrapped
private Map<String, {{{.}}}> additionalProperties;

/**
* Set the additional (undeclared) property with the specified name and value.
* If the property does not already exist, create it otherwise replace it.
*/
public {{classname}} putAdditionalProperty(String key, {{{.}}} value) {
if (this.additionalProperties == null) {
this.additionalProperties = new HashMap<String, {{{.}}}>();
}
this.additionalProperties.put(key, value);
return this;
}

/**
* Return the additional (undeclared) property with the specified name.
*/
public {{{.}}} getAdditionalProperty(String key) {
if (this.additionalProperties == null) {
return null;
}
return this.additionalProperties.get(key);
}
{{/additionalPropertiesType}}
Loading