Flexible DTO Java classes generator that creates advanced DTO classes from database metadata with extensive customization options.
- 🏗️ Database-driven: Generate DTOs directly from database schema metadata
- 🔧 Highly Customizable: Extensive configuration options for fields, types, and behavior
- 📝 Template-based: Uses Pebble templates with support for custom templates
- 🔌 Plugin System: Extensible plugin architecture for database-specific handling
- 📊 Change Tracking: Built-in field change tracking capabilities
- 🎯 Multiple Templates: Standard DTOs and Panache entity support
- 🏭 Build Integration: Gradle and Maven integration support
- 📦 Auto-compilation: Optional compilation and JAR creation
- Create configuration file
db2dto.conf:
{
"dbURL": "jdbc:postgresql://localhost/mydb",
"dbUser": "username",
"dbPassword": "password",
"dbSchema": "public",
"sourceOutputDir": "./generated",
"common": {
"packageName": "com.example.dto",
"classSuffix": "Data"
}
}- Run the generator:
java -jar db2dto-1.20.0.jar -c db2dto.conf- Use generated DTOs:
UserData user = new UserData()
.setName("John Doe")
.setEmail("[email protected]");
// Check if field changed
if (user.isNameChanged()) {
// Handle change
}<dependency>
<groupId>dev.walgo</groupId>
<artifactId>db2dto</artifactId>
<version>1.20.0</version>
</dependency>implementation 'dev.walgo:db2dto:1.20.0'Download the latest JAR from Maven Central or build from source.
{
"dbURL": "jdbc:postgresql://localhost/mydb",
"dbUser": "username",
"dbPassword": "password",
"dbSchema": "public",
"templateDir": "templates",
"sourceOutputDir": "./generated",
"baseInterfaceName": "IData",
"compile": true,
"classOutputDir": "build/classes",
"jarPath": "build/myapp-dto.jar"
}Configure common settings for all generated classes:
{
"common": {
"classPrefix": "",
"classSuffix": "Data",
"packageName": "com.example.dto",
"columnsOrder": "TABLE",
"useDefaults": true,
"readOnlyFields": ["created_at", "updated_at"]
}
}Options:
classPrefix/classSuffix: Add prefix/suffix to generated class namespackageName: Java package for generated classescolumnsOrder: generate columns in this order:ALPHA: columns sorted by nameTABLE: order as in table
useDefaults: Use database default values as field initializersreadOnlyFields: Fields without setters (global)
Override default SQL-to-Java type mappings:
{
"sqlTypes": {
"cidr": "String",
"_cidr": "String[]",
"_text": "List<String>",
"jsonb": "JsonNode"
}
}Customize individual tables:
{
"tables": {
"users": {
"packageName": "com.example.dto.user",
"interfaces": ["com.example.Auditable"],
"fieldNames": {
"usr_name": "username"
},
"additionalFields": {
"fullName": "String",
"roles": "Set<String>",
"metadata": "Map<String, Object>"
},
"enumFields": {
"status": "com.example.UserStatus"
},
"fieldTypes": {
"preferences": "com.example.UserPreferences"
},
"fieldDefaults": {
"roles": "new HashSet<>()",
"createdAt": "Instant.now()"
},
"readOnlyFields": ["id", "created_at"],
"toStringIgnoreFields": ["password_hash"]
}
}
}Table Options:
interfaces: Implement additional interfacesfieldNames: Rename fields from database column namesadditionalFields: Add fields not in database, it could be:- simple types: int, boolean, etc
- object types: Integer, String, etc
- collections: Map, List and Set
- complex types - any compile-time reachable from this class, with full package name, e.g: other.package.BeanClass
enumFields: Map columns to enum typesfieldTypes: Override field typesfieldDefaults: Set default values for fieldsreadOnlyFields: Fields without setters (table-specific)toStringIgnoreFields: Exclude fields from toString()
# Use configuration file
java -jar db2dto-1.20.0.jar -c myconfig.conf
# Override connection settings
java -jar db2dto-1.20.0.jar -c myconfig.conf \
--url jdbc:postgresql://localhost/mydb \
--user myuser \
--password mypass \
--schema publicCommand Line Options:
-c, --config <file>: Configuration file (default: db2dto.conf)-d, --url <url>: Database connection string-u, --user <user>: Database username-p, --password <pass>: Database password-s, --schema <schema>: Database schema-h: Show help
task generateDto(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'dev.walgo.db2dto.Main'
args '--config', 'db2dto.conf'
}
// Or programmatically
task generateDto() {
doLast {
File configFile = new File('db2dto.conf')
com.google.gson.Gson gson = new com.google.gson.Gson()
def config = gson.fromJson(configFile.text, dev.walgo.db2dto.config.Config.class)
// Override settings
config.dbURL = 'jdbc:postgresql://localhost/mydb'
config.dbUser = project.findProperty('dbUser') ?: 'defaultUser'
config.dbPassword = project.findProperty('dbPassword') ?: 'defaultPass'
def processor = new dev.walgo.db2dto.Processor()
processor.setConfig(config)
processor.execute()
}
}<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>generate-dto</id>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>dev.walgo.db2dto.Main</mainClass>
<arguments>
<argument>--config</argument>
<argument>db2dto.conf</argument>
</arguments>
</configuration>
</plugin>Every generated DTO implements the IData interface with change tracking:
public interface IData {
boolean hasChangedField(String fieldName);
boolean isChanged();
void resetChangedField(String fieldName);
void resetChanged();
Set<String> getFieldNames();
}Generated setters only mark fields as changed when values actually differ:
public UserData setName(String newValue) {
if (!Objects.equals(newValue, this.name)) {
this.name = newValue;
changedFields.add("name");
}
return this;
}
// Non-null setter variant
public UserData setNameNotNull(String newValue) {
if (!Objects.equals(newValue, this.name) && newValue != null) {
this.name = newValue;
changedFields.add("name");
}
return this;
}Each field gets individual change tracking methods:
// Mark field as changed
public UserData setNameChanged() {
changedFields.add("name");
return this;
}
// Check if field changed
public boolean isNameChanged() {
return changedFields.contains("name");
}DB2DTO uses Pebble templates for code generation. Built-in templates:
class.tpl: Standard DTO classesinterface.tpl: Interface generationpanache/class.tpl: Quarkus Panache entities
Create custom templates in your template directory:
package {{ packageName }};
{% for import in imports %}
import {{ import }};
{% endfor %}
public class {{ className }} {{ extendsClause }}{{ implementsClause }} {
{% for field in fields %}
private {{ field.type }} {{ field.name }}{{ field.defaultValue }};
{% endfor %}
// Your custom template content
}
Extend DB2DTO with custom plugins for database-specific handling:
public class CustomPlugin implements IPlugin {
@Override
public String convertType(String sqlType, int length, int scale) {
// Custom type conversion logic
return "CustomType";
}
}Register plugins in configuration:
{
"pluginPackages": ["com.example.plugins"]
}DB2DTO works with any JDBC-compliant database. Tested with:
- ✅ PostgreSQL
- ✅ HSQLDB
- ✅ MySQL/MariaDB
- ✅ Oracle
- ✅ SQL Server
- ✅ H2
git clone https://github.com/wwalery/db2dto.git
cd db2dto
./gradlew build./gradlew test./gradlew shadowJar
# Creates db2dto-{version}.jar in build/libs/See the examples/ directory for:
- Sample configuration files
- Database schemas
- Generated code examples
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
See ChangeLog.md for version history and changes.
Licensed under the Apache License, Version 2.0. See LICENSE file for details.
Walery Wysotsky - [email protected]
⭐ Star this repo if you find it useful!