JAX-RS/CXF 1158 Options to generate fully functional method bodies passing fully populated test data (#1879)

* add option to generate alias as model

* [JAXRS/CXF] Emit method bodies, test data (#1158)

New jaxrs-cxf-extended generator with options:
 - supportMultipleSpringServices Support generation of Spring services
   from multiple specifications
 - generateOperationBody (boolean) Enables generation of fully
   functional test/service method bodies that pass/return random
   but valid values & models.
 - loadTestDataFromFile (boolean) When true, generated method bodies
   load test data from a generated JSON file. When false, generated
   method bodies contain inline code to construct the test data.
 - testDataFile (string) The path of a JSON file to contain generated
   test data. The file is initially generated but editable; edits are
   preserved by subsequent generations.
 - testDataControlFile (string) The path of a JSON file to control test
   data generation - specifically, to control the number of items
   required in array properties, structured by API class
   / operation name / parameter name. The file is initially generated
   but editable; edits are preserved by subsequent generations.
 - tests for the jaxrs-cxf-extended generator, including the new options
Bug fixes:
 - fix bug (DefaultGenerator): handle absolute paths in supporting file
   spec
 - fix bug (DefaultCodegen): process enums in allVars
 - fix bug (AbstractJavaCodegen): support multiple inheritance via
   allOf (inheritance code deleted, as a subsequent pull broke it)
 - fix bug (JavaCXFServerCodegen): use operationId instead of nickname
(gets out of step with duplicate operationIds)
 - fix bug (JavaCXFServerCodegen): set appropriate default
consumes/produces for operations with body parameters or non-void
returns (CXF providers don't handle */*)
 - fix indentation (DefaultCodegen)
 - add support for a system property openapitools.implementation.version
to specify the package implementation version when running non-JAR'd
classes in an IDE (otherwise {{{generatorVersion}}} evaluates to
'unset'.

* reformat code

* make sh executable

* fix template folder

* fix template folder, update samples

* run test data manually to avoid ci failure
This commit is contained in:
Adrian Price
2019-03-06 00:58:11 +00:00
committed by William Cheng
parent 37c890f755
commit 2985c0f0b8
148 changed files with 18391 additions and 166 deletions

View File

@@ -1875,7 +1875,6 @@ public class DefaultCodegen implements CodegenConfig {
return camelize(toVarName(name));
}
/**
* Convert OAS Property object to Codegen Property object
*
@@ -2217,7 +2216,6 @@ public class DefaultCodegen implements CodegenConfig {
return currentProperty == null ? new HashMap<String, Object>() : currentProperty.allowableValues;
}
/**
* Update datatypeWithEnum for array container
*
@@ -2881,7 +2879,6 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.isContainer = true;
codegenParameter.isListContainer = true;
// recursively add import
while (codegenProperty != null) {
imports.add(codegenProperty.baseType);
@@ -3095,7 +3092,7 @@ public class DefaultCodegen implements CodegenConfig {
codegenParameter.paramName = "UNKNOWN_PARAMETER_NAME";
}
// set the parameter excample value
// set the parameter example value
// should be overridden by lang codegen
setParameterExampleValue(codegenParameter, parameter);
@@ -3309,8 +3306,8 @@ public class DefaultCodegen implements CodegenConfig {
Header header = ModelUtils.getReferencedHeader(this.openAPI, headerEntry.getValue());
Schema schema;
if(header.getSchema() == null) {
LOGGER.warn("No schema defined for Header '" + headerEntry.getKey() +"', using a String schema");
if (header.getSchema() == null) {
LOGGER.warn("No schema defined for Header '" + headerEntry.getKey() + "', using a String schema");
schema = new StringSchema();
} else {
schema = header.getSchema();
@@ -3374,7 +3371,6 @@ public class DefaultCodegen implements CodegenConfig {
co.baseName = tag;
}
private void addParentContainer(CodegenModel model, String name, Schema schema) {
final CodegenProperty property = fromProperty(name, schema);
addImport(model, property.complexType);
@@ -3770,7 +3766,6 @@ public class DefaultCodegen implements CodegenConfig {
this.docExtension = userDocExtension;
}
/**
* Set HTTP user agent.
*
@@ -3976,7 +3971,6 @@ public class DefaultCodegen implements CodegenConfig {
}
}
/**
* Update codegen property's enum by adding "enumVars" (with name and value)
*
@@ -4029,7 +4023,7 @@ public class DefaultCodegen implements CodegenConfig {
}
// if "x-enum-varnames" or "x-enum-descriptions" defined, update varnames
Map<String, Object> extensions = var.mostInnerItems != null ? var.mostInnerItems.getVendorExtensions() : var.getVendorExtensions();
if(referencedSchema.isPresent()) {
if (referencedSchema.isPresent()) {
extensions = referencedSchema.get().getExtensions();
}
updateEnumVarsWithExtensions(enumVars, extensions);
@@ -4039,7 +4033,7 @@ public class DefaultCodegen implements CodegenConfig {
if (var.defaultValue != null) {
String enumName = null;
final String enumDefaultValue;
if("string".equalsIgnoreCase(dataType)) {
if ("string".equalsIgnoreCase(dataType)) {
enumDefaultValue = toEnumValue(var.defaultValue, dataType);
} else {
enumDefaultValue = var.defaultValue;

View File

@@ -153,7 +153,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
generateApiTests = GeneratorProperties.getProperty(CodegenConstants.API_TESTS) != null ? Boolean.valueOf(GeneratorProperties.getProperty(CodegenConstants.API_TESTS)) : getGeneratorPropertyDefaultSwitch(CodegenConstants.API_TESTS, true);
generateApiDocumentation = GeneratorProperties.getProperty(CodegenConstants.API_DOCS) != null ? Boolean.valueOf(GeneratorProperties.getProperty(CodegenConstants.API_DOCS)) : getGeneratorPropertyDefaultSwitch(CodegenConstants.API_DOCS, true);
// Additional properties added for tests to exclude references in project related files
config.additionalProperties().put(CodegenConstants.GENERATE_API_TESTS, generateApiTests);
config.additionalProperties().put(CodegenConstants.GENERATE_MODEL_TESTS, generateModelTests);
@@ -627,7 +626,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
}
}
if (generateApiDocumentation) {
// to generate api documentation files
for (String templateName : config.apiDocTemplateFiles().keySet()) {
@@ -678,7 +676,9 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
if (!of.isDirectory()) {
of.mkdirs();
}
String outputFilename = outputFolder + File.separator + support.destinationFilename.replace('/', File.separatorChar);
String outputFilename = new File(support.destinationFilename).isAbsolute() // split
? support.destinationFilename
: outputFolder + File.separator + support.destinationFilename.replace('/', File.separatorChar);
if (!config.shouldOverwrite(outputFilename)) {
LOGGER.info("Skipped overwriting " + outputFilename);
continue;
@@ -910,7 +910,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
return files;
}
protected File processTemplateToFile(Map<String, Object> templateData, String templateName, String outputFilename) throws IOException {
String adjustedOutputFilename = outputFilename.replaceAll("//", "/").replace('/', File.separatorChar);
if (ignoreProcessor.allowsFile(new File(adjustedOutputFilename))) {
@@ -1059,7 +1058,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
return parameter.getName() + ":" + parameter.getIn();
}
private Map<String, Object> processOperations(CodegenConfig config, String tag, List<CodegenOperation> ops, List<Object> allModels) {
Map<String, Object> operations = new HashMap<String, Object>();
Map<String, Object> objs = new HashMap<String, Object>();
@@ -1125,7 +1123,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
return operations;
}
private Map<String, Object> processModels(CodegenConfig config, Map<String, Schema> definitions) {
Map<String, Object> objs = new HashMap<String, Object>();
objs.put("package", config.modelPackage());

View File

@@ -85,7 +85,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
protected boolean serializeBigDecimalAsString = false;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
protected boolean supportJava6= false;
protected boolean supportJava6 = false;
protected boolean disableHtmlEscaping = false;
protected String booleanGetterPrefix = BOOLEAN_GETTER_PREFIX_DEFAULT;
protected boolean useNullForUnknownEnumValue = false;
@@ -187,7 +187,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
cliOptions.add(CliOption.newBoolean(DISABLE_HTML_ESCAPING, "Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)"));
cliOptions.add(CliOption.newString(BOOLEAN_GETTER_PREFIX, "Set booleanGetterPrefix (default value '" + BOOLEAN_GETTER_PREFIX_DEFAULT + "')"));
cliOptions.add(CliOption.newString(CodegenConstants.PARENT_GROUP_ID, CodegenConstants.PARENT_GROUP_ID_DESC));
cliOptions.add(CliOption.newString(CodegenConstants.PARENT_ARTIFACT_ID, CodegenConstants.PARENT_ARTIFACT_ID_DESC));
cliOptions.add(CliOption.newString(CodegenConstants.PARENT_VERSION, CodegenConstants.PARENT_VERSION_DESC));
@@ -226,16 +226,16 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
} else if (additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
// guess from api package
String derviedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.API_PACKAGE));
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derviedInvokerPackage);
String derivedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.API_PACKAGE));
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derivedInvokerPackage);
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
LOGGER.info("Invoker Package Name, originally not set, is now dervied from api package name: " + derviedInvokerPackage);
LOGGER.info("Invoker Package Name, originally not set, is now derived from api package name: " + derivedInvokerPackage);
} else if (additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
// guess from model package
String derviedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derviedInvokerPackage);
String derivedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derivedInvokerPackage);
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
LOGGER.info("Invoker Package Name, originally not set, is now dervied from model package name: " + derviedInvokerPackage);
LOGGER.info("Invoker Package Name, originally not set, is now derived from model package name: " + derivedInvokerPackage);
} else {
//not set, use default to be passed to template
additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
@@ -380,19 +380,19 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
this.setWithXml(Boolean.valueOf(additionalProperties.get(WITH_XML).toString()));
}
additionalProperties.put(WITH_XML, withXml);
if (additionalProperties.containsKey(CodegenConstants.PARENT_GROUP_ID)) {
this.setParentGroupId((String) additionalProperties.get(CodegenConstants.PARENT_GROUP_ID));
}
if (additionalProperties.containsKey(CodegenConstants.PARENT_ARTIFACT_ID)) {
this.setParentArtifactId((String) additionalProperties.get(CodegenConstants.PARENT_ARTIFACT_ID));
}
if (additionalProperties.containsKey(CodegenConstants.PARENT_VERSION)) {
this.setParentVersion((String) additionalProperties.get(CodegenConstants.PARENT_VERSION));
}
if (!StringUtils.isEmpty(parentGroupId) && !StringUtils.isEmpty(parentArtifactId) && !StringUtils.isEmpty(parentVersion)) {
additionalProperties.put("parentOverridden", true);
}
@@ -617,7 +617,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
}
// If name contains special chars -> replace them.
if ((((CharSequence) name).chars().anyMatch(character -> specialCharReplacements.keySet().contains( "" + ((char) character))))) {
if ((((CharSequence) name).chars().anyMatch(character -> specialCharReplacements.keySet().contains("" + ((char) character))))) {
List<String> allowedCharacters = new ArrayList<>();
allowedCharacters.add("_");
allowedCharacters.add("$");
@@ -1356,7 +1356,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
*
* @return API version
*/
private String getVersionFromSpecification () {
private String getVersionFromSpecification() {
if (this.openAPI != null && this.openAPI.getInfo() != null) {
return this.openAPI.getInfo().getVersion();
} else {
@@ -1370,7 +1370,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
* @param version
* @return SNAPSHOT version
*/
private String buildSnapshotVersion (String version) {
private String buildSnapshotVersion(String version) {
return version + "-" + "SNAPSHOT";
}
@@ -1445,7 +1445,6 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
}
@Override
public void postProcessFile(File file, String fileType) {
if (file == null) {

View File

@@ -0,0 +1,20 @@
package org.openapitools.codegen.languages.features;
import java.io.File;
public interface CXFExtServerFeatures extends CXFServerFeatures {
String GENERATE_OPERATION_BODY = "generateOperationBody";
String SUPPORT_MULTIPLE_SPRING_SERVICES = "supportMultipleSpringServices";
String TEST_DATA_FILE = "testDataFile";
String TEST_DATA_CONTROL_FILE = "testDataControlFile";
void setGenerateOperationBody(boolean generateOperationBody);
void setLoadTestDataFromFile(boolean loadTestDataFromFile);
void setTestDataFile(File testDataFile);
void setTestDataControlFile(File testDataControlFile);
}

View File

@@ -33,6 +33,8 @@ public interface CXFServerFeatures
public static final String GENERATE_NON_SPRING_APPLICATION = "generateNonSpringApplication";
public static final String LOAD_TEST_DATA_FROM_FILE = "loadTestDataFromFile";
public void setUseWadlFeature(boolean useWadlFeature);
public void setUseMultipartFeature(boolean useMultipartFeature);
@@ -42,5 +44,4 @@ public interface CXFServerFeatures
public void setUseAnnotatedBasePath(boolean useAnnotatedBasePath);
public void setGenerateNonSpringApplication(boolean generateNonSpringApplication);
}

View File

@@ -21,10 +21,12 @@ public class ImplementationVersion {
public static String read() {
// Assumes this version is required at runtime. This could be modified to use a properties file like the CLI.
String compiledVersion = ImplementationVersion.class.getPackage().getImplementationVersion();
if(compiledVersion != null) {
if (compiledVersion != null) {
return compiledVersion;
}
return "unset";
// When running non-JARed class within an IDE the implementation version is not available, so we provide a means
// to set it externally via a system property so that generated artefacts contain the correct version.
return System.getProperty("openapitools.implementation.version", "unset");
}
}