Skip to content
Open
  •  
  •  
  •  
25 changes: 25 additions & 0 deletions docs/templating.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@ OpenAPI Generator supports user-defined templates. This approach is often the ea

> **Note:** You cannot use this approach to create new templates, only override existing ones. If you'd like to create a new generator to contribute back to the project, see `new.sh` in the repository root. If you'd like to create a private generator for more templating control, see the [customization](./customization.md) docs.

### Raw values and source-literal helpers

Specification text is data and must be encoded at its destination. The
`spring` and `kotlin-spring` generators expose additive Mustache helpers:

* `javaStringLiteral` and `kotlinStringLiteral` accept raw contents and emit a
complete quoted literal. Do not add another pair of quotes.
* `javaStringContent` and `kotlinStringContent` emit escaped contents for a
template-owned literal.
* `javaDocText` and `kotlinDocText` emit literal documentation text: they
HTML-escape text, protect comment delimiters (including Java Unicode-escape
preprocessing), and preserve line breaks.

Use triple-brace values inside these helpers so Mustache HTML escaping does not
run before source escaping:

```mustache
description = {{#lambda.kotlinStringLiteral}}{{{unescapedNotes}}}{{/lambda.kotlinStringLiteral}}
```

These helpers are scoped to the Spring generators and their supported
libraries. Keep raw specification fields separate from generated expressions,
identifiers, and intentional vendor-extension code. Other generators,
including Java `okhttp-gson`, are not covered by this contract.

OpenAPI Generator not only supports local files for templating, but also templates defined on the classpath. This is a great option if you want to reuse templates across multiple projects. To load a template via classpath, you'll need to generate a little differently. For example, if you've created an artifact called `template-classpath-example` which contains extended templates for the `htmlDocs` generator with the following structure:

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public class CodegenOperation {
isDeprecated, isCallbackRequest, uniqueItems,
hasErrorResponseObject; // if 4xx, 5xx responses have at least one error object defined
public CodegenProperty returnProperty;
public String path, operationId, returnType, returnFormat, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
public String path, unescapedPath, operationId, returnType, returnFormat, httpMethod, returnBaseType,
returnContainer, summary, unescapedSummary, unescapedNotes, notes, baseName, defaultResponse;
public CodegenDiscriminator discriminator;
public List<Map<String, String>> consumes, produces, prioritizedContentTypes;
public List<CodegenServer> servers = new ArrayList<CodegenServer>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.openapitools.codegen;

import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.models.examples.Example;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -35,6 +36,10 @@ public class CodegenParameter implements IJsonSchemaValidationProperties {
isFormStyle, isSpaceDelimited, isPipeDelimited;
public String baseName, paramName, dataType, datatypeWithEnum, dataFormat, contentType,
collectionFormat, description, unescapedDescription, baseType, defaultValue, enumDefaultValue, enumName, style;
/** Typed snapshot of the schema default captured before language conversion. */
public JsonNode rawDefaultValue;
public String rawDefaultValueText;
public boolean hasDefaultValue;

public String nameInLowerCase; // property name in lower case
public String nameInCamelCase; // property name in camel case (e.g. modifiedDate)
Expand Down Expand Up @@ -182,6 +187,9 @@ public CodegenParameter copy() {
output.multipleOf = this.multipleOf;
output.jsonSchema = this.jsonSchema;
output.defaultValue = this.defaultValue;
output.rawDefaultValue = this.rawDefaultValue;
output.rawDefaultValueText = this.rawDefaultValueText;
output.hasDefaultValue = this.hasDefaultValue;
output.enumDefaultValue = this.enumDefaultValue;
output.example = this.example;
output.examples = this.examples;
Expand Down Expand Up @@ -290,7 +298,8 @@ public int hashCode() {
isBodyParam, isContainer, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName,
paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description,
unescapedDescription, baseType, containerType, containerTypeMapped, defaultValue,
enumDefaultValue, enumName, style, isDeepObject, isMatrix, isAllowEmptyValue, example, examples,
rawDefaultValue, rawDefaultValueText, hasDefaultValue, enumDefaultValue, enumName, style,
isDeepObject, isMatrix, isAllowEmptyValue, example, examples,
isFormStyle, isSpaceDelimited, isPipeDelimited,
jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal,
isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isPassword,
Expand Down Expand Up @@ -382,6 +391,9 @@ public boolean equals(Object o) {
Objects.equals(containerType, that.containerType) &&
Objects.equals(containerTypeMapped, that.containerTypeMapped) &&
Objects.equals(defaultValue, that.defaultValue) &&
Objects.equals(rawDefaultValue, that.rawDefaultValue) &&
Objects.equals(rawDefaultValueText, that.rawDefaultValueText) &&
hasDefaultValue == that.hasDefaultValue &&
Objects.equals(enumDefaultValue, that.enumDefaultValue) &&
Objects.equals(enumName, that.enumName) &&
Objects.equals(style, that.style) &&
Expand Down Expand Up @@ -1151,4 +1163,3 @@ public void setIsEnum(boolean isEnum) {
this.isEnum = isEnum;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.openapitools.codegen;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.Setter;

Expand Down Expand Up @@ -61,6 +62,10 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
public String max; // TODO: is this really used?
@Getter @Setter
public String defaultValue;
/** Typed snapshot of the schema default captured before language conversion. */
public JsonNode rawDefaultValue;
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
public String rawDefaultValueText;
public boolean hasDefaultValue;
@Getter @Setter
public String defaultValueWithParam;
@Setter public String baseType;
Expand Down Expand Up @@ -98,6 +103,8 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti
*/
@Getter @Setter
public String example;
/** Original schema example before language-specific escaping. */
public String rawExample;

@Getter @Setter
public String jsonSchema;
Expand Down Expand Up @@ -986,6 +993,9 @@ public String toString() {
sb.append(", min='").append(min).append('\'');
sb.append(", max='").append(max).append('\'');
sb.append(", defaultValue='").append(defaultValue).append('\'');
sb.append(", rawDefaultValue=").append(rawDefaultValue);
sb.append(", rawDefaultValueText='").append(rawDefaultValueText).append('\'');
sb.append(", hasDefaultValue=").append(hasDefaultValue);
sb.append(", defaultValueWithParam='").append(defaultValueWithParam).append('\'');
sb.append(", baseType='").append(baseType).append('\'');
sb.append(", containerType='").append(containerType).append('\'');
Expand All @@ -996,6 +1006,7 @@ public String toString() {
sb.append(", minLength=").append(minLength);
sb.append(", pattern='").append(pattern).append('\'');
sb.append(", example='").append(example).append('\'');
sb.append(", rawExample='").append(rawExample).append('\'');
sb.append(", jsonSchema='").append(jsonSchema).append('\'');
sb.append(", minimum='").append(minimum).append('\'');
sb.append(", maximum='").append(maximum).append('\'');
Expand Down Expand Up @@ -1173,6 +1184,9 @@ public boolean equals(Object o) {
Objects.equals(min, that.min) &&
Objects.equals(max, that.max) &&
Objects.equals(defaultValue, that.defaultValue) &&
Objects.equals(rawDefaultValue, that.rawDefaultValue) &&
Objects.equals(rawDefaultValueText, that.rawDefaultValueText) &&
hasDefaultValue == that.hasDefaultValue &&
Objects.equals(defaultValueWithParam, that.defaultValueWithParam) &&
Objects.equals(baseType, that.baseType) &&
Objects.equals(containerType, that.containerType) &&
Expand All @@ -1183,6 +1197,7 @@ public boolean equals(Object o) {
Objects.equals(minLength, that.minLength) &&
Objects.equals(pattern, that.pattern) &&
Objects.equals(example, that.example) &&
Objects.equals(rawExample, that.rawExample) &&
Objects.equals(jsonSchema, that.jsonSchema) &&
Objects.equals(minimum, that.minimum) &&
Objects.equals(maximum, that.maximum) &&
Expand Down Expand Up @@ -1212,8 +1227,9 @@ public int hashCode() {

return Objects.hash(openApiType, baseName, complexType, getter, setter, description,
dataType, datatypeWithEnum, dataFormat, name, min, max, defaultValue,
defaultValueWithParam, baseType, containerType, containerTypeMapped, title, unescapedDescription,
maxLength, minLength, pattern, example, jsonSchema, minimum, maximum,
rawDefaultValue, rawDefaultValueText, hasDefaultValue, defaultValueWithParam, baseType,
containerType, containerTypeMapped, title, unescapedDescription,
maxLength, minLength, pattern, example, rawExample, jsonSchema, minimum, maximum,
exclusiveMinimum, exclusiveMaximum, required, deprecated,
isPrimitiveType, isModel, isContainer, isString, isNumeric,
isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class CodegenResponse implements IJsonSchemaValidationProperties {
public boolean is4xx;
public boolean is5xx;
public String message;
/** Original response description before generator escaping. */
public String unescapedMessage;
public List<Map<String, Object>> examples;
public String dataType;
public String baseType;
Expand Down Expand Up @@ -109,7 +111,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties {

@Override
public int hashCode() {
return Objects.hash(headers, code, message, examples, dataType, baseType, containerType, containerTypeMapped, hasHeaders,
return Objects.hash(headers, code, message, unescapedMessage, examples, dataType, baseType, containerType, containerTypeMapped, hasHeaders,
isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBoolean, isDate,
isDateTime, isUuid, isEmail, isPassword, isModel, isFreeFormObject, isAnyType, isDefault, simpleType, primitiveType,
isMap, isOptional, isArray, isBinary, isFile, schema, jsonSchema, vendorExtensions, items, additionalProperties,
Expand Down Expand Up @@ -182,6 +184,7 @@ public boolean equals(Object o) {
Objects.equals(headers, that.headers) &&
Objects.equals(code, that.code) &&
Objects.equals(message, that.message) &&
Objects.equals(unescapedMessage, that.unescapedMessage) &&
Objects.equals(examples, that.examples) &&
Objects.equals(dataType, that.dataType) &&
Objects.equals(baseType, that.baseType) &&
Expand Down
Loading
Loading