All notable changes to this project are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Versions 1.0.0 through 1.0.5 were published under the legacy plugin ID
dev.sbs.simplified-annotations and Maven coordinate dev.sbs:simplified-annotations.
Versions 2.0.0 onward are published under dev.simplified.simplified-annotations /
io.github.simplified-dev:annotations. See the 2.0.0 entry for the rename details.
- Namespace migration - the
dev.sbs.*Java packages and thedev.sbs:simplified-annotationsMaven coordinate are retired. New Maven coordinate isio.github.simplified-dev:annotations; the public-API package is nowdev.simplified.annotations.*(plural). The JetBrains plugin is re-published under IDdev.simplified.simplified-annotationswith vendor "Simplified Dev". This is source-breaking for Maven consumers - update imports fromdev.sbs.annotation.*todev.simplified.annotations.*. The legacydev.sbs:simplified-annotations1.x line on Maven Central and the JetBrains plugindev.sbs.simplified-annotationswill receive no further updates; existing installs of the legacy plugin see a one-time redirect notice (1.0.5).
- Automatic
--add-exportsmodule opening - the annotation processor opensjdk.compiler/com.sun.tools.javac.*packages at load time via asun.misc.Unsafe+MethodHandles.Lookup.IMPL_LOOKUPbootstrap (same technique Lombok uses). Consumers no longer need to pass--add-exportsflags in their build configuration. Version-gated viaJavacAccess/JavacAccessFactory/JavacAccessV17mirroring the existingJavacCompatdesign so future JDK hardening is absorbed by a new shim subclass + one gate. - End-to-end
@ClassBuilderruntime showcase - newlibrary/src/showcase/source set packaged as a standalone runnable jar that exercises every runtime-observable configuration of@ClassBuilder+ companions (@BuildRule,@BuildFlag,@ObtainVia,@Collector,@Negate,@Formattable) against real APT-generated builders. A new parameterised JUnit test in:library:testexecs the jar in a fresh JVM and surfaces one Gradle test row per CASE (43 rows), with a sibling coverage-drift assertion. The showcase artifact lives inbuild/showcase/and is deliberately excluded from the Maven Central publication.
- Merged generic field-level annotations into
@BuildRule-@BuilderDefault,@BuilderIgnore,@BuildFlag, and@ObtainViacollapse into a single parent@BuildRule(retainInit = ..., ignore = ..., flag = @BuildFlag(...), obtainVia = @ObtainVia(...)).@BuildFlagand@ObtainViabecome nested-only (@Target({}));@BuildRuleis@Retention(RUNTIME)soBuildFlagValidatorcontinues to reflectively read the nested@BuildFlag. Type-specific companions (@Negate,@Formattable,@Collector) stay standalone. Pre-release, no deprecation aliases - consumers migrate via find-and-replace.
@BuildRule(flag = @BuildFlag(...))runtime validation now actually fires on AST-mutated targets. The generatedbuild()method previously calledBuildFlagValidator.validate(this)against the Builder, whose synthesised fields carry no annotations - so everynonNull/notEmpty/pattern/limit/groupconstraint silently no-op'd on classes and records.build()now constructs the target first, validates it, then returns. Same fix mirrored in the sibling-emitter path used for interface targets. Surfaced by the new showcase harness.@BuildRule(retainInit = true)is now honoured on the AST-mutation path (classes and records). Previously only the sibling-emitter path used for interface targets supported it. Implemented via a private static$default$<fieldName>()provider injected onto the target class - the provider holds a deep-cloned copy of the original initializer expression withsym/type/pospointers reset so javac re-attributes it inside the method body's scope, and the generated Builder's field default becomes a static call to that provider. Supports arbitrary expressions (UUID.randomUUID(),new ArrayList<>(),List.of(...), ternaries, field accesses, etc.) and evaluates them fresh on everybuild()invocation.
@BuilderDefaultand@BuilderIgnore- replaced by@BuildRule(retainInit = true)and@BuildRule(ignore = true)respectively.
- Auto-generated bootstrap methods -
builder(),from(T), andmutate()are now injected on the annotated type automatically. Hand-written methods with the same name and arity win (skip-on-collision +Kind.NOTE). The bootstrap-methods inspection is retired. - SuperBuilder for abstract classes -
@ClassBuilderon an abstract class produces a self-typedBuilder<T extends Target, B extends Builder<T, B>>with abstractbuild()andself(). Concrete subclasses carrying@ClassBuilderautomatically inherit the parent's builder (class Builder extends Super.Builder<ThisType, ThisType.Builder>), overrideself()andbuild(), and get a protected copy constructor. Opt out withgenerateCopyConstructor = false. - IDE augmentation - a new
PsiAugmentProvidersurfaces the injected bootstrap methods to the PSI layer, so autocompletion, goto-symbol, and type resolution all work before the first javac round. A gutter icon (replaceable SVG at/icons/classbuilder_generated.svg) marks every@ClassBuilderannotation. - Multi-JDK support - versioned compat layer under
dev.simplified.classbuilder.mutate.compatwith a singlev17baseline dispatched byRuntime.version().feature(). aptTest matrix covers JDK 17, 21, and 25.
- AST-mutation pivot -
@ClassBuildernow injects apublic static class Builderdirectly into the annotated class via javac AST mutation rather than emitting a sibling<TypeName>Builder.java. Interface targets still emit sibling<Name>Impl.java+<Name>Builder.javasince there is no in-source mutation surface on an interface body. - Consumer requirement - javac-only (ecj not supported). Consumers' builds need
--add-exports=jdk.compiler/com.sun.tools.javac.*=ALL-UNNAMEDon compile; seebuild.gradle.ktsfor the full list. - Gradle 9.4.1 - wrapper bumped so JDK 25 is natively supported without toolchain workarounds; unused Kotlin JVM plugin dropped.
- New @ClassBuilder annotation - generates a sibling
<TypeName>Builder.javavia a JSR 269 annotation processor. Supports classes, records, and interfaces (interfaces also get a matching<Name>Impl). Full Lombok@Builderparity plus opinionated extras: configurable method prefix,builderName/builderMethodName/buildMethodName/fromMethodName/toBuilderMethodName, generatedfrom(T)+mutate(), and emitted@XContracton every setter so IDE data-flow understands fresh-object and this-return shapes. - New field-level companions -
@Collector(collection/map varargs + iterable bulk overloads, with opt-in single-element add/put, clear, and lazy put-if-absent for maps),@Negate(paired inverse boolean setters),@Formattable(@PrintFormatoverloads with null-tolerant variants forOptional<String>fields),@BuilderDefault,@BuilderIgnore,@ObtainVia. - @BuilderDefault source-initializer copying - the generated builder now reproduces the field's declared initializer verbatim, with type references (e.g.
UUID.randomUUID(),List.of(...)) auto-imported. Reports a compile error if@BuilderDefaultis applied to a field with no initializer. - @ObtainVia accessor redirection - the generated
from(T)honoursmethod,field, andisStatic, so builders can reconstruct from types that don't expose a standard getter. - New @BuildFlag runtime validator - enforces
nonNull,notEmpty,groupmutual-requirement, regexpattern, and length/sizelimitconstraints in the generatedbuild(). Zero external dependencies. - New ClassBuilder bootstrap inspection - ERROR-severity check that the three bootstrap methods (
builder()/from(T)/mutate()) are materialised on the annotated class, with a quick-fix that inserts them all at once with matching@XContractannotations. - New ClassBuilder field inspection - flags misuse of the companion annotations (e.g.
@Formattableon a non-String field) at source-edit time.
- @XContract annotation - superset of JetBrains
@Contractwith relational comparisons,&&/||grouping, named-parameter references,instanceofchecks, typedthrowsreturns, chained comparisons, and fullpure/mutatessupport. A synthetic@Contractis inferred so IntelliJ data-flow works from a single annotation. - XContract Call-Site inspection - flags calls whose literal arguments deterministically trigger a
failorthrowsclause. - ResourcePath Base-Prefix Usage inspection - warns when a
@ResourcePath(base="X")parameter is passed raw into a resource-loading call, with a quick-fix that prependsX/. Also flags base mismatches across call boundaries. - Settings - additional resource-root paths, glob-based file exclusions, split severity dropdowns, inheritance and mutates checks.
- Modernised PSI listener - narrowed to annotation events only; replaced deprecated
DaemonCodeAnalyzer.restart(PsiFile).
- ResourcePath freeze fix - removed the project-wide
ReferencesSearchthat locked up the IDE on large utility files.
- Plugin moved - final release of the legacy
dev.sbs.simplified-annotationsplugin. Description and change-notes replaced with a redirect notice pointing users at Simplified Annotations by Simplified Dev on the JetBrains Marketplace. No functionality changes; this listing receives no further updates. New installs should use the new plugin IDdev.simplified.simplified-annotations(see 2.0.0 above).
- Heavy lag in 800+ line files - removed an inspection traversal hot path that locked up the IDE on large utility files.
- Inspection settings - persisted highlight-level and enabled-by-default toggles surfaced through
plugin.xmldefaults; settings now round-trip across IDE restarts. - Startup indexing safety net - secondary check during startup so literal-string analysis no longer races the indexing phase on cold-open projects.
- Inspection enabled by default at ERROR severity.
- Method-call inspection code consolidated for readability.
IndexNotReadyExceptionon IDE startup - inspection no longer attempts PSI resolution before the project index is ready.
- Publishing pipeline cleanup - publish directory empties on build to prevent stale-artifact hangs; documentation links added.
- Initial release -
@ResourcePathannotation for fields, parameters, and methods with an optionalbasedirectory prefix. - Resource Path inspection - validates that the resolved string expression at every annotated site refers to a file that exists in the project's source/resource roots. Reports a problem at edit time when the file is missing.
- String expression evaluator - resolves literal string values across literals (
ULiteralExpression), concatenation (UPolyadicExpression), final/static/enum field references, local variable declarations, recursive method-call return values, and UAST local variables. Bounded recursion guards against cycles. - Change-tracking listener - narrow
PsiTreeChangeAdapterkeyed on@ResourcePathannotations, requestingDaemonCodeAnalyzerre-analysis on add/remove/replace events. - Maven Central + JetBrains Marketplace publication - dual-target build producing both a publishable jar (
dev.sbs:simplified-annotations) and a sandboxed plugin distribution (dev.sbs.simplified-annotations). Sources jar, javadoc jar, and signed POM included.