Skip to content

Full control with CrudOrchestrator

CrudOrchestrator is the most flexible CRUD base class in Mateu. It lets you define a separate type for every screen — filters, grid rows, read-only detail, edit form, and creation form — while the framework still handles all routing and navigation automatically.

Use it when AutoCrudOrchestrator<T> or FilteredAutoCrudOrchestrator<F,R> are not enough because different screens need genuinely different models.


public abstract class CrudOrchestrator<
View,
Editor extends CrudEditorForm<IdType>,
CreationForm extends CrudCreationForm<IdType>,
Filters,
Row,
IdType>
TypeMeaning
ViewThe object rendered in the read-only detail screen
EditorThe form shown in the edit screen — must implement CrudEditorForm<IdType>
CreationFormThe form shown in the create screen — must implement CrudCreationForm<IdType>
FiltersThe filter bar DTO
RowThe DTO shown as a grid row in the listing
IdTypeThe type of the entity identifier (usually String)

RouteScreen
/your-routeListing with filter bar
/your-route/:idRead-only detail (View)
/your-route/:id/editEdit form (Editor)
/your-route/newCreate form (CreationForm)

MethodReturn typePurpose
adapter()CrudAdapter<View,Editor,CreationForm,Filters,Row,IdType>The data layer that backs all operations
editorClass()Class<Editor>Class of the editor form
creationFormClass()Class<CreationForm>Class of the creation form
toId(String id)IdTypeConverts the URL string id to the actual IdType
getIdFieldForRow()StringField name in Row that holds the identifier
search(searchText, filters, pageable, httpRequest)ObjectExecutes the filtered search and returns ListingData<Row>
save(httpRequest)ObjectPersists the edit form
saveNew(httpRequest)ObjectPersists the creation form
MethodPurpose
search(searchText, filters, pageable, httpRequest)Returns ListingData<Row>
getView(id, httpRequest)Returns the View object
getEditor(id, httpRequest)Returns the Editor object
getCreationForm(httpRequest)Returns a blank CreationForm
deleteAllById(ids, httpRequest)Deletes selected rows

The editor must implement this interface:

public interface CrudEditorForm<IdType> {
void save(HttpRequest httpRequest);
IdType id();
}

save() is called when the user submits the edit form. id() is used to navigate back to the detail view after saving.

The creation form must implement this interface:

public interface CrudCreationForm<IdType> {
IdType create(HttpRequest httpRequest);
}

create() is called when the user submits the creation form. It returns the id of the newly created entity.


public record ProductFilters(
String name,
ProductStatus status
) {}
public record ProductRow(
@PrimaryKey String id,
String name,
BigDecimal price,
ProductStatus status
) implements Identifiable {}
public record ProductView(
String id,
String name,
String description,
BigDecimal price,
ProductStatus status
) {}
public class ProductEditor implements CrudEditorForm<String> {
public String id;
@NotEmpty
public String name;
public String description;
@NotNull
public BigDecimal price;
public ProductStatus status;
@Override
public String id() { return id; }
@Override
public void save(HttpRequest httpRequest) {
// persist changes — inject services via constructor or Spring
}
}
public class ProductCreationForm implements CrudCreationForm<String> {
@NotEmpty
public String name;
@NotNull
public BigDecimal price;
@Override
public String create(HttpRequest httpRequest) {
// create and persist — return the new entity's id
return UUID.randomUUID().toString();
}
}
@Service
public class ProductCrudAdapter
implements CrudAdapter<ProductView, ProductEditor, ProductCreationForm, ProductFilters, ProductRow, String> {
private final ProductService service;
public ProductCrudAdapter(ProductService service) {
this.service = service;
}
@Override
public ListingData<ProductRow> search(
String searchText, ProductFilters filters, Pageable pageable, HttpRequest httpRequest) {
return service.search(searchText, filters, pageable);
}
@Override
public ProductView getView(String id, HttpRequest httpRequest) {
return service.findView(id);
}
@Override
public ProductEditor getEditor(String id, HttpRequest httpRequest) {
return service.findEditor(id);
}
@Override
public ProductCreationForm getCreationForm(HttpRequest httpRequest) {
return new ProductCreationForm();
}
@Override
public void deleteAllById(List<String> ids, HttpRequest httpRequest) {
service.deleteAll(ids);
}
}
@Service
@UI("/products")
public class ProductOrchestrator
extends CrudOrchestrator<ProductView, ProductEditor, ProductCreationForm, ProductFilters, ProductRow, String> {
private final ProductCrudAdapter adapter;
public ProductOrchestrator(ProductCrudAdapter adapter) {
this.adapter = adapter;
}
@Override
public CrudAdapter<ProductView, ProductEditor, ProductCreationForm, ProductFilters, ProductRow, String> adapter() {
return adapter;
}
@Override
public Class<ProductEditor> editorClass() { return ProductEditor.class; }
@Override
public Class<ProductCreationForm> creationFormClass() { return ProductCreationForm.class; }
@Override
public String toId(String id) { return id; }
@Override
public String getIdFieldForRow() { return "id"; }
@Override
public Object search(String searchText, Object filters, Pageable pageable, HttpRequest httpRequest) {
return adapter.search(searchText, (ProductFilters) filters, pageable, httpRequest);
}
@Override
public Object save(HttpRequest httpRequest) {
var editor = httpRequest.getComponentState(ProductEditor.class);
editor.save(httpRequest);
return editor.id();
}
@Override
public Object saveNew(HttpRequest httpRequest) {
var form = httpRequest.getComponentState(ProductCreationForm.class);
return form.create(httpRequest);
}
}

MethodDefaultOverride to…
readOnly()falsemake the whole orchestrator read-only
view(id, httpRequest)calls adapter().getView()customize the view before rendering
edit(id, httpRequest)calls adapter().getEditor()customize the editor before rendering
searchable()truehide the search bar
selectionEnabled()truedisable row selection
title()class nameoverride the page title

OrchestratorFilter typeRow typeWriteSeparate forms
AutoListOrchestrator<T>TT
FilteredAutoListOrchestrator<F,R>FR
AutoCrudOrchestrator<T>TT
FilteredAutoCrudOrchestrator<F,R>FR
CrudOrchestrator<V,E,C,F,R,Id>FR

Move to CrudOrchestrator only when the view/editor/creation forms must differ from each other or from the row model. The simpler variants cover most real-world cases.