- Multi-module Gradle workspace for Jmix development.
- Standard Gradle layouts (
src/main,src/test) per module. - BOM for shared dependencies and Jmix modules in
jmix-bom. - Gradle plugin used by applications in
jmix-gradle-plugin. - Gradle plugin to build Jmix itself in
jmix-build.
./gradlew build— build all modules and run checks../gradlew test— run tests across modules../gradlew :<module-name>:test— run tests of a single module. Take<module-name>fromsettings.gradle, for exampledataforjmix-data/datamodule. It means that you must execute./gradlew :data:testinstead of./gradlew :jmix-data:data:test.- Tests of REST API are located in
jmix-rest/sample-restmodule and executed with./gradlew :sample-rest:test.
- Use
jetbrainsMCP to check file problems withget_file_problems("path/to/file.ext", onlyErrors=false). - Add imports instead of using fully qualified class names.
- Do not add comments or Javadocs to the files that you didn't change.
- Use current year in copyright headers for new files, e.g.
Copyright 2026 Haulmont. - Don't read the whole content of files JPA2Lexer.java and JPA2Parser.java to save context space and tokens. They are auto-generated from JPA2.g and JPA2.tokens as described in
jmix-data/data/src/main/java/io/jmix/data/impl/jpql/antlr2/README.md.
- Use IntelliJ default formatting. Max line length 120 (soft), method ~50 lines, class ~500 lines.
- Declaration order: constants, fields, constructors, methods, inner interfaces, inner classes. Static members first.
- Add comments only for non-trivial logic; proper English, start with a capital and end with a period.
- Use blank lines between logical blocks; keep blocks compact.
finalonly where required, not everywhere.- Streams: each method after
stream()on a new line unless it fits in one line.
- Classes: CamelCase even for abbreviations (
RdbmsStore,IdProxy). - Internal helper methods: suffix
Internal; avoid_prefixes. - Beans: explicit
@Component("module_BeanName"). Do not useNAMEconstants. PreferSupportoverHelper/Utils. - Logger constant name:
log. - Accepted abbreviations for local vars:
em(EntityManager),tx(Transaction) ,lc(LoadContext),kc(KeyCombination). - Liquibase: SQL keywords lowercase, identifiers
UPPERCASE_WITH_UNDERSCORES. - View routes:
kebab-casewith module short-id prefix (e.g.sec/resource-role-models).
- Only return/accept
nullwhen annotated@Nullable. Otherwise non-null is implied. - Prefer package-level
@NullMarked(except entity packages). - Use
org.jspecify.annotations.Nullablewhenjspecifyis available, elsejakarta.annotation.Nullable. - For public API, validate non-null params with:
io.jmix.core.common.util.Preconditions#checkNotNullArgument()(ifjmix-coreis available),com.google.common.base.Preconditions(ifguavais available),java.util.Objects#requireNonNull()(fallback).
- Never return
nullcollections; return empty collections.
- Keep code as simple as possible (KISS/YAGNI).
- Pay attention to IDE warnings; suppress narrowly when unavoidable.
- Prefer method references over lambdas when possible; avoid unnecessary lambdas when simple
forloop is possible. - Dependency injection: field injection is preferred.
- Use
em/rem(avoidpx);spacingis default;vboxneedspadding="false"to avoid extra space. TextAreaheight:9.5em.- Avoid expanding
detailActions. Grids typically do not need expand; setmin-height(e.g.20em). - Set
emptySelectionAllowed="true"forSelect/ComboBoxwhen value must be clearable. - Use RTL-safe spacing (
margin-inline-*), and addaria-labelwhere needed. @Routepath: addon prefix then screen name (e.g.sec/resourcerolemodels/:code).@Subscribe,@Install,@Supply, and view parameter methods must bepublic. Other APIs should beprotected/private.- View controller field order: constants, view components, data containers/loaders, beans, then own fields; no blank lines inside a block.
- Component init: constructor handles inputs only, move setup into overridable
protectedinit method. Separate create vs init for child components. - Prevent unsaved changes: when navigation close action is used, also call
BeforeLeaveEvent#postpone. - UI components should support light/dark themes via CSS variables, RTL, forced colors, and reduced motion.
- Icons: use
JmixFontIconandIconsbean where available; new icons requireJmixFontIconentry and CSS mapping.
- Data containers:
camelCaseending withDc(e.g.usersDc). - Data loaders:
camelCaseending withDl(e.g.usersDl). - Query params:
camelCase(prefixes separated by_), e.g.:current_user_username. - Component ids:
camelCase, include purpose; data-bound ids include entity/attribute + type (e.g.usersDataGrid,usernameField). - Action ids end with
Action; include type value if defined (e.g.entityLookupAction). - Exceptions:
detailActions,form; picker actions may omitAction. - Message keys:
- View title:
<viewClassName>.title - Component attribute:
<componentId>.<attribute> - Action attribute:
<actionId>.<attribute>oraction.<actionType>.<attribute> - Menu:
menu.<menuId>.<attribute>; menu item:<viewClassName>.<attribute>ormenu.<menuItemId>.<attribute>
- View title:
- Use JUnit 5 (with Jupiter API) or Spock. Prefer integration tests.
- Tests focus on behavior via public APIs.
- Test packages: top-level by functionality (e.g.
data_manager), with subpackages if needed. Don't add intermediateio.jmix.*packages. - Test infrastructure under
test_support, entities intest_support.entity(or its subpackages). - Resources mirror test package paths under
resources. - Test class names end with
*Test; helper classes start withTest*. - Test method names start with
test. - Use default (package-private) access level for test methods and other test class members.
- Slow tests: tag
@Tag("slowTests")(JUnit) or@IgnoreIf({env["includeSlowTests"] != 'true'})(Spock). Run with-PincludeSlowTests=true.