Java Code Generation Engine (JCGE) is a Maven plugin designed to automatically generate Entity or DTO classes from YAML/JSON files. This plugin simplifies the process of creating model classes required for Java applications, reducing time and coding errors.
- Features
- Installation
- Usage
- YAML File Examples
- Generating Classes
- Caveat
- Development Setup
- Future Implementations
- Requirements
- Contributing
- License
- Authors
- Repository
- Automatic generation of Entity or DTO classes from YAML/JSON files including:
- Fields
- NoArgsConstructor
- Getters
- Setters
- Builder
- Equals
- HashCode
- ToString
- Class Level Annotations
- Field Level Annotations
- Class Level Description
- Field Level Description
- Support for all Java types
- Support for Custom Types
To include JCGE in your Maven project, add the following plugin section to your pom.xml
file:
<build>
<plugins>
<plugin>
<groupId>io.github.robertomanfreda</groupId>
<artifactId>jcge-maven-plugin</artifactId>
<version>1.0.1-SNAPSHOT</version>
</plugin>
</plugins>
</build>
Depending on what you use, you need to import the appropriate dependencies:
- If you use Jakarta for validation and persistence, then you should import:
<dependencies>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
</dependencies>
- If you use javax for validation and persistence, then you should import:
<dependencies>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
</dependencies>
- If you use Jackson, then you should import:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
You can configure the plugin to load local or remote YAML/JSON files.
- For local configuration, you can specify single files:
<configuration>
<localFiles>
<file>${project.basedir}/src/main/resources/dto/student.yaml</file>
<file>${project.basedir}/src/main/resources/entity/student.yaml</file>
<file>${project.basedir}/src/main/resources/dto/person.yaml</file>
</localFiles>
</configuration>
or entire folders:
<configuration>
<localFolders>
<folder>${project.basedir}/src/main/resources/dto</folder>
<folder>${project.basedir}/src/main/resources/entity</folder>
</localFolders>
</configuration>
- For remote configuration, you can specify single files:
<configuration>
<remoteFiles>
<file>https://raw.githubusercontent.com/username/repo-name/branch-name/dto/student.yaml</file>
<file>https://raw.githubusercontent.com/username/repo-name/branch-name/entity/student.yaml</file>
<file>https://raw.githubusercontent.com/username/repo-name/branch-name/dto/person.yaml</file>
</remoteFiles>
</configuration>
or entire remote folders:
<configuration>
<remoteFolders>
<folder>https://raw.githubusercontent.com/username/repo-name/branch-name/dto</folder>
<folder>https://raw.githubusercontent.com/username/repo-name/branch-name/entity</folder>
</remoteFolders>
</configuration>
- A DTO with a field including a Custom type (TestClass), using jakarta imports (you need to specify the
package
and it must be in the classpath):
---
title: StudentCustom
version: jakarta
description: The StudentCustom class with a field including a Custom type
generationType: dto
properties:
id:
type: Integer
description: The unique identifier for a student
firstName:
type: String
description: The first name of the student
lastName:
type: String
description: The last name of the student
testClass:
type: TestClass
package: io.github.robertomanfreda.jcge.utils
description: A Custom TestClass type
- A DTO with Jackson annotations, using jakarta imports:
---
title: StudentDTO
version: jakarta
description: The StudentDTO class with various properties and Jackson annotations
generationType: dto
jackson:
- JsonIgnoreProperties({"password", "name", "foo", "ssn"})
- JsonInclude(JsonInclude.Include.NON_NULL)
- JsonPropertyOrder({"id", "firstName", "lastName", "email", "dateOfBirth", "enrolledCourses", "address", "phoneNumber", "gender", "nationality", "emergencyContact", "listListIds", "mapField"})
properties:
id:
type: Integer
description: The unique identifier for a student
firstName:
type: String
description: The first name of the student
jackson:
- JsonProperty("user_name")
lastName:
type: String
description: The last name of the student
email:
type: String
description: The email address of the student
password:
type: String
description: The password for the student account
jackson:
- JsonIgnore
ssn:
type: String
description: The social security number of the student
jackson:
- JsonIgnore
dateOfBirth:
type: Date
description: The date of birth of the student
gender:
type: String
description: The gender of the student
nationality:
type: String
description: The nationality of the student
address:
type: String
description: The address of the student
phoneNumber:
type: String
description: The phone number of the student
emergencyContact:
type: String
description: The emergency contact for the student
enrolledCourses:
type: List<Integer>
description: A list of courses the student is enrolled in
listListIds:
type: List<List<Integer>>
description: A list of lists of IDs
mapField:
type: Map<String, List<Integer>>
description: A map with String keys and List<Integer> values
grades:
type: Map<String, Double>
description: A map of course names to grades
attendanceRecord:
type: Map<Date, Boolean>
description: A record of attendance with dates and presence status
extracurricularActivities:
type: List<String>
description: A list of extracurricular activities the student is involved in
notes:
type: List<String>
description: Additional notes about the student
metadata:
type: Map<String, String>
description: Additional metadata for the student
createdAt:
type: Date
description: The creation timestamp of the student record
jackson:
- JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
updatedAt:
type: Date
description: The last updated timestamp of the student record
jackson:
- JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
- A DTO with JSR-303 annotations, using javax imports:
---
title: StudentDTO
version: javax
description: The StudentDTOJsr303 class with various properties and JSR303 annotations
generationType: dto
properties:
id:
type: Integer
description: The unique identifier for a student
jsr303:
- NotNull
firstName:
type: String
description: The first name of the student
jsr303:
- NotBlank
- Size(min = 1, max = 50)
lastName:
type: String
description: The last name of the student
jsr303:
- NotBlank
- Size(min = 1, max = 50)
email:
type: String
description: The email address of the student
jsr303:
- NotBlank
- Email
password:
type: String
description: The password for the student account
jsr303:
- NotBlank
- Size(min = 8, max = 100)
ssn:
type: String
description: The social security number of the student
jsr303:
- Pattern(regexp = "^(?!000|666)[0-8][0-9]{2}-[0-9]{2}-[0-9]{4}$")
dateOfBirth:
type: Date
description: The date of birth of the student
jsr303:
- NotNull
- Past
gender:
type: String
description: The gender of the student
jsr303:
- NotBlank
- Pattern(regexp = "Male|Female|Other")
nationality:
type: String
description: The nationality of the student
jsr303:
- NotBlank
address:
type: String
description: The address of the student
jsr303:
- NotBlank
- Size(min = 10, max = 100)
phoneNumber:
type: String
description: The phone number of the student
jsr303:
- NotBlank
- Pattern(regexp = "^\\+?[0-9. ()-]{7,25}$")
emergencyContact:
type: String
description: The emergency contact for the student
jsr303:
- NotBlank
enrolledCourses:
type: List<Integer>
description: A list of courses the student is enrolled in
jsr303:
- NotNull
- Size(min = 1)
listListIds:
type: List<List<Integer>>
description: A list of lists of IDs
mapField:
type: Map<String, List<Integer>>
description: A map with String keys and List<Integer> values
grades:
type: Map<String, Double>
description: A map of course names to grades
jsr303:
- NotNull
attendanceRecord:
type: Map<Date, Boolean>
description: A record of attendance with dates and presence status
extracurricularActivities:
type: List<String>
description: A list of extracurricular activities the student is involved in
jsr303:
- Size(min = 0, max = 10)
notes:
type: List<String>
description: Additional notes about the student
jsr303:
- Size(max = 500)
metadata:
type: Map<String, String>
description: Additional metadata for the student
createdAt:
type: Date
description: The creation timestamp of the student record
updatedAt:
type: Date
description: The last updated timestamp of the student record
jsr303:
- PastOrPresent
- An entity with JPA annotations, using jakarta imports:
---
title: StudentEntity
version: jakarta
description: The Student entity class with various properties and JPA annotations
generationType: entity
jpa:
- Entity
- Table(name = "students")
properties:
id:
type: Integer
description: The unique identifier for a student
jpa:
- Id
- GeneratedValue(strategy = GenerationType.IDENTITY)
firstName:
type: String
description: The first name of the student
jpa:
- Column(name = "first_name", nullable = false, length = 50)
lastName:
type: String
description: The last name of the student
jpa:
- Column(name = "last_name", nullable = false, length = 50)
email:
type: String
description: The email address of the student
jpa:
- Column(nullable = false, unique = true)
password:
type: String
description: The password for the student account
ssn:
type: String
description: The social security number of the student
dateOfBirth:
type: Date
description: The date of birth of the student
jpa:
- Column(name = "date_of_birth", nullable = false)
gender:
type: String
description: The gender of the student
jpa:
- Column(nullable = false)
nationality:
type: String
description: The nationality of the student
jpa:
- Column(nullable = false)
address:
type: String
description: The address of the student
jpa:
- Column(nullable = false, length = 100)
phoneNumber:
type: String
description: The phone number of the student
jpa:
- Column(name = "phone_number", nullable = false, length = 25)
emergencyContact:
type: String
description: The emergency contact for the student
jpa:
- Column(name = "emergency_contact", nullable = false)
enrolledCourses:
type: List<Integer>
description: A list of courses the student is enrolled in
listListIds:
type: List<List<Integer>>
description: A list of lists of IDs
mapField:
type: Map<String, List<Integer>>
description: A map with String keys and List<Integer> values
grades:
type: Map<String, Double>
description: A map of course names to grades
attendanceRecord:
type: Map<Date, Boolean>
description: A record of attendance with dates and presence status
extracurricularActivities:
type: List<String>
description: A list of extracurricular activities the student is involved in
notes:
type: List<String>
description: Additional notes about the student
metadata:
type: Map<String, String>
description: Additional metadata for the student
createdAt:
type: Date
description: The creation timestamp of the student record
jpa:
- Column(name = "created_at", updatable = false)
updatedAt:
type: Date
description: The last updated timestamp of the student record
jpa:
- Column(name = "updated_at")
To generate classes from the YAML files you can run the following Maven command:
mvn clean com.robertomanfreda:jcge-maven-plugin:1.0.1-SNAPSHOT:generate
or using the short form
mvn jcge:generate
The plugin will process the files and generate the classes. If it encounters any errors during generation, it will
generally throw a RuntimeException
. In a future release, we will provide the option to configure whether the exception
should be blocking during compilation or not.
At the end of the generation process, the generated class will be located in one of the following directories, depending on the value of generationType:
- If
generationType
is set todto
, the class will be found intarget/generated-sources/jcge/dto
with the packagejcge.dto
. - If
generationType
is set toentity
, the class will be found intarget/generated-sources/jcge/entity
with the packagejcge.entity
.
Here is an example of a class generated from the JPA StudentEntity file above:
package jcge.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.io.Serializable;
import java.lang.Boolean;
import java.lang.Double;
import java.lang.Integer;
import java.lang.Object;
import java.lang.Override;
import java.lang.String;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* The Student entity class with various properties and JPA annotations
*/
@Entity
@Table(
name = "students"
)
public class StudentEntity implements Serializable {
/**
* The unique identifier for a student
*/
@Id
@GeneratedValue(
strategy = GenerationType.IDENTITY
)
private Integer id;
/**
* The first name of the student
*/
@Column(
name = "first_name",
nullable = false,
length = 50
)
private String firstName;
/**
* The last name of the student
*/
@Column(
name = "last_name",
nullable = false,
length = 50
)
private String lastName;
/**
* The email address of the student
*/
@Column(
nullable = false,
unique = true
)
private String email;
/**
* The password for the student account
*/
private String password;
/**
* The social security number of the student
*/
private String ssn;
/**
* The date of birth of the student
*/
@Column(
name = "date_of_birth",
nullable = false
)
private Date dateOfBirth;
/**
* The gender of the student
*/
@Column(
nullable = false
)
private String gender;
/**
* The nationality of the student
*/
@Column(
nullable = false
)
private String nationality;
/**
* The address of the student
*/
@Column(
nullable = false,
length = 100
)
private String address;
/**
* The phone number of the student
*/
@Column(
name = "phone_number",
nullable = false,
length = 25
)
private String phoneNumber;
/**
* The emergency contact for the student
*/
@Column(
name = "emergency_contact",
nullable = false
)
private String emergencyContact;
/**
* A list of courses the student is enrolled in
*/
private List<Integer> enrolledCourses;
/**
* A list of lists of IDs
*/
private List<List<Integer>> listListIds;
/**
* A map with String keys and List<Integer> values
*/
private Map<String, List<Integer>> mapField;
/**
* A map of course names to grades
*/
private Map<String, Double> grades;
/**
* A record of attendance with dates and presence status
*/
private Map<Date, Boolean> attendanceRecord;
/**
* A list of extracurricular activities the student is involved in
*/
private List<String> extracurricularActivities;
/**
* Additional notes about the student
*/
private List<String> notes;
/**
* Additional metadata for the student
*/
private Map<String, String> metadata;
/**
* The creation timestamp of the student record
*/
@Column(
name = "created_at",
updatable = false
)
private Date createdAt;
/**
* The last updated timestamp of the student record
*/
@Column(
name = "updated_at"
)
private Date updatedAt;
public StudentEntity() {
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
StudentEntity that = (StudentEntity) o;
return Objects.equals(this.id, that.id) &&
Objects.equals(this.firstName, that.firstName) &&
Objects.equals(this.lastName, that.lastName) &&
Objects.equals(this.email, that.email) &&
Objects.equals(this.password, that.password) &&
Objects.equals(this.ssn, that.ssn) &&
Objects.equals(this.dateOfBirth, that.dateOfBirth) &&
Objects.equals(this.gender, that.gender) &&
Objects.equals(this.nationality, that.nationality) &&
Objects.equals(this.address, that.address) &&
Objects.equals(this.phoneNumber, that.phoneNumber) &&
Objects.equals(this.emergencyContact, that.emergencyContact) &&
Objects.equals(this.enrolledCourses, that.enrolledCourses) &&
Objects.equals(this.listListIds, that.listListIds) &&
Objects.equals(this.mapField, that.mapField) &&
Objects.equals(this.grades, that.grades) &&
Objects.equals(this.attendanceRecord, that.attendanceRecord) &&
Objects.equals(this.extracurricularActivities, that.extracurricularActivities) &&
Objects.equals(this.notes, that.notes) &&
Objects.equals(this.metadata, that.metadata) &&
Objects.equals(this.createdAt, that.createdAt) &&
Objects.equals(this.updatedAt, that.updatedAt);
}
@Override
public int hashCode() {
return Objects.hash(id, firstName, lastName, email, password, ssn, dateOfBirth, gender, nationality, address, phoneNumber, emergencyContact, enrolledCourses, listListIds, mapField, grades, attendanceRecord, extracurricularActivities, notes, metadata, createdAt, updatedAt);
}
@Override
public String toString() {
return "StudentEntity{" +
"id='" + id + '\'' + ", " +
"firstName='" + firstName + '\'' + ", " +
"lastName='" + lastName + '\'' + ", " +
"email='" + email + '\'' + ", " +
"password='" + password + '\'' + ", " +
"ssn='" + ssn + '\'' + ", " +
"dateOfBirth='" + dateOfBirth + '\'' + ", " +
"gender='" + gender + '\'' + ", " +
"nationality='" + nationality + '\'' + ", " +
"address='" + address + '\'' + ", " +
"phoneNumber='" + phoneNumber + '\'' + ", " +
"emergencyContact='" + emergencyContact + '\'' + ", " +
"enrolledCourses='" + enrolledCourses + '\'' + ", " +
"listListIds='" + listListIds + '\'' + ", " +
"mapField='" + mapField + '\'' + ", " +
"grades='" + grades + '\'' + ", " +
"attendanceRecord='" + attendanceRecord + '\'' + ", " +
"extracurricularActivities='" + extracurricularActivities + '\'' + ", " +
"notes='" + notes + '\'' + ", " +
"metadata='" + metadata + '\'' + ", " +
"createdAt='" + createdAt + '\'' + ", " +
"updatedAt='" + updatedAt + '\'' + "}";
}
// Getters (Omitted for brevity)
// Setters (Omitted for brevity)
public static class Builder {
private Integer id;
private String firstName;
private String lastName;
private String email;
private String password;
private String ssn;
private Date dateOfBirth;
private String gender;
private String nationality;
private String address;
private String phoneNumber;
private String emergencyContact;
private List<Integer> enrolledCourses;
private List<List<Integer>> listListIds;
private Map<String, List<Integer>> mapField;
private Map<String, Double> grades;
private Map<Date, Boolean> attendanceRecord;
private List<String> extracurricularActivities;
private List<String> notes;
private Map<String, String> metadata;
private Date createdAt;
private Date updatedAt;
public Builder id(Integer id) {
this.id = id;
return this;
}
public Builder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder password(String password) {
this.password = password;
return this;
}
public Builder ssn(String ssn) {
this.ssn = ssn;
return this;
}
public Builder dateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Builder nationality(String nationality) {
this.nationality = nationality;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public Builder emergencyContact(String emergencyContact) {
this.emergencyContact = emergencyContact;
return this;
}
public Builder enrolledCourses(List<Integer> enrolledCourses) {
this.enrolledCourses = enrolledCourses;
return this;
}
public Builder listListIds(List<List<Integer>> listListIds) {
this.listListIds = listListIds;
return this;
}
public Builder mapField(Map<String, List<Integer>> mapField) {
this.mapField = mapField;
return this;
}
public Builder grades(Map<String, Double> grades) {
this.grades = grades;
return this;
}
public Builder attendanceRecord(Map<Date, Boolean> attendanceRecord) {
this.attendanceRecord = attendanceRecord;
return this;
}
public Builder extracurricularActivities(List<String> extracurricularActivities) {
this.extracurricularActivities = extracurricularActivities;
return this;
}
public Builder notes(List<String> notes) {
this.notes = notes;
return this;
}
public Builder metadata(Map<String, String> metadata) {
this.metadata = metadata;
return this;
}
public Builder createdAt(Date createdAt) {
this.createdAt = createdAt;
return this;
}
public Builder updatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
return this;
}
public StudentEntity build() {
StudentEntity instance = new StudentEntity();
instance.id = this.id;
instance.firstName = this.firstName;
instance.lastName = this.lastName;
instance.email = this.email;
instance.password = this.password;
instance.ssn = this.ssn;
instance.dateOfBirth = this.dateOfBirth;
instance.gender = this.gender;
instance.nationality = this.nationality;
instance.address = this.address;
instance.phoneNumber = this.phoneNumber;
instance.emergencyContact = this.emergencyContact;
instance.enrolledCourses = this.enrolledCourses;
instance.listListIds = this.listListIds;
instance.mapField = this.mapField;
instance.grades = this.grades;
instance.attendanceRecord = this.attendanceRecord;
instance.extracurricularActivities = this.extracurricularActivities;
instance.notes = this.notes;
instance.metadata = this.metadata;
instance.createdAt = this.createdAt;
instance.updatedAt = this.updatedAt;
return instance;
}
}
}
The plugin is currently in an early stage and has not been officially released yet. It is still under active development.
At this moment to use the plugin, you need to clone the project from the main branch and compile it locally. Follow these steps:
- Clone the repository:
git clone https://github.com/robertomanfreda/java-code-generation-engine.git
- Navigate to the project directory:
cd java-code-generation-engine
- Compile and install the plugin locally:
mvn clean install
After these steps, you can use the plugin in your Maven projects as reported in the Generating Classes section.
- Automated release via GitHub CI/CD
- Support for authentication for remote downloads: Implement authentication mechanisms for downloading protected remote files.
- Support for MapStruct: Automate the generation of mappers for converting entities to DTOs and vice versa using MapStruct. Generation of unit tests: Automate the generation of unit tests for the generated classes.
- Support for Swagger/OpenAPI: Generate DTOs from Swagger/OpenAPI specifications.
- Customizable configuration: Allow greater customization of plugin configurations through advanced parameters.
- Support for other serialization libraries: In addition to Jackson, add support for other serialization/deserialization libraries like Gson or JSON-B.
- Support for advanced validation models: Integrate more advanced and customizable validation models.
- Integration with CI/CD tools: Facilitate integration with continuous integration and continuous deployment (CI/CD) tools to further automate the code generation process.
- Java 11 or higher
- Maven 3.6.3 or higher
Contributions are welcome! Please fork the repository and submit a pull request with your changes. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (git checkout -b feature/YourFeature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin feature/YourFeature)
- Create a new Pull Request
This project is licensed under the GNU General Public License (GPL) version 3 - see the LICENSE file for details.
- Roberto Manfreda
The source code for JCGE can be found at: GitHub Repository