Help make the library
a little better.
Bug reports, pull requests, tutorials, documentation fixes — all welcome. No CLA, no copyright assignment. Everything contributed stays under EUPL 1.2.
Pick whichever fits
File an issue
Found a bug, a confusing error message, or a doc that's wrong? Open an issue. A minimal reproducer goes a long way.
Improve docs
Typo fixes, clearer examples, a missing tutorial — docs PRs are the easiest to get merged and the most appreciated.
Submit code
For non-trivial changes, open an issue first so we can sketch the design together. Saves both sides the dead-end PR experience.
Filing a good bug report
A useful report has three parts:
- What you ran — the smallest snippet that reproduces the problem, including the
DI.activatePackages(...)calls used in the test or app. - What you expected — including the JDK version, library version, and OS if relevant.
- What you got — the actual error, stack trace, or wrong implementation chosen by the resolver.
Library version: 06.01.01
JDK: OpenJDK 21
OS: macOS 14 / Linux 6.6
Setup:
- Service interface with two impls (ServiceA, ServiceB).
- One ClassResolver returning ServiceB.
Expected: DI.activateDI(Service.class) returns ServiceB.
Got: DDIModelException: ambiguous resolution.
Open it at the [DDI issues tracker]({{ .Site.Params.github }}/issues).
Submitting a pull request
The flow is:
- Discuss first — for anything beyond a typo or a one-line fix, open an issue describing the change. We agree on the shape, then you write the code.
- Fork & branch — branch off
main, prefix the branch withfix/,feat/ordocs/plus a short slug. - Stay small — one logical change per PR. A 200-line PR reviewed in a day is more useful than a 2000-line PR that sits for a month.
- Tests required for code changes — add at least one JUnit 5 test that fails without your change and passes with it. For resolver/producer changes, the test should clear the model with
DI.clearReflectionModel()in@BeforeEachto keep test isolation. - Run the build locally —
mvn clean installshould pass before you push. - Mutation tests — if you change resolver internals, run
mvn -P pitest testand aim to keep the score above 90 %. - Keep style consistent — match the surrounding code. No re-flowing unrelated files; the diff should be the change you want to land.
Local development
DDI lives in the umbrella dependencies repository alongside core, functional-reactive, core-properties and logger-adapter:
git clone https://github.com/svenruppert/dependencies
cd dependencies
mvn clean install
The build targets JDK 21 LTS. SDKMAN! is the easiest way to switch:
sdk install java 21.0.4-tem
sdk use java 21.0.4-tem
Run only the DDI module tests:
mvn -pl ddi -am test
Run a single test class:
mvn -pl ddi test -Dtest=ClassResolver010Test
Run mutation tests against DDI:
mvn -pl ddi -P pitest test
Code style
Nothing exotic. Match the surrounding code. A few specific points:
- No checkstyle / spotless gate — readability beats mechanical conformance. The reviewer flags style issues during review.
- Public API gets Javadoc. Internal helpers don’t have to.
- No comments restating what the code does. Comment the why — the surprising invariant, the workaround for a specific bug, the design choice a future reader won’t infer from the names.
- No new runtime dependencies without prior discussion. The current bar is
reflections8,gson,javax.annotation-api, plus the sister projects (core,functional-reactive). - JDK 21 baseline. Records, sealed classes and pattern matching are fine. We don’t need to preserve JDK 8 compatibility in the 06.x line.
What gets accepted, and what doesn’t
Easy yes:
- Bug fixes with a regression test.
- Doc improvements, typo fixes, clearer examples.
- New resolver / producer tutorials.
- Test-coverage improvements for existing public API.
Discuss first:
- New top-level types or packages in
com.svenruppert.ddi.*. - Anything that changes a public API signature.
- New built-in scopes (the model is intentionally small).
- Build-tool changes, parent-POM bumps.
Probably no:
- “Make it more like <framework X>” rewrites.
- Mechanical reformatting that touches files you didn’t otherwise change.
- Replacing the licence, the build tool, or the test framework on a whim.
Licensing & signing off
All contributions are licensed under EUPL 1.2, the same licence the library uses. By submitting a PR you confirm that you have the right to license your contribution that way. There is no separate CLA to sign — your PR description and Git history are enough.
If the change is non-trivial, please add a Signed-off-by line to your commits:
git commit -s -m "feat: add ClassResolver caching hook"
Community
By participating in this project’s discussions, issues, and PRs, you agree to follow the Code of Conduct. Be kind, be specific, assume good faith.
Thank you
Open source happens because people show up. If you take the time to file a careful bug report or a thoughtful PR, you’re keeping this library alive for everyone else using it. That matters. Thank you.