This demo shows how you can extend your data entities to auto-generate Grids and Forms.
Based on:
- Spring Boot 3.4.1
- Vaadin Flow 24.6.0
- JDK21
- Added Vaadin Component-Column example to GenericGrid for Boolean values of entity properties und methods.
- Added Spring Boot Starter Validation to enable Form validation.
Use this annotation to let the GenericView auto-render your Grid. Use the annotaion properties to configure the behavior of each column.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface GridColumn {
String header() default "";
int order() default 999;
boolean sortable() default true;
String dateTimeFormat() default "";
boolean showAsComponent() default false;
}Use this annotation to define, which Entity.Property will show up to edit and how it behaves.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FormField {
String label() default "";
int order() default 999;
boolean required() default false;
}This demo provides two entity types:
- Person
- Address
@@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person implements BaseEntity {
@GridColumn(header = "ID", order = 0)
private Long personId;
@NotBlank(message = "First name is required")
@Size(min = 2, max = 50, message = "First name must be between 2 and 50 characters")
@GridColumn(header = "First Name", order = 1)
@FormField(label = "First Name", required = true, order = 1)
private String firstName;
@NotBlank(message = "Last name is required")
@Size(min = 2, max = 50, message = "Last name must be between 2 and 50 characters")
@GridColumn(header = "Last Name", order = 2)
@FormField(label = "Last Name", required = true, order = 2)
private String lastName;
@NotBlank(message = "Email is required")
@GridColumn(header = "Email", order = 3, sortable = false)
@FormField(label = "Email", required = true, order = 3)
private String email;
@GridColumn(header = "Is Active", order = 4)
@FormField(label = "Is Active", required = true, order = 4)
private Boolean isActive;
@GridColumn(header = "Birthday", order = 6, dateTimeFormat = "dd.MM.yyyy")
@FormField(label = "Birthday", required = true)
private LocalDate birthday;
@GridColumn(header = "Active Component", order = 5, showAsComponent = true)
public Boolean exampleBoolean(){
return isActive; // Just for demonstration purpose Component
}
@GridColumn(header = "Age", order = 6)
public int getAge() {
if (birthday == null) return 0;
return Period.between(birthday.atStartOfDay().toLocalDate(), LocalDate.now()).getYears();
}
}This view demonstrates how to bootstrap components or views using autogenerated Grids and Forms.
@PageTitle("PERSONS")
@Menu(order = 0, icon = "line-awesome/svg/home-solid.svg")
@Route(value = "", layout = MainLayout.class)
public class PersonView extends GenericView<Person> {
private final DataService dataService;
public PersonView(DataService dataService) {
super(Person.class);
this.dataService = dataService;
refreshGrid();
// Add Button for adding new person
Div addButton = new Div();
addButton.setClassName("circle-button-container");
Avatar addAvatar = new Avatar("+");
addAvatar.addClassName("circle-button");
addButton.add(addAvatar);
addButton.addClickListener(event -> addNew());
gridContainer.addComponentAsFirst(addButton);
}
@Override
protected void saveEntity(Person entity) {
dataService.savePerson(entity);
}
@Override
protected List<Person> loadEntities() {
return dataService.findAllPersons();
}
@Override
protected void deleteEntity(Person person) {
dataService.deletePerson(person);
}
}The GenericView is a type-safe, annotation-driven generic CRUD (Create, Read, Update, Delete) implementation for Vaadin applications that automatically generates Grid views and edit forms based on entity definitions. It minimizes boilerplate code while maintaining flexibility and extensibility.
- Automatic Grid column generation including ComponentColumns
- Automatic form field generation
- Support for computed/derived properties
- DateTime formatting capabilities
- Type-safe data binding
- Customizable layouts with split view
- Support for validation
-
Java Reflection API
- Dynamic field and method discovery
- Runtime annotation processing
- Dynamic property access and invocation
- Type introspection for appropriate component selection
-
Custom Annotations
@GridColumn: Configures grid column properties and formatting@FormField: Defines form field properties and validation- Runtime retention for dynamic processing
-
Vaadin Components
- Grid: Data display
- FormLayout: Edit form generation
- Binder: Type-safe data binding
- SplitLayout: Responsive layout management
-
Design Patterns
- Generic Type Pattern: Type-safe implementation using
<T extends BaseEntity> - Builder Pattern: Component construction
- Strategy Pattern: Field type handling
- Observer Pattern: Selection and update handling
- Generic Type Pattern: Type-safe implementation using
-
Presentation Layer
- Grid display
- Form rendering
- Layout management
-
Data Binding Layer
- Automatic binding setup
- Type conversion
- Validation rules
-
Metadata Layer
- Annotation processing
- Field discovery
- Configuration management
- Custom field type handling
- Custom component creation
- Validation rules
- Layout customization
- Formatting options
-
Reduced Boilerplate
- Automatic UI generation
- Convention over configuration
- Annotation-based configuration
-
Type Safety
- Compile-time type checking
- Type-safe data binding
- Protected against runtime type errors
-
Maintainability
- Centralized CRUD logic
- Consistent UI behavior
- Reusable components
-
Flexibility
- Customizable through annotations
- Extensible for new types
- Override capabilities
- Always implement BaseEntity interface
- Use meaningful order values in annotations
- Implement proper validation in save methods
- Consider caching for computed properties
- Handle exceptions appropriately
- Reflection usage is minimal and mostly during initialization
- Computed properties are calculated on-demand
- Grid uses lazy loading by default
- Form fields are created only when needed
- Reflection access is contained within the view
- Field access is controlled through annotations
- Input validation should be implemented in service layer
- Additional annotation features
- Custom validation rules
- Advanced filtering capabilities
- Extended formatting options
- Custom component integration



