Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Jmix
https://github.com/jmix-framework/jmix-context7
Admin
Official documentation and UI samples for the Jmix framework, an open-source platform for enterprise
...
Tokens:
1,041,949
Snippets:
10,540
Trust Score:
7.7
Update:
2 days ago
Context
Skills
Chat
Benchmark
93.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Jmix Framework Documentation Jmix is a high-level full-stack framework for building enterprise web applications in Java. It provides a comprehensive set of tools for data modeling, data access, security, UI development, and REST API generation. Built on top of Spring Boot, Jmix offers a rapid application development experience with features like automatic CRUD operations, entity management, role-based security, and a rich component library based on Vaadin Flow. The framework supports JPA entities with automatic database migrations, a powerful DataManager for CRUD operations, declarative security with resource and row-level roles, and a modern reactive UI using Flow components. Jmix also provides a Generic REST API add-on that automatically exposes endpoints for entity operations, business services, and file management without writing custom REST controllers. ## DataManager - Loading Entities DataManager is the main interface for CRUD operations on entities, providing a fluent API for loading, saving, and removing data with automatic security checks and transaction management. ```java @Component public class CustomerService { @Autowired private DataManager dataManager; // Load entity by ID Customer loadById(UUID customerId) { return dataManager.load(Customer.class) .id(customerId) .one(); } // Load with optional result (returns empty if not found) Customer loadOrCreate(UUID customerId) { return dataManager.load(Customer.class) .id(customerId) .optional() .orElse(dataManager.create(Customer.class)); } // Load all entities (use with caution for large datasets) List<Customer> loadAll() { return dataManager.load(Customer.class).all().list(); } // Load by JPQL query with parameters List<Customer> loadByQuery() { return dataManager.load(Customer.class) .query("select c from sample_Customer c where c.email like :email and c.grade = :grade") .parameter("email", "%@company.com") .parameter("grade", CustomerGrade.PLATINUM) .list(); } // Abbreviated query syntax with positional parameters List<Customer> loadByQueryShort() { return dataManager.load(Customer.class) .query("e.email like ?1 and e.grade = ?2", "%@company.com", CustomerGrade.PLATINUM) .list(); } // Load using property conditions List<Customer> loadByConditions() { return dataManager.load(Customer.class) .condition( LogicalCondition.and( PropertyCondition.contains("email", "@company.com"), PropertyCondition.equal("grade", CustomerGrade.PLATINUM) ) ) .list(); } // Paging and sorting List<Customer> loadPageSorted(int offset, int limit) { return dataManager.load(Customer.class) .query("e.grade = ?1", CustomerGrade.BRONZE) .firstResult(offset) .maxResults(limit) .sort(Sort.by("name")) .list(); } } ``` ## DataManager - Saving and Removing Entities DataManager provides methods for persisting new entities, updating existing ones, and removing entities from the database with proper transaction handling. ```java @Component public class OrderService { @Autowired private DataManager dataManager; // Save a single entity Customer saveCustomer(Customer entity) { return dataManager.save(entity); } // Save without reload for better performance void saveCustomerWithoutReload(Customer entity) { dataManager.saveWithoutReload(entity); } // Create and save multiple linked entities Order createOrderWithCustomer() { Customer customer = dataManager.create(Customer.class); customer.setName("Alice"); Order order = dataManager.create(Order.class); order.setCustomer(customer); EntitySet savedEntities = dataManager.save(order, customer); return savedEntities.get(order); } // Save a collection of entities EntitySet saveCustomers(List<Customer> entities) { return dataManager.saveAll(entities); } // Batch save for large collections (performance optimization) void saveInBatches(List<Customer> entities) { for (int i = 0; i < entities.size(); i += 100) { int endIndex = Math.min(i + 100, entities.size()); List<Customer> batch = entities.subList(i, endIndex); dataManager.saveWithoutReload(batch); } } // Remove entity void removeCustomer(Customer entity) { dataManager.remove(entity); } // Remove by ID void removeCustomerById(UUID customerId) { dataManager.remove(Id.of(customerId, Customer.class)); } // Hard delete (bypassing soft deletion) void hardDelete(Product product) { dataManager.save( new SaveContext() .removing(product) .setHint(PersistenceHints.SOFT_DELETION, false) ); } // Bypass security checks with UnconstrainedDataManager @Autowired private UnconstrainedDataManager unconstrainedDataManager; Customer loadByIdUnconstrained(UUID customerId) { return unconstrainedDataManager.load(Customer.class) .id(customerId) .one(); } } ``` ## JPA Entity Definition JPA entities in Jmix are standard JPA entities with additional Jmix-specific annotations for enhanced functionality like automatic ID generation, instance naming, and entity traits. ```java @JmixEntity @Table(name = "CUSTOMER") @Entity public class Customer { @JmixGeneratedValue @Id @Column(name = "ID", nullable = false) private UUID id; @Version @Column(name = "VERSION") private Integer version; @InstanceName @NotNull @Column(name = "NAME", nullable = false) private String name; @Email @Column(name = "EMAIL", unique = true) private String email; // Audit traits @CreatedBy @Column(name = "CREATED_BY") private String createdBy; @CreatedDate @Column(name = "CREATED_DATE") private OffsetDateTime createdDate; @LastModifiedBy @Column(name = "LAST_MODIFIED_BY") private String lastModifiedBy; @LastModifiedDate @Column(name = "LAST_MODIFIED_DATE") private OffsetDateTime lastModifiedDate; // Soft delete traits @DeletedBy @Column(name = "DELETED_BY") private String deletedBy; @DeletedDate @Column(name = "DELETED_DATE") private OffsetDateTime deletedDate; // Many-to-One relationship @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "DEPARTMENT_ID") private Department department; // One-to-Many composition @OrderBy("rowNum") @Composition @OneToMany(mappedBy = "customer") private List<Order> orders; public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } // Other getters and setters... } ``` ## DataGrid Component DataGrid displays tabular data with support for sorting, filtering, inline editing, and lazy loading for efficient handling of large datasets. ```xml <!-- View XML descriptor --> <view xmlns="http://jmix.io/schema/flowui/view"> <data readOnly="true"> <collection id="ordersDc" class="com.company.entity.Order"> <fetchPlan extends="_local"> <property name="customer" fetchPlan="_local"/> </fetchPlan> <loader id="ordersLoader"> <query> <![CDATA[select e from Order e order by e.date]]> </query> </loader> </collection> </data> <facets> <dataLoadCoordinator auto="true"/> </facets> <layout> <dataGrid id="ordersGrid" width="100%" minHeight="20em" dataContainer="ordersDc" columnReorderingAllowed="true"> <columns resizable="true"> <column property="date"/> <column property="customer"/> <column property="amount"/> <column property="description" filterable="true"/> </columns> <actions> <action id="create" type="list_create"/> <action id="edit" type="list_edit"/> <action id="remove" type="list_remove"/> </actions> </dataGrid> </layout> </view> ``` ```java // View controller @ViewController("orders-list") @ViewDescriptor("orders-list.xml") public class OrdersListView extends StandardView { @ViewComponent private DataGrid<Order> ordersGrid; @ViewComponent private CollectionContainer<Order> ordersDc; @Subscribe public void onInit(InitEvent event) { // Programmatic column configuration ordersGrid.getAllColumns().forEach(col -> col.setSortable(true)); ordersGrid.setColumnReorderingAllowed(true); } // Custom renderer for a column @Supply(to = "ordersGrid.status", subject = "renderer") private Renderer<Order> ordersGridStatusRenderer() { return new TextRenderer<>(order -> order.isOverdue() ? "Overdue!" : "On Track"); } // Inline editing with auto-save @Install(to = "ordersGrid.@editor", subject = "closeListener") private void ordersGridEditorCloseListener(EditorCloseEvent<Order> event) { Order order = event.getItem(); Order savedOrder = dataManager.save(order); ordersDc.replaceItem(savedOrder); } } ``` ## Button Component and Event Handling Buttons trigger actions in response to user clicks and can display text, icons, or both with various styling options. ```xml <!-- Button examples in XML --> <view xmlns="http://jmix.io/schema/flowui/view"> <layout classNames="flex-row flex-wrap"> <button id="helloButton" text="Say hello!" title="Click me!"/> <button id="saveButton" text="Save" icon="ARCHIVE"/> <button id="iconOnlyButton" title="Save" icon="ARCHIVE"/> </layout> </view> ``` ```java // Button event handlers @ViewController("button-sample") @ViewDescriptor("button-sample.xml") public class ButtonSampleView extends StandardView { @Autowired private Notifications notifications; @Subscribe("helloButton") protected void onHelloButtonClick(ClickEvent<Button> event) { notifications.show("Hello, world!"); } @Subscribe("saveButton") protected void onSaveButtonClick(ClickEvent<Button> event) { event.getSource().getId() .ifPresent(id -> notifications.show("Save called from " + id)); } } ``` ## Security - Resource Roles Resource roles define permissions for entity operations, attributes, and UI views using declarative annotations on Java interfaces. ```java @ResourceRole(name = "User management", code = UserManagementRole.CODE, scope = "API") public interface UserManagementRole { String CODE = "user-management"; @EntityAttributePolicy(entityClass = User.class, attributes = "*", action = EntityAttributePolicyAction.MODIFY) @EntityPolicy(entityClass = User.class, actions = EntityPolicyAction.ALL) void user(); @EntityAttributePolicy(entityClass = Order.class, attributes = {"id", "date", "amount"}, action = EntityAttributePolicyAction.VIEW) @EntityPolicy(entityClass = Order.class, actions = {EntityPolicyAction.READ}) void order(); @ViewPolicy(viewIds = {"User.list", "User.detail"}) @MenuPolicy(menuIds = {"application", "administration"}) void screens(); } ``` ## Generic REST API The Generic REST API add-on exposes endpoints for CRUD operations, service methods, and file management without writing REST controllers. ```bash # Installation: add to build.gradle # implementation 'io.jmix.rest:jmix-rest-starter' # implementation 'io.jmix.authserver:jmix-authserver-starter' # Configure client credentials in application.properties # spring.security.oauth2.authorizationserver.client.myclient.registration.client-id=my-client # spring.security.oauth2.authorizationserver.client.myclient.registration.client-secret={noop}my-secret # spring.security.oauth2.authorizationserver.client.myclient.registration.authorization-grant-types=client_credentials # jmix.authserver.client.myclient.client-id=my-client # jmix.authserver.client.myclient.resource-roles=user-management,rest-minimal # jmix.resource-server.authenticated-url-patterns=/rest/** # Obtain access token curl -X POST http://localhost:8080/oauth2/token \ --basic --user my-client:my-secret \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" # Response: # { # "access_token": "hKhgNyGMTqaKd6prH-GoHF8zFVTSr9tKKyE3OnMoafRO...", # "token_type": "Bearer", # "expires_in": 299 # } # Load all entities curl -X GET http://localhost:8080/rest/entities/User \ -H "Authorization: Bearer <access_token>" # Response: # [ # { # "_entityName": "User", # "_instanceName": "[admin]", # "id": "60885987-1b61-4247-94c7-dff348347f93", # "version": 1, # "active": true, # "username": "admin" # } # ] # Create entity curl -X POST http://localhost:8080/rest/entities/Customer \ -H "Authorization: Bearer <access_token>" \ -H "Content-Type: application/json" \ -d '{"name": "John Doe", "email": "john@example.com"}' # Update entity curl -X PUT http://localhost:8080/rest/entities/Customer/60885987-1b61-4247-94c7-dff348347f93 \ -H "Authorization: Bearer <access_token>" \ -H "Content-Type: application/json" \ -d '{"name": "John Smith", "email": "john.smith@example.com"}' # Delete entity curl -X DELETE http://localhost:8080/rest/entities/Customer/60885987-1b61-4247-94c7-dff348347f93 \ -H "Authorization: Bearer <access_token>" ``` ## Loading Scalar and Aggregate Values DataManager can load scalar and aggregate values using key-value entities for reporting and analytics queries. ```java @Component public class ReportService { @Autowired private DataManager dataManager; // Load aggregated values as KeyValueEntity String getCustomerPurchases(LocalDate fromDate) { List<KeyValueEntity> kvEntities = dataManager.loadValues( "select o.customer, sum(o.amount) from sample_Order o " + "where o.date >= :date group by o.customer") .store("main") .properties("customer", "sum") .parameter("date", fromDate) .list(); StringBuilder sb = new StringBuilder(); for (KeyValueEntity kvEntity : kvEntities) { Customer customer = kvEntity.getValue("customer"); BigDecimal sum = kvEntity.getValue("sum"); sb.append(customer.getName()).append(" : ").append(sum).append("\n"); } return sb.toString(); } // Load single aggregate value BigDecimal getTotal(LocalDate toDate) { return dataManager.loadValue( "select sum(o.amount) from sample_Order o where o.date >= :date", BigDecimal.class ) .store("main") .parameter("date", toDate) .one(); } } ``` ## View Controller Lifecycle and Annotations View controllers manage UI views with lifecycle events, component injection, and declarative event subscriptions. ```java @ViewController("order-detail") @ViewDescriptor("order-detail.xml") public class OrderDetailView extends StandardView { @ViewComponent private DataGrid<OrderItem> itemsGrid; @ViewComponent private CollectionContainer<OrderItem> itemsDc; @Autowired private DataManager dataManager; @Autowired private Notifications notifications; @Autowired private UiComponents uiComponents; // Lifecycle event - called when view initializes @Subscribe public void onInit(InitEvent event) { // Initialize components } // Lifecycle event - called before view is shown @Subscribe public void onBeforeShow(BeforeShowEvent event) { // Load data, configure components } // Subscribe to component events @Subscribe("saveBtn") protected void onSaveBtnClick(ClickEvent<Button> event) { // Handle button click } // Supply custom renderer @Supply(to = "itemsGrid.total", subject = "renderer") private Renderer<OrderItem> itemsGridTotalRenderer() { return new ComponentRenderer<>(() -> { Span span = uiComponents.create(Span.class); return span; }, (span, item) -> { span.setText(String.format("$%.2f", item.getTotal())); }); } // Install custom handler @Install(to = "itemsGrid", subject = "enterPressHandler") private void itemsGridEnterPressHandler(DataGrid.EnterPressEvent<OrderItem> event) { // Handle enter key press } } ``` Jmix is designed for building line-of-business applications with complex data models, security requirements, and rich user interfaces. The framework excels at rapid development of internal enterprise applications, admin panels, CRM systems, and data-intensive business applications where productivity and maintainability are paramount. The typical integration pattern involves defining JPA entities with Jmix annotations, using DataManager for data access in services and controllers, building UI views with Flow components in XML descriptors, and exposing business functionality through the Generic REST API for external integrations. Security is enforced declaratively through resource and row-level roles that automatically apply to both UI and API access.