Open-Source Wikis

/

Spring Framework

/

How to contribute

/

Patterns and conventions

spring-projects/spring-framework

Patterns and conventions

The Spring Framework codebase has been written and maintained for nearly two decades. It carries strong, consistent conventions. New contributions must match the surrounding style.

File and package layout

  • One public type per file. Inner static helper types are fine.
  • Packages mirror module-level domains: org.springframework.<module>.<area>.
  • *.support packages contain implementation helpers; *.config packages contain configuration classes; *.annotation packages contain annotations and their processors.
  • Internal-only types (not for public consumption) live in packages whose name ends with .support, .internal, or are package-private.

Class structure

Within a typical Spring class:

  1. License header (Apache 2.0)
  2. Package
  3. Imports (no wildcards; ordered: java.*, jakarta.*, third-party, org.springframework.*)
  4. Javadoc
  5. Class declaration
  6. Fieldsstatic final first, then final, then mutable
  7. Constructors — primary first
  8. Public methods — grouped by concept, not alphabetical
  9. Protected/private helpers — at the bottom
  10. Inner classes — last

Nullness annotations

The codebase is in an active migration from Spring's own org.springframework.lang.@Nullable to JSpecify (org.jspecify.annotations.@Nullable).

  • New code should prefer JSpecify annotations where the surrounding module has already been migrated.
  • Each module's nullness rules are validated by the io.spring.nullability Gradle plugin at build time.
  • A package-info.java typically declares @NullMarked or @NonNullApi to set the default.
  • A method that returns null must be annotated @Nullable. A parameter that accepts null must be annotated @Nullable. The build will fail otherwise.

Generics, type tokens, and ResolvableType

When a method needs the full generic type (not just the raw class), the codebase uses org.springframework.core.ResolvableType rather than Type/ParameterizedType directly. ResolvableType resolves type variables across class hierarchies and is the standard for advanced generic work in this codebase.

ResolvableType resolved = ResolvableType.forMethodReturnType(method);
ResolvableType element = resolved.getGeneric(0);

Logging

  • Use Apache Commons Logging (org.apache.commons.logging.Log) — Spring ships its own SLF4J-bridge, so this is effectively SLF4J under the hood.
  • Acquire loggers via LogFactory.getLog(getClass()) and store as protected final Log logger = ….
  • Use if (logger.isDebugEnabled()) only for expensive message construction.
  • Log levels: error for unexpected failures, warn for recoverable problems, info for major lifecycle events, debug for routine internal flow, trace for fine-grained details.

Exception conventions

  • Public APIs throw runtime exceptions for programmer/configuration errors and checked exceptions only when they're intrinsic to the operation (rare; Spring largely avoids checked exceptions).
  • Exception hierarchies are deep and well-organized. For example:
    • BeansExceptionBeanInitializationException, NoSuchBeanDefinitionException, …
    • DataAccessExceptionDataAccessResourceFailureException, DataIntegrityViolationException, …
  • New exception types extend the closest framework parent, not RuntimeException directly.
  • Translate underlying SQLException / JMSException / etc. into Spring's hierarchy at the API boundary using *ExceptionTranslator classes.

Error message style

  • Sentences end with periods. Multi-line error messages have one sentence per period.
  • Include the offending value ("Failed to resolve bean: " + beanName) — log lines without identifiers are unhelpful.
  • Use Assert (org.springframework.util.Assert) for precondition checks: Assert.notNull(value, "Value must not be null").

Annotation design

  • Stereotype annotations (@Component, @Service, …) are meta-annotated for composability.
  • @AliasFor is used heavily to alias annotation attributes between annotations.
  • Annotation processors live in *.annotation packages and typically extend BeanFactoryPostProcessor or BeanDefinitionRegistryPostProcessor.

Configuration class style

  • Prefer @Configuration with @Bean methods to XML for new code.
  • @Configuration(proxyBeanMethods = false) is preferred for "lite" configurations that don't depend on inter-@Bean-method calls — produces less reflection and works better in native images.
  • @Conditional-style annotations are used sparingly in the framework itself; they're more common in Spring Boot.

Code formatting

  • Tabs for indentation, not spaces (intentional, consistent across decades).
  • Line length: ~120 characters is the soft limit.
  • Braces on same line (Java standard, K&R variant).
  • Imports: no wildcards; ordering enforced by Checkstyle.

The full code style is documented at Spring's Code Style wiki page; IntelliJ settings live at IntelliJ IDEA Editor Settings.

Internationalization

  • Public-facing string resources go through MessageSource.
  • Internal exception messages and logs are English only.

Backwards compatibility

  • The framework guarantees binary and source compatibility within a minor release line (e.g., 7.0.x).
  • Major releases (e.g., 7.0 → 7.1, 6.x → 7.x) may break compatibility but must be documented in the upgrade guide.
  • New methods added to public interfaces must be default to preserve compatibility.
  • Deprecated APIs are kept for at least one minor cycle and removed in the next major. Use @Deprecated(since = "X.Y", forRemoval = true).

Reactive code conventions

  • Public reactive APIs return Mono<T> or Flux<T> — never raw Publisher<T> (so users get the operator-rich Reactor types).
  • Methods that adapt to other reactive libraries go through ReactiveAdapterRegistry (spring-core).
  • Avoid blocking inside reactive flows. The codebase uses BlockHound in some test runs to enforce this.

Kotlin conventions

  • Kotlin extensions for framework APIs live alongside Java code in <module>/src/main/kotlin/.
  • Extension files are named after the type they extend, e.g., BeanFactoryExtensions.kt.
  • Spring's Kotlin code uses idiomatic Kotlin (data classes, extension functions, DSL builders).

Test conventions

See testing — test class style mirrors production class style.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Spring Framework wiki | Factory