Contributing to Apache Pulsar support for Spring

Apache Pulsar support for Spring is released under the Apache License 2.0. This document helps you get started if you'd like to contribute or work on the code. See the README for the project background and modules.

If you use AI tooling, see Using AI tools. Agents also follow AGENTS.md.

Reporting issues

We use GitHub issues to track bugs and enhancements.

If you're reporting a bug, please provide as much information as you can, as it speeds up the diagnosis. Ideally, include a small sample project that reproduces the problem.

Reporting security vulnerabilities

Don‘t report vulnerabilities in public issues, and don’t disclose a vulnerability, or the security nature of a change, in a public issue, pull request or commit. See SECURITY.md for how to report them.

Discussing large changes

Please discuss large refactorings on dev@pulsar.apache.org before you start working on them. We recommend joining the mailing list before posting to it. The join instructions are on the Pulsar website.

Setting up your environment

You need:

  • JDK 25. The build uses a Java 25 toolchain and compiles for Java 17.
  • Docker, for most of the tests.

Use the included Gradle wrapper, ./gradlew.

IntelliJ IDEA

  1. Open the root directory of the repository as a Gradle project, and select JDK 25 as the Gradle JVM in Settings | Build, Execution, Deployment | Build Tools | Gradle.
  2. Install the Spring Java Format plugin. Download spring-javaformat-intellij-idea-plugin-<version>.jar from Maven Central, using the javaformat version in gradle/build-libs.versions.toml, and install it with Settings | Plugins | Install Plugin from Disk. It activates when IntelliJ IDEA imports the Gradle project, and shows an icon in the status bar. Code | Reformat Code then uses the project's formatting.
  3. The plugin doesn't configure imports, so set them in Settings | Editor | Code Style | Java | Imports:
    • Set Class count to use import with ‘*’ and Names count to use static import with ‘*’ to 999.
    • Set Import Layout to these groups, with a blank line between them:
      1. import static all other imports
      2. java
      3. javax
      4. org
      5. org.springframework
      6. all other imports
  4. Keep Run tests using set to Gradle, which is the default. The build adds the JVM options that the tests need, such as the ones for the Pulsar client and Netty, and the IntelliJ IDEA test runner wouldn't use them.

To also see Checkstyle violations in the editor, set up the CheckStyle-IDEA plugin with the Spring Java Format instructions, and use src/checkstyle/checkstyle.xml as the configuration file.

Building and testing

./gradlew build                                # Everything, including the tests
./gradlew build -PsampleTests                  # Also runs the sample application tests
./gradlew build -x test -x integrationTest -x dockerTest   # Everything except the tests
./gradlew :pulsar-spring:test --tests '*PulsarTemplateTests'   # Scope test runs while working
./gradlew :pulsar-spring-boot-autoconfigure:dockerTest
./gradlew :pulsar-spring-integration-tests:integrationTest
./gradlew :pulsar-spring-sample-apps:sample-pulsar-reader:test -PsampleTests   # Scope a sample's tests
./gradlew :pulsar-spring-docs:antora           # Site output in pulsar-spring-docs/build/site

The README also covers running the tests with another Pulsar image, against published artifacts and in a native image.

Code conventions

CI enforces the formatting, Checkstyle and license header rules. To check them without running the tests:

./gradlew checkFormat checkstyleMain checkstyleTest rat
  • Formatting: we use Spring Java Format. Apply it with your IDE or with ./gradlew format. Format checks are disabled for the pulsar-spring module, so formatting can also change unrelated files there: review the diff, and keep those changes out of your commit.
  • Packages: all sources belong under org.apache.pulsar.spring.
  • Artifacts: the group is org.apache.pulsar, set in gradle.properties, and published artifact IDs start with pulsar-spring. Spring Boot does not manage their versions.
  • Name: the project is “Apache Pulsar support for Spring”. Use “Spring for Apache Pulsar” only when referring to the upstream project it succeeds, as in NOTICE and the migration page.
  • Author tags: don't add @author tags. The ASF board discourages them, and the Git history records the authors. Checkstyle and CI reject them.
  • Imports: Checkstyle requires static imports first, then java, javax, org, org.springframework and everything else, as separate groups.
  • Javadoc: add a Javadoc comment to new classes that says what they're for.
  • Documentation: there is one site, in pulsar-spring-docs/src/main/antora. Don't add documentation to other modules. The Java and Kotlin snippets in pulsar-spring-docs/src/main are compiled, and the Configuration Properties appendix is generated from the auto-configuration metadata.
  • Sample apps: pulsar-spring-sample-apps is a separate Gradle build that only shares the version catalog, and uses the artifacts by their coordinates. The main build includes it and substitutes its projects for them. Gradle's dependencies and dependencyInsight tasks hang for its projects when run through the main build, so run them in that directory with -PpulsarSpringRepository, as described in its README.adoc.
  • Tests: add tests for your change. Tests that need a broker use Testcontainers. Clean up anything you start, including containers, so that runs don't leave resources behind.
  • Compatibility: don't break backward compatibility in public APIs or configuration properties without calling it out, and record user-facing changes in the What's New page.

Submitting a pull request

  • Keep a change focused on its task, and don't bundle unrelated refactoring.
  • Rebase your branch on main if no one else is using it. Pull requests are squashed or rebased when they're merged, not merged with a merge commit.
  • Write commit messages that follow these conventions, and start the subject with the type of change, such as fix:, docs:, build:, test:, ci:, refactor: or chore:.

Licensing and provenance

  • Every new source file needs the ASF license header. Copy the form from a package-info.java file, and keep existing notices in imported code. ./gradlew rat checks this, with exclusions in .ratignore.
  • Don't introduce code of incompatible or unknown provenance. Never copy verbatim from GPL/AGPL/LGPL, proprietary or unlicensed sources, including Stack Overflow, blog or forum snippets of unclear licensing. Reimplement from specifications or Apache-compatible sources, and follow the ASF 3rd Party Licensing Policy.

Using AI tools

Contributions made with AI tools must meet the ASF's Generative Tooling guidance:

  • A human is in the loop and is accountable. Every pull request and every security report must be submitted by a human contributor who has reviewed and verified the change and takes responsibility for it. Fully autonomous agents opening pull requests or filing reports on their own are not acceptable.
  • Don't use a tool whose terms restrict the output inconsistently with open source.
  • Consider attributing AI assistance. When AI tooling assisted on a change, consider adding an Assisted-by: <tool/version> commit trailer, which is the default since a human still does the final review. Generated-by: <tool/version> is for minimally-modified generated output.

Where to ask

See the discussion channels of the Apache Pulsar community on the Pulsar website, along with how to join them. The channels include:

The Apache Pulsar documentation is at https://pulsar.apache.org.