Introduction to Extension Architecture
SpringBootCodeGenerator is a robust utility built on Spring Boot 2 and Freemarker, designed to automate Java code creation from database schemas or structured data. While it supports standard inputs like MySQL, Oracle, and PostgreSQL DDL, complex projects often require custom data ingestion methods or specific framework outputs. This guide details the architectural steps required to integrate custom parsing logic and new template definitions into the generation pipeline.
Implementing Custom Data Parsers
The core responsibility of a parser within this system is to transform raw enput sources into a standardized metadata object used by the templating engine. The system currently supports SQL and JSON inputs via dedicated service interfaces. To introduce support for additional formats, developers must adhere to the defined service contract.
Defining the Parser Interface
New parsing strategies should be defined within the com.softdev.system.generator.service.parser package. Instead of directly coupling to specific file types, consider defining a generic ingestion contract. For example, a YAML-based parser interface might look like this:
public interface DataIngestionStrategy {
EntityDefinition ingest(SourcePayload payload);
}
The EntityDefinition object serves as the canonical model containing table structuers, field types, and relationships, ensuring compatibility with existing templates.
Developing the Implementation Logic
Implementation classes reside in com.softdev.system.generator.service.impl.parser. When building the logic, focus on the following requirements:
- Input Handling: Accept the
SourcePayloadwhich encapsulates raw text or file streams. - Type Mapping: Utilize existing utility classes, such as
mysqlJavaTypeUtil.java, to ensure database types are correctly converted to Java types. - Error Management: Throw specific runtime exceptions, such as
GenerationFailureException, when input data is malformed.
Below is a simplified example of how the ingestion logic might be structured:
@Service
public class YamlStructureParser implements DataIngestionStrategy {
@Override
public EntityDefinition ingest(SourcePayload payload) {
// Parse YAML content
YamlNode root = parseYaml(payload.getContent());
// Map to internal entity model
EntityDefinition model = new EntityDefinition();
model.setNamespace(extractPackage(root));
model.setFields(mapFields(root.getChildren()));
return model;
}
}
Registering the Parser
To make the new parser available to the generation engine, it must be wired into the main orchestration service. Modify the GenerationOrchestrator.java (formerly CodeGenServiceImpl) to include the new strategy. Use dependency injection to load the service and implement a routing mechanism based on the input source type.
@Autowired
private DataIngestionStrategy yamlParser;
public void executeGeneration(GenerationRequest request) {
EntityDefinition metadata;
if (request.getType() == InputType.YAML) {
metadata = yamlParser.ingest(request.getPayload());
} else {
// Default handling
}
// Proceed to template rendering
}
Customizing Freemarker Templates
The output generation relies on Freemarker templates stored in the resources directory. The template service, defined by TemplateService, manages the loading and processing of these files.
Creating Template Files
New templates should follow the naming convention {framework}-{component}.ftl. For instance, to generate OpenAPI specifications, you might create openapi-spec.ftl. Place this file in the designated templates folder within the classpath.
Configuring Template Metadata
Each template must be registered in the configuration JSON so it apears in the user interface. Add an entry describing the template's purpose and identifier:
{
"id": "22",
"key": "openapi-spec",
"label": "OpenAPI Specification Definition",
"category": "documentation"
}
Utilizing Template Variables
Templates access the metadata generated by the parsers. Key variables available during rendering include:
${metadata}: Contains namespace, entity name, and imports.${columns}: A list of field objects with types and comments.${tableName}: The source database table identifier.
A basic entity class template might utilize these variables as follows:
package ${metadata.namespace};
public class ${metadata.entityName} {
<#list columns as col>
private ${col.javaType} ${col.fieldName};
#list>
}
Development Best Practices
Project Structure
Maintain separation of concerns by adhering to the standard package layout:
- Interfaces:
com.softdev.system.generator.service.parser - Implementations:
com.softdev.system.generator.service.impl.parser - Utilities:
com.softdev.system.generator.util - DTOs:
com.softdev.system.generator.entity.dto
Testing and Validation
Every new parser or template should be covered by unit tests. Mimic the structure of existing test suites like SqlParserServiceTest.java. Ensure that edge cases, such as null values or unexpected data types, are handled gracefully during parsing.
Performance Considerations
For high-volume generation tasks, consider the following optimizations:
- Implement caching for frequently used parsing results using tools like
MapUtil. - Pre-compile Freemarker configurations to reduce rendering overhead.
- Process large datasets in batches to prevent memory overflow.
Integration Workflow
To fully integrate a new capability, such as an XML parser paired with a Swagger documentation template, follow this sequence:
- Define the
XmlParserStrategyinterface. - Implement the parsing logic in
XmlStructureParser. - Create the
swagger-doc.ftltemplate file. - Update the template configuration JSON with the new entry.
- Wire the parser into the
GenerationOrchestrator. - Validate functionality via
XmlParserStrategyTest.
Once completed, the new options will appear in the generation configuration interface, allowing users to select the custom template and input format for their projects.