A small Maven project for trying maddi's IDE plugins by hand: open it, run the analysis, and check that the hints, the gutter icons and the tool window say what this project says they should.
Every class shows one or two of maddi's annotations, and its Javadoc says what to look for. The popular annotations
(@NotModified/@Modified, @Immutable, @Container, @Independent) recur throughout; the rare ones have a class
each. EXPECTED-HINTS.md lists, per declaration, exactly what the analysis computes.
The classes are adapted from the test batteries of maddi-modification-analyzer and maddi-modification-link.
- IntelliJ IDEA: File → Open on this directory, as a Maven project. Install the maddi plugin, set its JDK (25 or later) under Settings → Tools → maddi, then Tools → Analyze with maddi.
- Builds with
mvn compileon JDK 21 or later. The only dependencies areio.codelaser:maddi-annotationandio.codelaser:maddi-support0.9.5 from Maven Central, for the contracts and the eventually immutable classes.
| Package | Classes | Shows |
|---|---|---|
demo.modification |
Counter, Bag, ListTools, Item, Elements, Registry |
@Modified / @NotModified on methods, fields and parameters; @Container; @Modified(hc=true) where only the elements change |
demo.immutable |
Point, Pair, Color, Snapshot, Tags, LazyName, Shape, Circle |
@ImmutableContainer, with and without hidden content; @FinalFields; @Final; a contract on an interface |
demo.independence |
Inventory, Box, Wrapper |
@Independent, @Independent(hc=true), @Dependent; @UnmodifiableView |
demo.method |
Sentence, Checks, Person, Ranges |
@Fluent, @Identity, @GetSet, @Commutable |
demo.nullability |
Lookup |
@NotNull / @Nullable |
demo.eventual |
Config, Document |
@Mark, @Only, @TestMark, @Immutable(after=...), @NotModified(after=...) |
demo.rare |
Audit, Settings, SettingsClient, Report, Worker, Clock, Strings |
@IgnoreModifications, @StaticSideEffects, @Finalizer, @AllowsInterrupt, @Singleton, @ExtensionClass, @UtilityClass |
demo.guard |
WrongImmutable, WrongContainer |
wrong contracts on purpose: two guard findings, with their why-chain |
As of 2026-10-27 (regenerated after the fixes of that day), so that a missing hint is not mistaken for a broken plugin:
- Nullability: a public parameter whose method accepts null without failing is
@Nullable, even when no call passes null (maddi-mod#68): concatenated (Tags.tag), appended to aStringBuilder(Sentence.word,Report.line), tested for null (Checks.orDefault), or stored where null is already possible (Person.setName). A parameter stored into a field's list that holds no null stays@NotNull(Bag.add).Lookupitself comes out as intended. - Contracts the analyzer reads but the IDE does not echo:
@UtilityClass(ListTools),@Commutable(Ranges),@AllowsInterrupt(Worker). - Not used by the analyzer at all:
@Singleton(Clock),@ExtensionClass(Strings),@BeforeMark;@Docstringis documentation, not analysis.