diff --git a/README.md b/README.md
index 00d55078..e1b09426 100644
--- a/README.md
+++ b/README.md
@@ -306,6 +306,24 @@ Or in Maven:
📖 **For complete documentation, examples, and all available options, see the [Configuration Guide](docs/CONFIGURATION.md).**
+#### Strict mode (fail the build on generation errors)
+
+By default, if generation fails (for a builder or for a Jackson module) the processor emits a **compiler warning** and continues, so the build still succeeds. This keeps local/iterative development smooth.
+
+For high-reliability builds (e.g. CI/release pipelines) you can opt in to **strict mode**, which promotes generation failures — including Jackson module generation failures — to **compiler errors** that fail the build:
+
+```bash
+javac -Asimplebuilder.strict=true YourClass.java
+```
+
+```xml
+
+ -Asimplebuilder.strict=true
+
+```
+
+Strict mode is **disabled by default** (`false`); the default behavior (warnings only, build does not fail) is unchanged.
+
## Examples
The `example` module contains real-world examples demonstrating various builder configurations and features. You can explore the source DTOs and their generated builders:
diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/BuilderProcessor.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/BuilderProcessor.java
index 07530341..0373d763 100644
--- a/processor/src/main/java/org/javahelpers/simple/builders/processor/BuilderProcessor.java
+++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/BuilderProcessor.java
@@ -67,6 +67,13 @@ public class BuilderProcessor extends AbstractProcessor {
private JacksonModuleGenerator jacksonModuleGenerator;
private boolean supportedJdk = true;
+ /**
+ * Opt-in strict/fail-fast mode. When enabled (via {@code -Asimplebuilder.strict=true}),
+ * generation failures are reported as compiler errors that fail the build. Defaults to {@code
+ * false} (warnings only, build does not fail).
+ */
+ private boolean strict = false;
+
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
@@ -78,6 +85,9 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
BuilderConfiguration globalConfig = reader.readBuilderConfiguration();
logger.debug("Loaded global configuration from compiler arguments: %s", globalConfig);
+ this.strict = reader.readBooleanValue(CompilerArgumentsEnum.STRICT);
+ logger.debug("Strict generation mode: %s", this.strict);
+
this.context = new ProcessingContext(logger, globalConfig, processingEnv);
this.codeGenerator = new RoasterCodeGenerator(processingEnv, logger);
this.jacksonModuleGenerator = new JacksonModuleGenerator(processingEnv, logger);
@@ -116,9 +126,17 @@ public boolean process(Set extends TypeElement> annotations, RoundEnvironment
try {
codeGenerator.generateClass(moduleClassDef);
} catch (BuilderException e) {
- context.warning(
- "simple-builders: Error generating Jackson module for package %s: %s",
- packageName, e.getMessage());
+ // By default Jackson module generation failures are warnings. In opt-in strict mode
+ // they are promoted to errors that fail the build.
+ if (strict) {
+ context.error(
+ "simple-builders: Error generating Jackson module for package %s: %s",
+ packageName, e.getMessage());
+ } else {
+ context.warning(
+ "simple-builders: Error generating Jackson module for package %s: %s",
+ packageName, e.getMessage());
+ }
}
}
// Reset indentation after Jackson module generation as well
diff --git a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/CompilerArgumentsEnum.java b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/CompilerArgumentsEnum.java
index 01e0ff45..cf40d714 100644
--- a/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/CompilerArgumentsEnum.java
+++ b/processor/src/main/java/org/javahelpers/simple/builders/processor/processing/CompilerArgumentsEnum.java
@@ -131,7 +131,15 @@ public enum CompilerArgumentsEnum {
// === Logging ===
/** Option for verbose logging output. */
- VERBOSE("verbose");
+ VERBOSE("verbose"),
+
+ // === Error Handling ===
+ /**
+ * Option for strict/fail-fast generation mode. When enabled, builder (and Jackson module)
+ * generation failures are reported as compiler errors that fail the build instead of warnings.
+ * Defaults to disabled (warnings only, build does not fail).
+ */
+ STRICT("strict");
/** Compiler option prefix for all simple-builders options. */
private static final String OPTION_PREFIX = "simplebuilder.";
diff --git a/processor/src/test/java/org/javahelpers/simple/builders/processor/JacksonModuleStrictModeTest.java b/processor/src/test/java/org/javahelpers/simple/builders/processor/JacksonModuleStrictModeTest.java
new file mode 100644
index 00000000..439a225d
--- /dev/null
+++ b/processor/src/test/java/org/javahelpers/simple/builders/processor/JacksonModuleStrictModeTest.java
@@ -0,0 +1,93 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2026 Andreas Igel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.javahelpers.simple.builders.processor;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static org.javahelpers.simple.builders.processor.testing.ProcessorTestUtils.createCompiler;
+import static org.javahelpers.simple.builders.processor.testing.ProcessorTestUtils.simpleBuilderClass;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests that the opt-in strict/fail-fast mode ({@code -Asimplebuilder.strict=true}) also governs
+ * Jackson module generation failures.
+ *
+ *
A failure is induced by providing a hand-written class named {@code
+ * SimpleBuildersJacksonModule} in the DTO's package, which collides with the module the processor
+ * generates at the end of processing and makes generation fail with a "already exists" error.
+ */
+class JacksonModuleStrictModeTest {
+
+ private static final String PACKAGE = "pkg.jacksonstrict";
+
+ private JavaFileObject dto() {
+ return simpleBuilderClass(
+ PACKAGE,
+ "JacksonStrictDto",
+ """
+ private String name;
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ """);
+ }
+
+ /** A hand-written class colliding with the generated Jackson module for the package. */
+ private JavaFileObject collidingModule() {
+ return JavaFileObjects.forSourceLines(
+ PACKAGE + ".SimpleBuildersJacksonModule",
+ "package " + PACKAGE + ";",
+ "public class SimpleBuildersJacksonModule {}");
+ }
+
+ @Test
+ void defaultMode_jacksonModuleFailure_isWarning_andCompilationSucceeds() {
+ Compilation compilation =
+ createCompiler()
+ .withOptions(
+ "-Asimplebuilder.generateJacksonModule=true",
+ "-Asimplebuilder.usingJacksonDeserializerAnnotation=true")
+ .compile(dto(), collidingModule());
+
+ assertThat(compilation).succeeded();
+ assertThat(compilation).hadWarningContaining("Error generating Jackson module");
+ }
+
+ @Test
+ void strictMode_jacksonModuleFailure_isError_andCompilationFails() {
+ Compilation compilation =
+ createCompiler()
+ .withOptions(
+ "-Asimplebuilder.generateJacksonModule=true",
+ "-Asimplebuilder.usingJacksonDeserializerAnnotation=true",
+ "-Asimplebuilder.strict=true")
+ .compile(dto(), collidingModule());
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorContaining("Error generating Jackson module");
+ }
+}