Concise extract of CONTRIBUTING.md, which remains the reference for humans.
- Gradle build, JDK from
.sdkmanrc(currently JDK 25,sdk env install/sdk env); artifacts target Java 17+. - Scope builds to the modules you touched:
./gradlew :spring-webmvc:test, a single test with--tests <fully.qualified.ClassTests>. - Run
./gradlew :<module>:checkbefore finishing: it runs tests and Checkstyle (src/checkstyle/checkstyle.xml), which enforces most of the code style below. - NullAway null-safety checks run during compilation; fix reported errors instead of suppressing them.
- Do not run
cleanunless needed; the build is incremental and cached. - Reference docs:
./gradlew antora, output inframework-docs/build/site/index.html.
- Match surrounding code; do not reformat unrelated code; a file should look like it was written by a single author.
- Tabs, LF, UTF-8, no trailing whitespace.
- Aim for 90 characters per line for code (105 acceptable, 120 max) and ~80 for Javadoc.
- Wrap lines after separators (
,+?:&&||), never before. - K&R braces, with
else,catch, andfinallyon a new line. - Two blank lines before fields, constructors,
static {}blocks, and inner classes; one blank line after a multiline method signature. - Import order, groups separated by a blank line:
java.*, thenjavax.*+jakarta.*, then others, thenorg.springframework.*, then static imports. - No wildcard imports. No static imports in production code except constants/enum constants and third-party DSL factory methods; use them in tests (e.g.
assertThat). - Every source file: Apache 2.0 license header (
Copyright 2002-present the original author or authors., copy from an existing file), package, imports, exactly one top-level class. - Always reference fields with
this., never methods. Always add@Override. - No
varin production code. No single-character variable names. Wrap ternaries in parentheses with the non-null condition first:(foo != null ? foo : "default"). - Argument checks:
Assert.notNull(event, "Event must not be null"); state checks:Assert.state(...). - Null-safety with JSpecify: packages are
@NullMarkedinpackage-info.java, useorg.jspecify.annotations.Nullableexplicitly (e.g.private @Nullable String name;), repeat super method nullness on overrides,@Contractwhere useful. - Static utility classes:
abstract,Utilssuffix, private constructor. - No
System.out/System.errorprintStackTrace().
- First sentence in imperative style ("Return", not "Returns");
<p>to start extra paragraphs;{@code}for code andnull. - No blank line between method description and tags; do not indent wrapped tag descriptions.
- Add
@sinceto new classes and new public/protected methods; omit a.0patch version (@since 7.1, not7.1.0). - Tag order for types:
@author,@since,@param,@see,@deprecated; for members:@param,@return,@throws,@since,@see,@deprecated.
- Add or update tests for any code change.
- JUnit Jupiter, AssertJ (including
assertThatIllegalArgumentException()and similar), Mockito. No JUnit 4/Jupiter/TestNG assertions, no Hamcrest. - Test class names end with
Tests. - Use the standard Mockito API (
when(...).thenReturn(...)), notBDDMockito(given(...)), in new test code; do not migrate existingBDDMockitousage.
- Reference docs are AsciiDoc in
framework-docs/modules/ROOT; code snippets forinclude-code::live inframework-docs/src/main/{java,kotlin}.
- Pull requests target
main. - Subject: imperative, capitalized verb, at most 55 characters, no
fix:/docs:prefixes, no issue/PR number, no trailing period. - Body wrapped at 72 characters explaining the motivation, followed by
Closes gh-123(orSee gh-123), then aSigned-off-by: Name <email>trailer (DCO, usegit commit -s). - Never write annotations verbatim in commit messages or PR titles (it mentions GitHub users): enclose them in backticks, as in
`@Override`. - Changes must be reviewed by a human who remains accountable for them before being submitted.