org.openapitools.codegen.languages.AbstractJavaCodegen Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.samskivert.mustache.Mustache;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
import org.openapitools.codegen.languages.features.DocumentationProviderFeatures;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.model.ModelMap;
import org.openapitools.codegen.model.ModelsMap;
import org.openapitools.codegen.model.OperationMap;
import org.openapitools.codegen.model.OperationsMap;
import org.openapitools.codegen.utils.CamelizeOption;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.openapitools.codegen.utils.CamelizeOption.*;
import static org.openapitools.codegen.utils.ModelUtils.getSchemaItems;
import static org.openapitools.codegen.utils.OnceLogger.once;
import static org.openapitools.codegen.utils.StringUtils.*;
public abstract class AbstractJavaCodegen extends DefaultCodegen implements CodegenConfig,
DocumentationProviderFeatures {
private final Logger LOGGER = LoggerFactory.getLogger(AbstractJavaCodegen.class);
private static final String ARTIFACT_VERSION_DEFAULT_VALUE = "1.0.0";
public static final String DEFAULT_LIBRARY = "";
public static final String DATE_LIBRARY = "dateLibrary";
public static final String SUPPORT_ASYNC = "supportAsync";
public static final String WITH_XML = "withXml";
public static final String DISABLE_HTML_ESCAPING = "disableHtmlEscaping";
public static final String BOOLEAN_GETTER_PREFIX = "booleanGetterPrefix";
public static final String IGNORE_ANYOF_IN_ENUM = "ignoreAnyOfInEnum";
public static final String ADDITIONAL_MODEL_TYPE_ANNOTATIONS = "additionalModelTypeAnnotations";
public static final String ADDITIONAL_ONE_OF_TYPE_ANNOTATIONS = "additionalOneOfTypeAnnotations";
public static final String ADDITIONAL_ENUM_TYPE_ANNOTATIONS = "additionalEnumTypeAnnotations";
public static final String DISCRIMINATOR_CASE_SENSITIVE = "discriminatorCaseSensitive";
public static final String OPENAPI_NULLABLE = "openApiNullable";
public static final String JACKSON = "jackson";
public static final String TEST_OUTPUT = "testOutput";
public static final String IMPLICIT_HEADERS = "implicitHeaders";
public static final String IMPLICIT_HEADERS_REGEX = "implicitHeadersRegex";
public static final String JAVAX_PACKAGE = "javaxPackage";
public static final String USE_JAKARTA_EE = "useJakartaEe";
public static final String CONTAINER_DEFAULT_TO_NULL = "containerDefaultToNull";
public static final String CAMEL_CASE_DOLLAR_SIGN = "camelCaseDollarSign";
public static final String USE_ONE_OF_INTERFACES = "useOneOfInterfaces";
public static final String LOMBOK = "lombok";
public static final String DEFAULT_TEST_FOLDER = "${project.build.directory}/generated-test-sources/openapi";
public static final String GENERATE_CONSTRUCTOR_WITH_ALL_ARGS = "generateConstructorWithAllArgs";
public static final String GENERATE_BUILDERS = "generateBuilders";
@Getter @Setter
protected String dateLibrary = "java8";
@Setter protected boolean supportAsync = false;
@Setter protected boolean withXml = false;
@Getter @Setter
protected String invokerPackage = "org.openapitools";
@Getter @Setter
protected String groupId = "org.openapitools";
@Getter @Setter
protected String artifactId = "openapi-java";
@Getter @Setter
protected String artifactVersion = null;
@Getter @Setter
protected String artifactUrl = "https://github.com/openapitools/openapi-generator";
@Getter @Setter
protected String artifactDescription = "OpenAPI Java";
@Getter @Setter
protected String developerName = "OpenAPI-Generator Contributors";
@Getter @Setter
protected String developerEmail = "[email protected]";
@Getter @Setter
protected String developerOrganization = "OpenAPITools.org";
@Getter @Setter
protected String developerOrganizationUrl = "http://openapitools.org";
@Getter @Setter
protected String scmConnection = "scm:git:[email protected]:openapitools/openapi-generator.git";
@Getter @Setter
protected String scmDeveloperConnection = "scm:git:[email protected]:openapitools/openapi-generator.git";
@Getter @Setter
protected String scmUrl = "https://github.com/openapitools/openapi-generator";
@Getter @Setter
protected String licenseName = "Unlicense";
@Getter @Setter
protected String licenseUrl = "http://unlicense.org";
protected String projectFolder = "src/main";
protected String projectTestFolder = "src/test";
// this must not be OS-specific
@Getter @Setter
protected String sourceFolder = projectFolder + "/java";
@Getter @Setter
protected String testFolder = projectTestFolder + "/java";
/**
* -- SETTER --
* Set whether discriminator value lookup is case-sensitive or not.
*
* @param discriminatorCaseSensitive true if the discriminator value lookup should be case-sensitive.
*/
@Setter protected boolean discriminatorCaseSensitive = true;
@Getter @Setter
protected Boolean serializableModel = false;
@Setter protected boolean serializeBigDecimalAsString = false;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
@Setter protected boolean disableHtmlEscaping = false;
@Getter @Setter
protected String booleanGetterPrefix = "get";
@Setter protected boolean ignoreAnyOfInEnum = false;
@Setter protected String parentGroupId = "";
@Setter protected String parentArtifactId = "";
@Setter protected String parentVersion = "";
@Setter protected boolean parentOverridden = false;
@Getter @Setter
protected List additionalModelTypeAnnotations = new LinkedList<>();
protected Map lombokAnnotations = null;
@Getter @Setter
protected List additionalOneOfTypeAnnotations = new LinkedList<>();
@Setter protected List additionalEnumTypeAnnotations = new LinkedList<>();
@Getter @Setter
protected boolean openApiNullable = true;
@Setter protected String outputTestFolder = "";
protected DocumentationProvider documentationProvider;
protected AnnotationLibrary annotationLibrary;
@Setter protected boolean implicitHeaders = false;
@Setter protected String implicitHeadersRegex = null;
@Setter protected boolean camelCaseDollarSign = false;
@Setter protected boolean useJakartaEe = false;
@Setter protected boolean containerDefaultToNull = false;
@Getter @Setter
protected boolean generateConstructorWithAllArgs = false;
@Getter @Setter
protected boolean jackson = false;
@Getter @Setter
protected boolean generateBuilders;
/**
* useBeanValidation has been moved from child generators to AbstractJavaCodegen.
* The reason is that getBeanValidation needs it
*/
@Getter @Setter
protected boolean useBeanValidation = false;
private Map schemaKeyToModelNameCache = new HashMap<>();
public AbstractJavaCodegen() {
super();
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML))
.securityFeatures(EnumSet.of(
SecurityFeature.ApiKey,
SecurityFeature.BasicAuth,
SecurityFeature.BearerToken,
SecurityFeature.OAuth2_Implicit
))
.excludeGlobalFeatures(
GlobalFeature.XMLStructureDefinitions,
GlobalFeature.Callbacks,
GlobalFeature.LinkObjects,
GlobalFeature.ParameterStyling
)
.excludeSchemaSupportFeatures(
SchemaSupportFeature.Polymorphism
)
.includeClientModificationFeatures(
ClientModificationFeature.BasePath
)
);
supportsInheritance = true;
modelTemplateFiles.put("model.mustache", ".java");
apiTemplateFiles.put("api.mustache", ".java");
apiTestTemplateFiles.put("api_test.mustache", ".java");
modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");
hideGenerationTimestamp = false;
setReservedWordsLowerCase(
Arrays.asList(
// special words
"object", "list", "file",
// used as internal variables, can collide with parameter names
"localVarPath", "localVarQueryParams", "localVarCollectionQueryParams",
"localVarHeaderParams", "localVarCookieParams", "localVarFormParams", "localVarPostBody",
"localVarAccepts", "localVarAccept", "localVarContentTypes",
"localVarContentType", "localVarAuthNames", "localReturnType",
"ApiClient", "ApiException", "ApiResponse", "Configuration", "StringUtil",
// language reserved words
"_", "abstract", "continue", "for", "new", "switch", "assert",
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
"import", "public", "throws", "case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try", "char", "final", "interface", "static",
"void", "class", "finally", "long", "strictfp", "volatile", "const", "float",
"native", "super", "while", "null", "offsetdatetime", "localdate", "localtime")
);
languageSpecificPrimitives = Sets.newHashSet("String",
"boolean",
"Boolean",
"Double",
"Integer",
"Long",
"Float",
"Object",
"byte[]"
);
instantiationTypes.put("array", "ArrayList");
instantiationTypes.put("set", "LinkedHashSet");
instantiationTypes.put("map", "HashMap");
typeMapping.put("date", "Date");
typeMapping.put("file", "File");
typeMapping.put("AnyType", "Object");
importMapping.put("BigDecimal", "java.math.BigDecimal");
importMapping.put("UUID", "java.util.UUID");
importMapping.put("URI", "java.net.URI");
importMapping.put("File", "java.io.File");
importMapping.put("Date", "java.util.Date");
importMapping.put("Timestamp", "java.sql.Timestamp");
importMapping.put("Map", "java.util.Map");
importMapping.put("HashMap", "java.util.HashMap");
importMapping.put("Array", "java.util.List");
importMapping.put("ArrayList", "java.util.ArrayList");
importMapping.put("List", "java.util.*");
importMapping.put("Set", "java.util.*");
importMapping.put("LinkedHashSet", "java.util.LinkedHashSet");
importMapping.put("DateTime", "org.joda.time.*");
importMapping.put("LocalDateTime", "org.joda.time.*");
importMapping.put("LocalDate", "org.joda.time.*");
importMapping.put("LocalTime", "org.joda.time.*");
cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC));
cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC));
cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC).defaultValue(this.getInvokerPackage()));
cliOptions.add(new CliOption(CodegenConstants.GROUP_ID, CodegenConstants.GROUP_ID_DESC).defaultValue(this.getGroupId()));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_ID, CodegenConstants.ARTIFACT_ID_DESC).defaultValue(this.getArtifactId()));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC).defaultValue(ARTIFACT_VERSION_DEFAULT_VALUE));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_URL, CodegenConstants.ARTIFACT_URL_DESC).defaultValue(this.getArtifactUrl()));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_DESCRIPTION, CodegenConstants.ARTIFACT_DESCRIPTION_DESC).defaultValue(this.getArtifactDescription()));
cliOptions.add(new CliOption(CodegenConstants.SCM_CONNECTION, CodegenConstants.SCM_CONNECTION_DESC).defaultValue(this.getScmConnection()));
cliOptions.add(new CliOption(CodegenConstants.SCM_DEVELOPER_CONNECTION, CodegenConstants.SCM_DEVELOPER_CONNECTION_DESC).defaultValue(this.getScmDeveloperConnection()));
cliOptions.add(new CliOption(CodegenConstants.SCM_URL, CodegenConstants.SCM_URL_DESC).defaultValue(this.getScmUrl()));
cliOptions.add(new CliOption(CodegenConstants.DEVELOPER_NAME, CodegenConstants.DEVELOPER_NAME_DESC).defaultValue(this.getDeveloperName()));
cliOptions.add(new CliOption(CodegenConstants.DEVELOPER_EMAIL, CodegenConstants.DEVELOPER_EMAIL_DESC).defaultValue(this.getDeveloperEmail()));
cliOptions.add(new CliOption(CodegenConstants.DEVELOPER_ORGANIZATION, CodegenConstants.DEVELOPER_ORGANIZATION_DESC).defaultValue(this.getDeveloperOrganization()));
cliOptions.add(new CliOption(CodegenConstants.DEVELOPER_ORGANIZATION_URL, CodegenConstants.DEVELOPER_ORGANIZATION_URL_DESC).defaultValue(this.getDeveloperOrganizationUrl()));
cliOptions.add(new CliOption(CodegenConstants.LICENSE_NAME, CodegenConstants.LICENSE_NAME_DESC).defaultValue(this.getLicenseName()));
cliOptions.add(new CliOption(CodegenConstants.LICENSE_URL, CodegenConstants.LICENSE_URL_DESC).defaultValue(this.getLicenseUrl()));
cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC).defaultValue(this.getSourceFolder()));
cliOptions.add(CliOption.newBoolean(CodegenConstants.SERIALIZABLE_MODEL, CodegenConstants.SERIALIZABLE_MODEL_DESC, this.getSerializableModel()));
cliOptions.add(CliOption.newBoolean(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING, CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING_DESC, serializeBigDecimalAsString));
cliOptions.add(CliOption.newBoolean(DISCRIMINATOR_CASE_SENSITIVE, "Whether the discriminator value lookup should be case-sensitive or not. This option only works for Java API client", discriminatorCaseSensitive));
cliOptions.add(CliOption.newBoolean(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC, this.isHideGenerationTimestamp()));
cliOptions.add(CliOption.newBoolean(WITH_XML, "whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)"));
cliOptions.add(CliOption.newBoolean(USE_ONE_OF_INTERFACES, "whether to use a java interface to describe a set of oneOf options, where each option is a class that implements the interface"));
CliOption dateLibrary = new CliOption(DATE_LIBRARY, "Option. Date library to use").defaultValue(this.getDateLibrary());
Map dateOptions = new HashMap<>();
dateOptions.put("java8", "Java 8 native JSR310 (preferred for jdk 1.8+)");
dateOptions.put("java8-localdatetime", "Java 8 using LocalDateTime (for legacy app only)");
dateOptions.put("joda", "Joda (for legacy app only)");
dateOptions.put("legacy", "Legacy java.util.Date");
dateLibrary.setEnum(dateOptions);
cliOptions.add(dateLibrary);
cliOptions.add(CliOption.newBoolean(DISABLE_HTML_ESCAPING, "Disable HTML escaping of JSON strings when using gson (needed to avoid problems with byte[] fields)", disableHtmlEscaping));
cliOptions.add(CliOption.newString(BOOLEAN_GETTER_PREFIX, "Set booleanGetterPrefix").defaultValue(this.getBooleanGetterPrefix()));
cliOptions.add(CliOption.newBoolean(IGNORE_ANYOF_IN_ENUM, "Ignore anyOf keyword in enum", ignoreAnyOfInEnum));
cliOptions.add(CliOption.newString(ADDITIONAL_ENUM_TYPE_ANNOTATIONS, "Additional annotations for enum type(class level annotations)"));
cliOptions.add(CliOption.newString(ADDITIONAL_MODEL_TYPE_ANNOTATIONS, "Additional annotations for model type(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)"));
cliOptions.add(CliOption.newString(ADDITIONAL_ONE_OF_TYPE_ANNOTATIONS, "Additional annotations for oneOf interfaces(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)"));
cliOptions.add(CliOption.newBoolean(OPENAPI_NULLABLE, "Enable OpenAPI Jackson Nullable library", this.openApiNullable));
cliOptions.add(CliOption.newBoolean(IMPLICIT_HEADERS, "Skip header parameters in the generated API methods using @ApiImplicitParams annotation.", implicitHeaders));
cliOptions.add(CliOption.newString(IMPLICIT_HEADERS_REGEX, "Skip header parameters that matches given regex in the generated API methods using @ApiImplicitParams annotation. Note: this parameter is ignored when implicitHeaders=true"));
cliOptions.add(CliOption.newBoolean(CAMEL_CASE_DOLLAR_SIGN, "Fix camelCase when starting with $ sign. when true : $Value when false : $value"));
cliOptions.add(CliOption.newBoolean(USE_JAKARTA_EE, "whether to use Jakarta EE namespace instead of javax"));
cliOptions.add(CliOption.newBoolean(CONTAINER_DEFAULT_TO_NULL, "Set containers (array, set, map) default to null"));
cliOptions.add(CliOption.newBoolean(GENERATE_CONSTRUCTOR_WITH_ALL_ARGS, "whether to generate a constructor for all arguments").defaultValue(Boolean.FALSE.toString()));
cliOptions.add(CliOption.newBoolean(GENERATE_BUILDERS, "Whether to generate builders for models").defaultValue(Boolean.FALSE.toString()));
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));
CliOption snapShotVersion = CliOption.newString(CodegenConstants.SNAPSHOT_VERSION, CodegenConstants.SNAPSHOT_VERSION_DESC);
Map snapShotVersionOptions = new HashMap<>();
snapShotVersionOptions.put("true", "Use a SnapShot Version");
snapShotVersionOptions.put("false", "Use a Release Version");
snapShotVersion.setEnum(snapShotVersionOptions);
cliOptions.add(snapShotVersion);
cliOptions.add(CliOption.newString(TEST_OUTPUT, "Set output folder for models and APIs tests").defaultValue(DEFAULT_TEST_FOLDER));
if (null != defaultDocumentationProvider()) {
CliOption documentationProviderCliOption = new CliOption(DOCUMENTATION_PROVIDER,
"Select the OpenAPI documentation provider.")
.defaultValue(defaultDocumentationProvider().toCliOptValue());
supportedDocumentationProvider().forEach(dp ->
documentationProviderCliOption.addEnum(dp.toCliOptValue(), dp.getDescription()));
cliOptions.add(documentationProviderCliOption);
CliOption annotationLibraryCliOption = new CliOption(ANNOTATION_LIBRARY,
"Select the complementary documentation annotation library.")
.defaultValue(defaultDocumentationProvider().getPreferredAnnotationLibrary().toCliOptValue());
supportedAnnotationLibraries().forEach(al ->
annotationLibraryCliOption.addEnum(al.toCliOptValue(), al.getDescription()));
cliOptions.add(annotationLibraryCliOption);
}
}
@Override
public void processOpts() {
useCodegenAsMustacheParentContext();
super.processOpts();
if (null != defaultDocumentationProvider()) {
documentationProvider = DocumentationProvider.ofCliOption(
(String) additionalProperties.getOrDefault(DOCUMENTATION_PROVIDER,
defaultDocumentationProvider().toCliOptValue())
);
if (!supportedDocumentationProvider().contains(documentationProvider)) {
String msg = String.format(Locale.ROOT,
"The [%s] Documentation Provider is not supported by this generator",
documentationProvider.toCliOptValue());
throw new IllegalArgumentException(msg);
}
annotationLibrary = AnnotationLibrary.ofCliOption(
(String) additionalProperties.getOrDefault(ANNOTATION_LIBRARY,
documentationProvider.getPreferredAnnotationLibrary().toCliOptValue())
);
if (!supportedAnnotationLibraries().contains(annotationLibrary)) {
String msg = String.format(Locale.ROOT, "The Annotation Library [%s] is not supported by this generator",
annotationLibrary.toCliOptValue());
throw new IllegalArgumentException(msg);
}
if (!documentationProvider.supportedAnnotationLibraries().contains(annotationLibrary)) {
String msg = String.format(Locale.ROOT,
"The [%s] documentation provider does not support [%s] as complementary annotation library",
documentationProvider.toCliOptValue(), annotationLibrary.toCliOptValue());
throw new IllegalArgumentException(msg);
}
additionalProperties.put(DOCUMENTATION_PROVIDER, documentationProvider.toCliOptValue());
additionalProperties.put(documentationProvider.getPropertyName(), true);
additionalProperties.put(ANNOTATION_LIBRARY, annotationLibrary.toCliOptValue());
additionalProperties.put(annotationLibrary.getPropertyName(), true);
} else {
additionalProperties.put(DOCUMENTATION_PROVIDER, DocumentationProvider.NONE);
additionalProperties.put(ANNOTATION_LIBRARY, AnnotationLibrary.NONE);
}
convertPropertyToBooleanAndWriteBack(GENERATE_CONSTRUCTOR_WITH_ALL_ARGS, this::setGenerateConstructorWithAllArgs);
convertPropertyToBooleanAndWriteBack(GENERATE_BUILDERS, this::setGenerateBuilders);
if (StringUtils.isEmpty(System.getenv("JAVA_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable JAVA_POST_PROCESS_FILE not defined so the Java code may not be properly formatted. To define it, try 'export JAVA_POST_PROCESS_FILE=\"/usr/local/bin/clang-format -i\"' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
} else if (!this.isEnablePostProcessFile()) {
LOGGER.info("Warning: Environment variable 'JAVA_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
}
convertPropertyToBooleanAndWriteBack(BeanValidationFeatures.USE_BEANVALIDATION, this::setUseBeanValidation);
convertPropertyToBooleanAndWriteBack(DISABLE_HTML_ESCAPING, this::setDisableHtmlEscaping);
convertPropertyToStringAndWriteBack(BOOLEAN_GETTER_PREFIX, this::setBooleanGetterPrefix);
convertPropertyToBooleanAndWriteBack(IGNORE_ANYOF_IN_ENUM, this::setIgnoreAnyOfInEnum);
convertPropertyToTypeAndWriteBack(ADDITIONAL_MODEL_TYPE_ANNOTATIONS,
annotations-> Arrays.asList(annotations.trim().split("\\s*(;|\\r?\\n)\\s*")),
this::setAdditionalModelTypeAnnotations);
convertPropertyToTypeAndWriteBack(ADDITIONAL_ONE_OF_TYPE_ANNOTATIONS,
annotations-> Arrays.asList(annotations.trim().split("\\s*(;|\\r?\\n)\\s*")),
this::setAdditionalOneOfTypeAnnotations);
convertPropertyToTypeAndWriteBack(ADDITIONAL_ENUM_TYPE_ANNOTATIONS,
annotations -> Arrays.asList(annotations.split(";")),
this::setAdditionalEnumTypeAnnotations);
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
} else if (additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
// guess from api package
String derivedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.API_PACKAGE));
this.setInvokerPackage(derivedInvokerPackage);
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 derivedInvokerPackage = deriveInvokerPackageName((String) additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
this.setInvokerPackage(derivedInvokerPackage);
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);
}
if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
}
if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
}
if (additionalProperties.containsKey(CodegenConstants.GROUP_ID)) {
this.setGroupId((String) additionalProperties.get(CodegenConstants.GROUP_ID));
} else {
//not set, use to be passed to template
additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
}
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_ID)) {
this.setArtifactId((String) additionalProperties.get(CodegenConstants.ARTIFACT_ID));
} else {
//not set, use to be passed to template
additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
}
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_URL)) {
this.setArtifactUrl((String) additionalProperties.get(CodegenConstants.ARTIFACT_URL));
} else {
additionalProperties.put(CodegenConstants.ARTIFACT_URL, artifactUrl);
}
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_DESCRIPTION)) {
this.setArtifactDescription((String) additionalProperties.get(CodegenConstants.ARTIFACT_DESCRIPTION));
} else {
additionalProperties.put(CodegenConstants.ARTIFACT_DESCRIPTION, artifactDescription);
}
if (additionalProperties.containsKey(CodegenConstants.SCM_CONNECTION)) {
this.setScmConnection((String) additionalProperties.get(CodegenConstants.SCM_CONNECTION));
} else {
additionalProperties.put(CodegenConstants.SCM_CONNECTION, scmConnection);
}
if (additionalProperties.containsKey(CodegenConstants.SCM_DEVELOPER_CONNECTION)) {
this.setScmDeveloperConnection((String) additionalProperties.get(CodegenConstants.SCM_DEVELOPER_CONNECTION));
} else {
additionalProperties.put(CodegenConstants.SCM_DEVELOPER_CONNECTION, scmDeveloperConnection);
}
if (additionalProperties.containsKey(CodegenConstants.SCM_URL)) {
this.setScmUrl((String) additionalProperties.get(CodegenConstants.SCM_URL));
} else {
additionalProperties.put(CodegenConstants.SCM_URL, scmUrl);
}
if (additionalProperties.containsKey(CodegenConstants.DEVELOPER_NAME)) {
this.setDeveloperName((String) additionalProperties.get(CodegenConstants.DEVELOPER_NAME));
} else {
additionalProperties.put(CodegenConstants.DEVELOPER_NAME, developerName);
}
if (additionalProperties.containsKey(CodegenConstants.DEVELOPER_EMAIL)) {
this.setDeveloperEmail((String) additionalProperties.get(CodegenConstants.DEVELOPER_EMAIL));
} else {
additionalProperties.put(CodegenConstants.DEVELOPER_EMAIL, developerEmail);
}
if (additionalProperties.containsKey(CodegenConstants.DEVELOPER_ORGANIZATION)) {
this.setDeveloperOrganization((String) additionalProperties.get(CodegenConstants.DEVELOPER_ORGANIZATION));
} else {
additionalProperties.put(CodegenConstants.DEVELOPER_ORGANIZATION, developerOrganization);
}
if (additionalProperties.containsKey(CodegenConstants.DEVELOPER_ORGANIZATION_URL)) {
this.setDeveloperOrganizationUrl((String) additionalProperties.get(CodegenConstants.DEVELOPER_ORGANIZATION_URL));
} else {
additionalProperties.put(CodegenConstants.DEVELOPER_ORGANIZATION_URL, developerOrganizationUrl);
}
convertPropertyToStringAndWriteBack(CodegenConstants.MODEL_PACKAGE, this::setModelPackage);
convertPropertyToStringAndWriteBack(CodegenConstants.API_PACKAGE, this::setApiPackage);
convertPropertyToStringAndWriteBack(CodegenConstants.GROUP_ID, this::setGroupId);
convertPropertyToStringAndWriteBack(CodegenConstants.ARTIFACT_ID, this::setArtifactId);
convertPropertyToStringAndWriteBack(CodegenConstants.ARTIFACT_URL, this::setArtifactUrl);
convertPropertyToStringAndWriteBack(CodegenConstants.ARTIFACT_DESCRIPTION, this::setArtifactDescription);
convertPropertyToStringAndWriteBack(CodegenConstants.SCM_CONNECTION, this::setScmConnection);
convertPropertyToStringAndWriteBack(CodegenConstants.SCM_DEVELOPER_CONNECTION, this::setScmDeveloperConnection);
convertPropertyToStringAndWriteBack(CodegenConstants.SCM_URL, this::setScmUrl);
convertPropertyToStringAndWriteBack(CodegenConstants.DEVELOPER_NAME, this::setDeveloperName);
convertPropertyToStringAndWriteBack(CodegenConstants.DEVELOPER_EMAIL, this::setDeveloperEmail);
convertPropertyToStringAndWriteBack(CodegenConstants.DEVELOPER_ORGANIZATION, this::setDeveloperOrganization);
convertPropertyToStringAndWriteBack(CodegenConstants.DEVELOPER_ORGANIZATION_URL, this::setDeveloperOrganizationUrl);
convertPropertyToStringAndWriteBack(CodegenConstants.LICENSE_NAME, this::setLicenseName);
convertPropertyToStringAndWriteBack(CodegenConstants.LICENSE_URL, this::setLicenseUrl);
convertPropertyToStringAndWriteBack(CodegenConstants.SOURCE_FOLDER, this::setSourceFolder);
convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZABLE_MODEL, this::setSerializableModel);
convertPropertyToStringAndWriteBack(CodegenConstants.LIBRARY, this::setLibrary);
convertPropertyToBooleanAndWriteBack(CodegenConstants.SERIALIZE_BIG_DECIMAL_AS_STRING, this::setSerializeBigDecimalAsString );
// need to put back serializableModel (boolean) into additionalProperties as value in additionalProperties is string
// additionalProperties.put(CodegenConstants.SERIALIZABLE_MODEL, serializableModel);
// By default, the discriminator lookup should be case sensitive. There is nothing in the OpenAPI specification
// that indicates the lookup should be case insensitive. However, some implementations perform
// a case-insensitive lookup.
convertPropertyToBooleanAndWriteBack(DISCRIMINATOR_CASE_SENSITIVE, this::setDiscriminatorCaseSensitive);
convertPropertyToBooleanAndWriteBack(WITH_XML, this::setWithXml);
convertPropertyToBooleanAndWriteBack(OPENAPI_NULLABLE, this::setOpenApiNullable);
convertPropertyToStringAndWriteBack(CodegenConstants.PARENT_GROUP_ID, this::setParentGroupId);
convertPropertyToStringAndWriteBack(CodegenConstants.PARENT_ARTIFACT_ID, this::setParentArtifactId);
convertPropertyToStringAndWriteBack(CodegenConstants.PARENT_VERSION, this::setParentVersion);
convertPropertyToBooleanAndWriteBack(IMPLICIT_HEADERS, this::setImplicitHeaders);
convertPropertyToStringAndWriteBack(IMPLICIT_HEADERS_REGEX, this::setImplicitHeadersRegex);
convertPropertyToBooleanAndWriteBack(CAMEL_CASE_DOLLAR_SIGN, this::setCamelCaseDollarSign);
convertPropertyToBooleanAndWriteBack(USE_ONE_OF_INTERFACES, this::setUseOneOfInterfaces);
if (!StringUtils.isEmpty(parentGroupId) && !StringUtils.isEmpty(parentArtifactId) && !StringUtils.isEmpty(parentVersion)) {
additionalProperties.put("parentOverridden", true);
}
// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
importMapping.put("List", "java.util.List");
importMapping.put("Set", "java.util.Set");
this.sanitizeConfig();
// optional jackson mappings for BigDecimal support
if (serializeBigDecimalAsString) {
importMapping.put("JsonFormat", "com.fasterxml.jackson.annotation.JsonFormat");
}
// imports for pojos
importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty");
importMapping.put("ApiModel", "io.swagger.annotations.ApiModel");
importMapping.put("Schema", "io.swagger.v3.oas.annotations.media.Schema");
importMapping.put("BigDecimal", "java.math.BigDecimal");
importMapping.put("JsonDeserialize", "com.fasterxml.jackson.databind.annotation.JsonDeserialize");
importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty");
importMapping.put("JsonSubTypes", "com.fasterxml.jackson.annotation.JsonSubTypes");
importMapping.put("JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonTypeInfo");
importMapping.put("JsonTypeName", "com.fasterxml.jackson.annotation.JsonTypeName");
importMapping.put("JsonCreator", "com.fasterxml.jackson.annotation.JsonCreator");
importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue");
importMapping.put("JsonIgnore", "com.fasterxml.jackson.annotation.JsonIgnore");
importMapping.put("JsonIgnoreProperties", "com.fasterxml.jackson.annotation.JsonIgnoreProperties");
importMapping.put("JsonInclude", "com.fasterxml.jackson.annotation.JsonInclude");
if (openApiNullable) {
importMapping.put("JsonNullable", "org.openapitools.jackson.nullable.JsonNullable");
}
importMapping.put("SerializedName", "com.google.gson.annotations.SerializedName");
importMapping.put("TypeAdapter", "com.google.gson.TypeAdapter");
importMapping.put("JsonAdapter", "com.google.gson.annotations.JsonAdapter");
importMapping.put("JsonReader", "com.google.gson.stream.JsonReader");
importMapping.put("JsonWriter", "com.google.gson.stream.JsonWriter");
importMapping.put("IOException", "java.io.IOException");
importMapping.put("Arrays", "java.util.Arrays");
importMapping.put("Objects", "java.util.Objects");
importMapping.put("StringUtil", invokerPackage + ".StringUtil");
// import JsonCreator if JsonProperty is imported
// used later in recursive import in postProcessingModels
importMapping.put("com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonCreator");
convertPropertyToBooleanAndWriteBack(SUPPORT_ASYNC, this::setSupportAsync);
convertPropertyToStringAndWriteBack(DATE_LIBRARY, this::setDateLibrary);
if ("joda".equals(dateLibrary)) {
additionalProperties.put("joda", "true");
typeMapping.put("date", "LocalDate");
typeMapping.put("DateTime", "DateTime");
importMapping.put("LocalDate", "org.joda.time.LocalDate");
importMapping.put("DateTime", "org.joda.time.DateTime");
} else if (dateLibrary.startsWith("java8")) {
additionalProperties.put("java8", "true");
additionalProperties.put("jsr310", "true");
typeMapping.put("date", "LocalDate");
importMapping.put("LocalDate", "java.time.LocalDate");
importMapping.put("LocalTime", "java.time.LocalTime");
if ("java8-localdatetime".equals(dateLibrary)) {
typeMapping.put("DateTime", "LocalDateTime");
importMapping.put("LocalDateTime", "java.time.LocalDateTime");
} else {
typeMapping.put("DateTime", "OffsetDateTime");
importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
}
} else if (dateLibrary.equals("legacy")) {
additionalProperties.put("legacyDates", "true");
}
convertPropertyToStringAndWriteBack(TEST_OUTPUT, this::setOutputTestFolder);
convertPropertyToBooleanAndWriteBack(USE_JAKARTA_EE, this::setUseJakartaEe);
if (useJakartaEe) {
applyJakartaPackage();
} else {
applyJavaxPackage();
}
convertPropertyToBooleanAndWriteBack(CONTAINER_DEFAULT_TO_NULL, this::setContainerDefaultToNull);
additionalProperties.put("sanitizeGeneric", (Mustache.Lambda) (fragment, writer) -> {
String content = removeAnnotations(fragment.execute());
for (final String s: List.of("<", ">", ",", " ")) {
content = content.replace(s, "");
}
writer.write(content);
});
}
/**
* Analyse and post process all Models.
* @param objs the models map.
* @return the processed models map.
**/
@Override
public Map postProcessAllModels(Map objs) {
objs = super.postProcessAllModels(objs);
objs = super.updateAllModels(objs);
Map allModels = getAllModels(objs);
if (!additionalModelTypeAnnotations.isEmpty()) {
for (String modelName : objs.keySet()) {
Map models = objs.get(modelName);
models.put(ADDITIONAL_MODEL_TYPE_ANNOTATIONS, additionalModelTypeAnnotations);
}
}
if (!additionalOneOfTypeAnnotations.isEmpty()) {
for (String modelName : objs.keySet()) {
Map models = objs.get(modelName);
models.put(ADDITIONAL_ONE_OF_TYPE_ANNOTATIONS, additionalOneOfTypeAnnotations);
}
}
if (!additionalEnumTypeAnnotations.isEmpty()) {
for (String modelName : objs.keySet()) {
Map models = objs.get(modelName);
models.put(ADDITIONAL_ENUM_TYPE_ANNOTATIONS, additionalEnumTypeAnnotations);
}
}
/*
Add parentVars and parentRequiredVars to every Model which has a parent.
Add isInherited to every model which has children.
This allows
the generation of fluent setter methods for inherited properties
the generation of all arg constructors
ps: This code was specific to SpringCodeGen and now is available to all java generators.
*/
for (ModelsMap modelsAttrs : objs.values()) {
for (ModelMap mo : modelsAttrs.getModels()) {
CodegenModel codegenModel = mo.getModel();
Set inheritedImports = new HashSet<>();
Map propertyHash = new HashMap<>(codegenModel.vars.size());
for (final CodegenProperty property : codegenModel.vars) {
propertyHash.put(property.name, property);
}
List parentModelList = getParentModelList(codegenModel);
for (CodegenModel parentCodegenModel: parentModelList) {
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.debug("adding parent variable {} to {}", property.name, codegenModel.name);
codegenModel.parentVars.add(parentVar);
Set imports = parentVar.getImports(true, this.importBaseType, generatorMetadata.getFeatureSet()).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);
}
}
}
}
}
if (codegenModel.getParentModel() != null) {
codegenModel.parentRequiredVars = new ArrayList<>(codegenModel.getParentModel().requiredVars);
}
// There must be a better way ...
for (String imp: inheritedImports) {
String qimp = importMapping().get(imp);
if (qimp != null) {
Map toAdd = new HashMap<>();
toAdd.put("import", qimp);
modelsAttrs.getImports().add(toAdd);
}
}
}
}
if (isGenerateConstructorWithAllArgs()) {
// conditionally force the generation of all args constructor.
for (CodegenModel cm : allModels.values()) {
if (isConstructorWithAllArgsAllowed(cm)) {
cm.vendorExtensions.put("x-java-all-args-constructor", true);
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy