Code style
Most of njMule's style is enforced by the build: Spotless formats and checks the Java sources, Checkstyle checks what the formatter cannot, and SonarQube Cloud gates the rest. A few rules no tool catches; this page lists them all, so that a review has nothing left to say about style.
Formatting
Java code follows the Google Java Style Guide, formatted with palantir-java-format in its PALANTIR style:
- 4-space indentation, 8 for continuation lines;
- 120 columns;
- compact lambdas and call chains, Javadoc reflowed;
- sorted imports, no wildcard imports, no unused imports.
Spotless applies it (./gradlew spotlessApply) and ./gradlew build fails on any unformatted file
or missing license header. In IntelliJ IDEA, install the palantir-java-format plugin and let the
IDE honour .editorconfig.
Every file type follows the same basics, set in .editorconfig and .gitattributes:
| Rule | Exception |
|---|---|
| 4-space indentation, in Java, Kotlin build scripts, XML, YAML and scripts | tabs in Makefiles only |
| LF line endings, in the repository and in every checkout | *.cmd and *.bat files use CRLF, which cmd.exe needs |
| UTF-8, a final newline, no trailing whitespace | Markdown keeps trailing whitespace |
| Java, Kotlin: at most 120 columns | Markdown is wrapped at about 100 columns |
The interface's and this site's TypeScript and Vue files are formatted with Prettier (120 columns,
4 spaces, single quotes, LF), checked by the build for the interface
(Interface) and by ./gradlew :website:siteCheck for this
site (Documentation). The desktop window's Rust code is
formatted with cargo fmt (120 columns, rustfmt.toml) and linted with Clippy, which the CI runs
with warnings as errors.
Fields and own methods
Always qualify instance fields with this., also where nothing needs disambiguating, and call the
object's own methods without it:
this.queue.offer(task); // a field: always this.
publish(event); // an own method: never this.publish(event)
Checkstyle enforces both, with RequireThis and a regular expression in
config/checkstyle/checkstyle.xml. It also requires braces around every block, one statement per
line and one variable per declaration, and refuses wildcard imports; a single warning fails the
build. The tests follow the same rules.
Names that differ only in case
Never give two members of one type names that differ only in case, such as a constant DIRECT
and a field direct, or SETTINGS and settings. SonarQube's rule java:S1845 marks it as a
blocker and fails the quality gate, and neither the compiler nor Checkstyle notices it.
The mistake comes back whenever a constant is named after what a field or method of the same type
holds or does: SECONDS beside seconds, JSON beside json(...), HOST beside host(...),
ENGLISH beside english(), or a nested type Windows beside a field windows. Name the newcomer
after what it is (SECONDS_KEPT, MAPPER, TEMPLATES, SETTINGS_PAGE, straight), and before
you commit, compare every new member's lower-cased name with the others of its type, inherited ones
included.
Comments
- Comment only what the code cannot say: the why, invariants, security reasons, references to a specification or an RFC.
- Keep comments to one or two lines. No comments that restate the code, no change history, no "added by". The story of a change belongs in its commit message.
- Public API Javadoc: one summary sentence;
@paramand@returnonly when the name does not say it. No Javadoc on trivial getters, setters, builders or obvious methods. - Never reference eMule's source code in code, comments, tests or commit messages: no file names
of its sources (
*.cpp,*.h), no line numbers, classes, functions or variables, and no "as eMule does" phrasing. Describe the protocol or the file format itself. Name eMule only where the feature is about it: importing an eMule profile, interoperability tests.
Logging
- Log only through SLF4J, with
{}placeholders:logger.info("Server {}:{} added", host, port). Never use external data as a format string. - A logger is
private static final Logger logger, in lowerCamelCase (in the Google style a logger is not a constant), neverLOG. - The log line encoder of
njmule-appreplaces line breaks in every message, so call sites need not clean the data they log.
Engineering rules
- Use what exists. The JDK or a well-known, maintained library comes before a utility, codec, parser or algorithm of your own (Dependencies).
- The core knows no interface.
njmule-corenever depends on AWT or on an interface module; front ends use only its exported packages (Developer guide), and the interface reaches the engine only through the remote-control API. - Native-image friendly. No undeclared reflection, no dynamic proxies; register resources and
ServiceLoaderproviders in the reachability metadata (Native images). - Hands off the user's eMule. Never write into an eMule installation or configuration folder: the import only reads them.
- Static analysis is part of the build. Error Prone runs with the compiler, SpotBugs with
FindSecBugs on the production code. An exclusion in
config/spotbugs/exclude.xmlcarries its reason, such as MD4, MD5 and SHA-1, which the eD2K and Kad protocols mandate.
Licensing and REUSE
njMule follows the REUSE specification, which the CI checks on every push.
-
Every Java file starts with the header of
config/license/header-java.txt, which Spotless adds and checks:/** njMule - Next generation Java Mule* SPDX-FileCopyrightText: 2026 Salvatore Coppola and the njMule contributors* SPDX-License-Identifier: GPL-3.0-or-later** This program is free software: ...*/ -
Every other text file carries the two SPDX lines as comments of its own syntax, for example in a Kotlin build script:
// SPDX-FileCopyrightText: 2026 Salvatore Coppola and the njMule contributors// SPDX-License-Identifier: GPL-3.0-or-later -
Files that cannot carry a comment (binaries, JSON, images, lock files) are covered by an entry of
REUSE.toml. This site's pages are covered there too, under CC BY-SA 4.0. -
Third-party code or assets keep their notices and are recorded in
REUSE.tomlandNOTICE; only licenses compatible with the GPL 3.0 are allowed (Dependencies). -
No graphical asset of eMule (icons, bitmaps, skins, logo) is ever used or derived from: all artwork is original and lives in
branding/. -
No personal data in the repository: no copies of an eMule configuration, user hashes, nick names, IP addresses or screenshots of your own eMule. Keep them in the git-ignored
fixtures-private/and.local/folders.
UI colours
The interface has one sober palette with pastel tints, the same in the desktop window and in the web interface, compatible with whichever theme is in use. The default theme is Nord Light or Nord Dark, following the system's colour scheme; Primer, Cupertino and Dracula stay selectable.
- Tokens only. Use the theme's colours (
--color-bg-*,--color-fg-*,--color-accent-*,--color-success-*, …) and njMule's--nj-*tokens. The theme's colours are innjmule-ui/src/styles/themes.css, one rule per theme, converted once from the AtlantaFX 3.0.0 themes (MIT); the--nj-*tokens are innjmule-ui/src/styles/njmule.css. Those files hold the only colour literals: none in TypeScript, Vue or CSS elsewhere. - Every token has a light and a dark value, and the system's forced colours (high contrast) take the place of the tokens while they are on.
- Pastel for surfaces, theme colours for text. Pastel tones fill surfaces, bars, charts and
chips (
*-subtle,*-muted); text uses the theme's--color-fg-*and--color-*-fgtokens, never a pastel tone. Saturated colours are kept for real errors and warnings. - Accessibility (WCAG 2.2 AA). Text keeps a contrast of 4.5:1 at least (3:1 for large text), essential icons and graphics 3:1; colour is never the only cue, so add an icon, a tooltip, a legend or a pattern.
- The brand is a deep blue
#24427A, an off-white mark#F4F6FBand warm orange accents#F5A65B(seebranding/README.md). Orange stays an accent, never a large surface.
The pre-commit hook
An optional Git hook runs spotlessCheck before each commit and stops a commit with unformatted
code or a missing license header:
git config core.hooksPath .githooks
Related pages
- Testing: the given/when/then style of every test.
- Contributing: commits, sign-off and pull requests.
- Releases: Conventional Commits and branch names.