OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec
—
The validation framework provides JSON Schema validation properties and type checking utilities for ensuring proper data handling and constraint validation throughout the code generation process.
Defines JSON Schema validation properties implemented by models, properties, parameters, and responses.
interface IJsonSchemaValidationProperties {
// Type identification methods
boolean getIsModel(); // Is a custom model/object type
boolean getIsArray(); // Is an array/list type
boolean getIsMap(); // Is a map/dictionary type
boolean getIsString(); // Is a string type
boolean getIsNumber(); // Is any numeric type
boolean getIsInteger(); // Is an integer type
boolean getIsBoolean(); // Is a boolean type
boolean getIsDate(); // Is a date type
boolean getIsDateTime(); // Is a date-time type
boolean getIsPrimitiveType(); // Is a primitive type (string, number, boolean)
boolean getIsEnum(); // Is an enumeration type
// Validation constraint methods
String getPattern(); // Regular expression pattern
String getMinimum(); // Minimum value for numbers
String getMaximum(); // Maximum value for numbers
boolean getExclusiveMinimum(); // Exclusive minimum flag
boolean getExclusiveMaximum(); // Exclusive maximum flag
Integer getMinLength(); // Minimum string length
Integer getMaxLength(); // Maximum string length
Integer getMinItems(); // Minimum array items
Integer getMaxItems(); // Maximum array items
boolean getUniqueItems(); // Array items must be unique
Integer getMinProperties(); // Minimum object properties
Integer getMaxProperties(); // Maximum object properties
Number getMultipleOf(); // Number must be multiple of this value
// Schema relationship methods
CodegenProperty getItems(); // For arrays - item type
CodegenProperty getAdditionalProperties(); // For objects - additional props type
List<CodegenProperty> getVars(); // Object properties
List<CodegenProperty> getRequiredVars(); // Required object properties
CodegenComposedSchemas getComposedSchemas(); // oneOf/anyOf/allOf schemas
// Type processing methods
void setTypeProperties(Schema p, OpenAPI openAPI); // Set type properties from schema
String getBaseType(); // Get base type name
String getComplexType(); // Get full type with generics
Set<String> getImports(boolean importContainerType, boolean importBaseType, FeatureSet featureSet);
}Static utilities for checking OpenAPI schema types.
class ModelUtils {
// Schema type checking
public static boolean isObjectSchema(Schema schema);
public static boolean isComposedSchema(Schema schema); // oneOf/anyOf/allOf
public static boolean isMapSchema(Schema schema);
public static boolean isArraySchema(Schema schema);
public static boolean isStringSchema(Schema schema);
public static boolean isIntegerSchema(Schema schema);
public static boolean isNumberSchema(Schema schema);
public static boolean isBooleanSchema(Schema schema);
public static boolean isNullType(Schema schema);
public static boolean isAnyType(Schema schema);
// Format-specific type checking
public static boolean isDateSchema(Schema schema); // date format
public static boolean isDateTimeSchema(Schema schema); // date-time format
public static boolean isByteArraySchema(Schema schema); // byte format
public static boolean isBinarySchema(Schema schema); // binary format
public static boolean isFileSchema(Schema schema); // file type
public static boolean isUUIDSchema(Schema schema); // uuid format
public static boolean isEmailSchema(Schema schema); // email format
public static boolean isPasswordSchema(Schema schema); // password format
// Schema analysis
public static List<String> getAllUsedSchemas(OpenAPI openAPI); // Find all referenced schemas
public static List<String> getUnusedSchemas(OpenAPI openAPI); // Find unused schemas
public static String getSimpleRef(String ref); // Extract name from $ref
public static Schema unaliasSchema(Schema schema, OpenAPI openAPI); // Resolve schema aliases
// Model utilities
public static CodegenModel getModelByName(final String name, final Map<String, ModelsMap> models);
public static boolean isGenerateAliasAsModel();
public static void setGenerateAliasAsModel(boolean value);
}Exception thrown when OpenAPI specification validation fails.
class SpecValidationException extends RuntimeException {
// Constructors
public SpecValidationException();
public SpecValidationException(String message);
public SpecValidationException(String message, Throwable cause);
public SpecValidationException(Throwable cause);
// Error and warning handling
public Set<String> getErrors(); // Get validation errors
public void setErrors(Set<String> errors);
public Set<String> getWarnings(); // Get validation warnings
public void setWarnings(Set<String> warnings);
// Overridden methods
public String getMessage(); // Get formatted error message
}Exception thrown when a specified generator cannot be found.
class GeneratorNotFoundException extends RuntimeException {
// Inherits standard RuntimeException constructors
}public class ValidatingGenerator extends DefaultCodegen {
@Override
public CodegenModel fromModel(String name, Schema schema) {
CodegenModel model = super.fromModel(name, schema);
// Validate model properties
validateModelProperties(model);
return model;
}
private void validateModelProperties(CodegenModel model) {
for (CodegenProperty property : model.vars) {
validateProperty(property);
}
}
private void validateProperty(CodegenProperty property) {
// Check string length constraints
if (property.getIsString()) {
if (property.getMinLength() != null && property.getMaxLength() != null) {
if (property.getMinLength() > property.getMaxLength()) {
throw new SpecValidationException(
"Property " + property.name + " has minLength > maxLength");
}
}
}
// Check numeric constraints
if (property.getIsNumber()) {
if (property.getMinimum() != null && property.getMaximum() != null) {
try {
double min = Double.parseDouble(property.getMinimum());
double max = Double.parseDouble(property.getMaximum());
if (min > max) {
throw new SpecValidationException(
"Property " + property.name + " has minimum > maximum");
}
} catch (NumberFormatException e) {
throw new SpecValidationException(
"Invalid numeric constraint for property " + property.name, e);
}
}
}
// Check array constraints
if (property.getIsArray()) {
if (property.getMinItems() != null && property.getMaxItems() != null) {
if (property.getMinItems() > property.getMaxItems()) {
throw new SpecValidationException(
"Property " + property.name + " has minItems > maxItems");
}
}
}
}
}public class TypeAwareGenerator extends DefaultCodegen {
@Override
public CodegenProperty fromProperty(String name, Schema propertySchema) {
CodegenProperty property = super.fromProperty(name, propertySchema);
// Add type-specific processing
if (property.getIsString()) {
processStringProperty(property);
} else if (property.getIsNumber()) {
processNumericProperty(property);
} else if (property.getIsArray()) {
processArrayProperty(property);
} else if (property.getIsMap()) {
processMapProperty(property);
} else if (property.getIsModel()) {
processModelProperty(property);
}
return property;
}
private void processStringProperty(CodegenProperty property) {
// Add string-specific validation and formatting
if (property.getPattern() != null) {
property.vendorExtensions.put("x-pattern-validation", true);
}
if (property.getMinLength() != null || property.getMaxLength() != null) {
property.vendorExtensions.put("x-length-validation", true);
}
// Check for specific formats
if ("email".equals(property.dataFormat)) {
property.vendorExtensions.put("x-email-validation", true);
} else if ("uuid".equals(property.dataFormat)) {
property.vendorExtensions.put("x-uuid-format", true);
}
}
private void processNumericProperty(CodegenProperty property) {
// Add numeric validation
if (property.getMinimum() != null || property.getMaximum() != null) {
property.vendorExtensions.put("x-range-validation", true);
}
if (property.getMultipleOf() != null) {
property.vendorExtensions.put("x-multiple-validation", true);
}
// Check for exclusive bounds
if (property.getExclusiveMinimum() || property.getExclusiveMaximum()) {
property.vendorExtensions.put("x-exclusive-bounds", true);
}
}
private void processArrayProperty(CodegenProperty property) {
// Process array constraints
if (property.getMinItems() != null || property.getMaxItems() != null) {
property.vendorExtensions.put("x-array-size-validation", true);
}
if (property.getUniqueItems()) {
property.vendorExtensions.put("x-unique-items", true);
}
// Process array item type
if (property.getItems() != null) {
CodegenProperty items = property.getItems();
property.vendorExtensions.put("x-item-type", items.dataType);
}
}
}public class SchemaAnalyzer {
public void analyzeOpenAPISpec(OpenAPI openAPI) {
// Find all used schemas
List<String> usedSchemas = ModelUtils.getAllUsedSchemas(openAPI);
System.out.println("Used schemas: " + usedSchemas);
// Find unused schemas
List<String> unusedSchemas = ModelUtils.getUnusedSchemas(openAPI);
if (!unusedSchemas.isEmpty()) {
System.out.println("Warning: Unused schemas found: " + unusedSchemas);
}
// Analyze schemas by type
Map<String, Schema> schemas = openAPI.getComponents().getSchemas();
for (Map.Entry<String, Schema> entry : schemas.entrySet()) {
String name = entry.getKey();
Schema schema = entry.getValue();
analyzeSchema(name, schema);
}
}
private void analyzeSchema(String name, Schema schema) {
System.out.println("Analyzing schema: " + name);
if (ModelUtils.isObjectSchema(schema)) {
System.out.println(" Type: Object");
analyzeObjectSchema(schema);
} else if (ModelUtils.isArraySchema(schema)) {
System.out.println(" Type: Array");
analyzeArraySchema(schema);
} else if (ModelUtils.isStringSchema(schema)) {
System.out.println(" Type: String");
analyzeStringSchema(schema);
} else if (ModelUtils.isNumberSchema(schema)) {
System.out.println(" Type: Number");
analyzeNumericSchema(schema);
} else if (ModelUtils.isComposedSchema(schema)) {
System.out.println(" Type: Composed (oneOf/anyOf/allOf)");
analyzeComposedSchema(schema);
}
}
private void analyzeObjectSchema(Schema schema) {
Map<String, Schema> properties = schema.getProperties();
if (properties != null) {
System.out.println(" Properties: " + properties.keySet());
}
List<String> required = schema.getRequired();
if (required != null && !required.isEmpty()) {
System.out.println(" Required: " + required);
}
}
private void analyzeStringSchema(Schema schema) {
if (schema.getFormat() != null) {
System.out.println(" Format: " + schema.getFormat());
}
if (schema.getPattern() != null) {
System.out.println(" Pattern: " + schema.getPattern());
}
if (schema.getMinLength() != null) {
System.out.println(" MinLength: " + schema.getMinLength());
}
if (schema.getMaxLength() != null) {
System.out.println(" MaxLength: " + schema.getMaxLength());
}
}
}public class SafeGenerator extends DefaultGenerator {
@Override
public List<File> generate() {
try {
return super.generate();
} catch (SpecValidationException e) {
System.err.println("Specification validation failed:");
// Print validation errors
if (e.getErrors() != null && !e.getErrors().isEmpty()) {
System.err.println("Errors:");
for (String error : e.getErrors()) {
System.err.println(" - " + error);
}
}
// Print validation warnings
if (e.getWarnings() != null && !e.getWarnings().isEmpty()) {
System.err.println("Warnings:");
for (String warning : e.getWarnings()) {
System.err.println(" - " + warning);
}
}
throw e; // Re-throw to stop generation
} catch (GeneratorNotFoundException e) {
System.err.println("Generator not found: " + e.getMessage());
System.err.println("Available generators: " + getAvailableGenerators());
throw e;
}
}
private List<String> getAvailableGenerators() {
// Return list of available generator names
return Arrays.asList("java", "python", "javascript", "typescript", "go", "ruby");
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-openapitools--openapi-generator