Java Design Util (com.github.nbbrd.java-design-util) is a lightweight Java library that provides source-level annotations to document and enforce design decisions at compile time.
It targets Java 8+ and is published to Maven Central under the EUPL license.
The annotations cover:
- Design patterns:
@BuilderPattern,@DecoratorPattern,@FacadePattern,@FlyweightPattern,@PrototypePattern,@Singleton - Type constraints:
@Immutable,@Mutable,@SealedType,@DirectImpl,@Trait,@PrimitiveReplacementOf - Thread-safety:
@ThreadSafe,@NotThreadSafe,@ThreadHostile - Representation:
@RepresentableAs,@RepresentableAsInt,@RepresentableAsString,@StringValue(deprecated) - Method contracts:
@StaticFactoryMethod,@ReturnNew,@ReturnImmutable,@Unsafe,@Demo,@SystemDependent - Lifecycle & intent:
@Development,@Internal,@VisibleForTesting,@MightBePromoted,@MightBeGenerated,@NextJdk,@LombokWorkaround - Value constraints:
@NonNegative - Naming:
@ClassNameConstant - Processing control:
@SkipProcessing - Swing-specific:
@swing.OnEDT,@swing.OnAnyThread
A companion annotation processor validates a subset of these annotations during compilation, emitting errors when structural rules are violated (e.g. @Immutable types must be final with private final fields, @DirectImpl types must not extend a class).
The project is a multi-module Maven build with three modules:
java-design-parent (root POM)
├── java-design-annotation ─ compile-time annotations (no dependencies)
├── java-design-processor ─ annotation processor (shaded jar, depends on annotation module + JavaPoet)
└── java-design-bom ─ Bill of Materials POM for consumers
- Package:
nbbrd.design(+nbbrd.design.swing) - Pure annotation definitions — no runtime dependencies, no annotation processors
- JPMS module name:
nbbrd.design(viaAutomatic-Module-Namemanifest entry) - All annotations use
@Retention(SOURCE)except@Internal(RUNTIME),@PrimitiveReplacementOf,@SystemDependent,@RepresentableAs,@RepresentableAsIntand@RepresentableAsString(CLASS)
- Public package:
nbbrd.design.processor(contains only a placeholder class for Javadoc) - Internal package:
internal.nbbrd.design— oneAbstractProcessorsubclass per validated annotation - Internal utilities:
internal.nbbrd.design.proc— shared processing helpers (Rule,Processing,Processors,Elements2,TypeRules,ExecutableRules) - Processors are registered via
@ServiceProvider(Processor.class)(usingjava-service-util), which generatesMETA-INF/services/javax.annotation.processing.Processor - Validation is rule-based: each processor defines a
Rule<TypeElement>(orRule<Element>) chain that checks structural constraints and reports errors throughMessager - The
@SkipProcessingannotation lets users bypass validation with a documented reason - JavaPoet (
com.squareup:javapoet) is shaded and relocated into the jar to avoid classpath conflicts - Tests use
compile-testing(Google) to verify processor diagnostics against source fixtures
- A
pom-packaged module that declaresdependencyManagementforjava-design-annotationandjava-design-processor - Houses release automation (JReleaser, changelog extraction)
mvn clean install # full build + tests + enforcer checks
mvn clean install -Pyolo # skip all checks (fast local iteration)
mvn test -pl <module-name> -Pyolo # fast test a single module
mvn test -pl <module-name> -am # full test a single module- Java 8 target with JPMS
module-info.javacompiled separately on JDK 9+ (seejava8-with-jpmsprofile in root POM) - JUnit 5 with parallel execution enabled (
junit.jupiter.execution.parallel.enabled=true); AssertJ for assertions heylogs-apipublishes a test-jar (tests/package) reused by extension modules for shared test fixtures
- Lombok: use lombok annotations when possible. Config in
lombok.config:addNullAnnotations=jspecify,builder.className=Builder - Nullability:
@org.jspecify.annotations.Nullablefor nullable;@lombok.NonNullfor non-null parameters. Return types use@Nullableor theOrNullsuffix (e.g.,getThingOrNull) - Design annotations use annotations from
java-design-utilsuch as@VisibleForTesting,@StaticFactoryMethod,@DirectImpl,@MightBeGenerated,@MightBePromoted - Internal packages:
internal.<project>.*are implementation details; public API lives in the root andspipackages - Static analysis:
forbiddenapis(nojdk-unsafe,jdk-deprecated,jdk-internal,jdk-non-portable,jdk-reflection),modernizer - Reproducible builds:
project.build.outputTimestampis set in the root POM - Formatting/style:
- Use IntelliJ IDEA default code style for Java
- Follow existing formatting and match naming conventions exactly
- Follow the principles of "Effective Java"
- Follow the principles of "Clean Code"
- Java/JVM:
- Target version defined in root POM properties; some modules may require higher versions
- Use modern Java feature compatible with defined version
- Do respect existing architecture, coding style, and conventions
- Do prefer minimal, reviewable changes
- Do preserve backward compatibility
- Do not introduce new dependencies without justification
- Do not rewrite large sections for cleanliness
- Do not reformat code
- Do not propose additional features or changes beyond the scope of the task