From e9cc473a366158c5d188cd4e2038c32d24c6dec8 Mon Sep 17 00:00:00 2001 From: Hermann Czedik-Eysenberg Date: Wed, 29 Apr 2026 22:05:43 +0200 Subject: [PATCH 1/6] Upgrade NullAway version to 0.12.15 --- pom.xml | 2 +- .../java/com/github/erroraway/rules/ErrorAwayRulesMapping.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index fb9df45..5ad2535 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 5.6.0.2578 2.42.0 - 0.12.7 + 0.12.15 0.1.29 0.25.0 diff --git a/sonar-erroraway-lib/src/main/java/com/github/erroraway/rules/ErrorAwayRulesMapping.java b/sonar-erroraway-lib/src/main/java/com/github/erroraway/rules/ErrorAwayRulesMapping.java index cd372f7..f14065c 100644 --- a/sonar-erroraway-lib/src/main/java/com/github/erroraway/rules/ErrorAwayRulesMapping.java +++ b/sonar-erroraway-lib/src/main/java/com/github/erroraway/rules/ErrorAwayRulesMapping.java @@ -35,7 +35,7 @@ public final class ErrorAwayRulesMapping { public static final String PICNIC_REPOSITORY = "picnic-errorprone"; public static final int ERRORPRONE_REPOSITORY_RULES_COUNT = 475; - public static final int NULLAWAY_REPOSITORY_RULES_COUNT = 1; + public static final int NULLAWAY_REPOSITORY_RULES_COUNT = 2; public static final int ERRORPRONE_SLF4J_REPOSITORY_RULES_COUNT = 8; public static final int PICNIC_REPOSITORY_RULES_COUNT = 45; From f32b98fa91aaf41e67863746bdfc7e7931ddfdde Mon Sep 17 00:00:00 2001 From: Hermann Czedik-Eysenberg Date: Wed, 29 Apr 2026 22:07:38 +0200 Subject: [PATCH 2/6] Upgrade sonar-packaging-maven-plugin from 1.21.0.505 to 1.23.0.740 Version 1.21.0.505 silently ignores the configuration, resulting in a missing Plugin-RequiredForLanguages manifest entry. This caused the scanner to skip downloading the plugin when not all plugins are fetched (the default behavior). --- sonar-erroraway-sonar-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-erroraway-sonar-plugin/pom.xml b/sonar-erroraway-sonar-plugin/pom.xml index 54de820..ea40894 100644 --- a/sonar-erroraway-sonar-plugin/pom.xml +++ b/sonar-erroraway-sonar-plugin/pom.xml @@ -236,7 +236,7 @@ org.sonarsource.sonar-packaging-maven-plugin sonar-packaging-maven-plugin - 1.21.0.505 + 1.23.0.740 true errorawaysonar From 3f9c0c6e7c9edba5ba4ddf7f4d2ca1d360e7a2be Mon Sep 17 00:00:00 2001 From: Hermann Czedik-Eysenberg Date: Wed, 29 Apr 2026 22:17:11 +0200 Subject: [PATCH 3/6] Fix rule-to-repository mapping for plugin checkers The previous findRepository implementation used a switch statement that only matched "NullAway" literally, plus heuristics for Slf4j (prefix) and Picnic (URL in message). Any other plugin checker fell through to the default "errorprone" repository, causing its issues to be silently dropped. This broke the RequireExplicitNullMarking checker (added in NullAway 0.12.15) which belongs to the "nullaway" repository but was mapped to "errorprone", so its issues were never saved. Replace with a static lookup map built from ServiceLoader-registered plugin checkers, which correctly maps all checkers to their repository. --- .../ErrorAwayDiagnosticListener.java | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayDiagnosticListener.java b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayDiagnosticListener.java index 005b92f..41005b9 100644 --- a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayDiagnosticListener.java +++ b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayDiagnosticListener.java @@ -15,7 +15,11 @@ */ package com.github.erroraway.sonarqube; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; import java.util.Locale; +import java.util.Map; import java.util.Set; import javax.tools.Diagnostic; @@ -36,6 +40,8 @@ import com.github.erroraway.ErrorAwayException; import com.github.erroraway.rules.ErrorAwayRulesMapping; +import com.google.errorprone.BugCheckerInfo; +import com.google.errorprone.bugpatterns.BugChecker; /** * @author Guillaume @@ -44,6 +50,8 @@ public class ErrorAwayDiagnosticListener implements DiagnosticListener { private static final Logger LOGGER = LoggerFactory.getLogger(ErrorAwayDiagnosticListener.class); + private static final Map PLUGIN_RULE_REPOSITORY_MAP = buildPluginRuleRepositoryMap(); + public static final String ERROR_PRONE_COMPILER_CRASH_CODE = "compiler.err.error.prone.crash"; private static final Set ERROR_PRONE_DIAGNOSTIC_CODES = Set.of("compiler.warn.error.prone", "compiler.err.error.prone", @@ -62,7 +70,7 @@ public void report(Diagnostic diagnostic) { String message = diagnostic.getMessage(Locale.ENGLISH); String rule = parseRule(diagnostic, message); - RuleKey ruleKey = RuleKey.of(findRepository(rule, message), rule); + RuleKey ruleKey = RuleKey.of(findRepository(rule), rule); int startLine = (int) diagnostic.getLineNumber(); @@ -156,18 +164,20 @@ private String parseRule(Diagnostic diagnostic, String } } - private String findRepository(String rule, String message) { - if (rule.startsWith("Slf4j")) { - return ErrorAwayRulesMapping.ERRORPRONE_SLF4J_REPOSITORY; - } - - if (message.contains("see https://error-prone.picnic.tech/bugpatterns/")) { - return ErrorAwayRulesMapping.PICNIC_REPOSITORY; - } + private String findRepository(String rule) { + String repository = PLUGIN_RULE_REPOSITORY_MAP.get(rule); + return repository != null ? repository : ErrorAwayRulesMapping.ERRORPRONE_REPOSITORY; + } - return switch (rule) { - case "NullAway" -> ErrorAwayRulesMapping.NULLAWAY_REPOSITORY; - default ->ErrorAwayRulesMapping.ERRORPRONE_REPOSITORY; - }; + private static Map buildPluginRuleRepositoryMap() { + Map map = new HashMap<>(); + Iterator checkers = ErrorAwayRulesMapping.pluginCheckers(); + while (checkers.hasNext()) { + BugChecker checker = checkers.next(); + String repo = ErrorAwayRulesMapping.repository(checker.getClass()); + String ruleKey = BugCheckerInfo.create(checker.getClass()).canonicalName(); + map.put(ruleKey, repo); + } + return Collections.unmodifiableMap(map); } } \ No newline at end of file From 1b63084537714b1b205ac7e4d7d864b72b9ea719 Mon Sep 17 00:00:00 2001 From: Hermann Czedik-Eysenberg Date: Wed, 29 Apr 2026 23:48:27 +0200 Subject: [PATCH 4/6] Fix sensor descriptor to register all rule repositories at once createIssuesForRuleRepository() has replacement semantics, so calling it in a loop left only the last repository registered, preventing the sensor from executing for most rule repositories. --- .../java/com/github/erroraway/sonarqube/ErrorAwaySensor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java index 5848ae7..81b563e 100644 --- a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java +++ b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java @@ -220,9 +220,8 @@ private void addErrorProneCheckers(SensorContext context, List Date: Wed, 29 Apr 2026 23:53:16 +0200 Subject: [PATCH 5/6] Add OnlyNullMarked option and support RequireExplicitNullMarking checker Add a boolean OnlyNullMarked configuration option so NullAway only checks code within @NullMarked scope. When enabled, package-scope options (AnnotatedPackages, UnannotatedSubPackages) are skipped. Support dual-key property reading: server-side key (e.g. nullaway.only.null.marked) and sonar.*-prefixed analysis parameter key (sonar.nullaway.only.null.marked), since the scanner only forwards sonar.* properties from build tools. Enable the RequireExplicitNullMarking checker (SUGGESTION severity) to produce diagnostics by overriding it to WARN level, which avoids a classloader issue with ErrorProne's auto-fix patch generation. --- .../erroraway/sonarqube/ErrorAwayPlugin.java | 13 ++-- .../erroraway/sonarqube/ErrorAwaySensor.java | 69 ++++++++++++++++--- .../erroraway/sonarqube/NullAwayOption.java | 53 ++++++++++++-- 3 files changed, 116 insertions(+), 19 deletions(-) diff --git a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayPlugin.java b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayPlugin.java index 62f78cd..41d9821 100644 --- a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayPlugin.java +++ b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwayPlugin.java @@ -108,14 +108,19 @@ public void define(Context context) { .build()); for (NullAwayOption option : NullAwayOption.values()) { - context.addExtension(PropertyDefinition + PropertyDefinition.Builder builder = PropertyDefinition .builder(option.getKey()) .name(option.getName()) .description(option.getDescription()) .category(PROPERTY_NULLAWAY_CATEGORY) - .onQualifiers(Qualifiers.PROJECT) - .multiValues(true) - .build()); + .onQualifiers(Qualifiers.PROJECT); + + switch (option.getType()) { + case BOOLEAN -> builder.type(PropertyType.BOOLEAN); + case STRING_ARRAY -> builder.multiValues(true); + } + + context.addExtension(builder.build()); } context.addExtension(ErrorAwayRulesDefinition.class); diff --git a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java index 81b563e..b822dba 100644 --- a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java +++ b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/ErrorAwaySensor.java @@ -51,6 +51,7 @@ import com.github.erroraway.ErrorAwayException; import com.github.erroraway.rules.ErrorAwayRulesMapping; import com.google.errorprone.BugCheckerInfo; +import com.google.errorprone.BugPattern; import com.google.errorprone.ErrorProneJavaCompiler; import com.google.errorprone.ErrorProneOptions; import com.google.errorprone.bugpatterns.BugChecker; @@ -92,7 +93,7 @@ public void execute(SensorContext context) { } // Compiler options - ErrorProneOptions errorProneOptions = buildErrorProneOptions(context); + ErrorProneOptions errorProneOptions = buildErrorProneOptions(context, checkers); List javacOptions = buildJavacOptions(); // Setup the compiler and analyze the code @@ -121,14 +122,16 @@ public void execute(SensorContext context) { } } - private ErrorProneOptions buildErrorProneOptions(SensorContext context) { + private ErrorProneOptions buildErrorProneOptions(SensorContext context, List> checkers) { Configuration configuration = context.config(); List options = new ArrayList<>(); + boolean onlyNullMarked = getBoolean(configuration, NullAwayOption.ONLY_NULL_MARKED); + // Fail here if the option was not set instead a showing a giant stacktrace - if (!configuration.hasKey(NullAwayOption.ANNOTATED_PACKAGES.getKey())) { + if (!onlyNullMarked && !hasOption(configuration, NullAwayOption.ANNOTATED_PACKAGES)) { if (context.activeRules().find(RuleKey.of("nullaway", "NullAway")) != null) { - throw new ErrorAwayException("The " + NullAwayOption.ANNOTATED_PACKAGES.getKey() + " option must be set when the NullAway rule is enabled"); + throw new ErrorAwayException("The " + NullAwayOption.ANNOTATED_PACKAGES.getKey() + " option must be set when the NullAway rule is enabled (unless " + NullAwayOption.ONLY_NULL_MARKED.getKey() + " is set)"); } // When some annotation processors are enabled com.google.errorprone.ErrorPronePlugins turns on plugin @@ -139,18 +142,68 @@ private ErrorProneOptions buildErrorProneOptions(SensorContext context) { } for (NullAwayOption option : NullAwayOption.values()) { - String key = option.getKey(); + // In OnlyNullMarked mode, skip package-scope options since NullAway would check + // both scopes if both are set + if (onlyNullMarked && option.isPackageScopeOption()) { + continue; + } - if (configuration.hasKey(key)) { - String[] values = configuration.getStringArray(key); + if (hasOption(configuration, option)) { + switch (option.getType()) { + case BOOLEAN -> { + if (getBoolean(configuration, option)) { + options.add("-XepOpt:NullAway:" + option.getErrorproneOption() + "=true"); + } + } + case STRING_ARRAY -> { + String[] values = getStringArray(configuration, option); + options.add("-XepOpt:NullAway:" + option.getErrorproneOption() + "=" + String.join(",", values)); + } + } + } + } - options.add("-XepOpt:NullAway:" + option.getErrorproneOption() + "=" + String.join(",", values)); + // Override SUGGESTION-level checkers to WARN so they produce diagnostics. + // At SUGGESTION severity, ErrorProne attempts to generate auto-fix patches which requires + // com.sun.source.tree.Tree — inaccessible from the SonarQube plugin classloader. + // This crashes the entire compilation, suppressing all diagnostics from all checkers. + for (Class checker : checkers) { + BugCheckerInfo info = BugCheckerInfo.create(checker); + if (info.defaultSeverity() == BugPattern.SeverityLevel.SUGGESTION) { + options.add("-Xep:" + info.canonicalName() + ":WARN"); } } return ErrorProneOptions.processArgs(options); } + /** + * Checks if an option is set, looking at both the server-side key and the + * analysis parameter key (sonar. prefixed). + */ + private boolean hasOption(Configuration configuration, NullAwayOption option) { + return configuration.hasKey(option.getKey()) || configuration.hasKey(option.getAnalysisParameterKey()); + } + + /** + * Reads a boolean option, checking both the server-side key and the analysis parameter key. + */ + private boolean getBoolean(Configuration configuration, NullAwayOption option) { + return configuration.getBoolean(option.getKey()).orElse(false) + || configuration.getBoolean(option.getAnalysisParameterKey()).orElse(false); + } + + /** + * Reads a string array option, preferring the analysis parameter key over the server-side key. + */ + private String[] getStringArray(Configuration configuration, NullAwayOption option) { + String[] values = configuration.getStringArray(option.getAnalysisParameterKey()); + if (values != null && values.length > 0) { + return values; + } + return configuration.getStringArray(option.getKey()); + } + private List buildJavacOptions() { List options = new ArrayList<>(); diff --git a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/NullAwayOption.java b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/NullAwayOption.java index 71940be..0bf6dee 100644 --- a/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/NullAwayOption.java +++ b/sonar-erroraway-sonar-plugin/src/main/java/com/github/erroraway/sonarqube/NullAwayOption.java @@ -24,40 +24,58 @@ public enum NullAwayOption { "AnnotatedPackages", "nullaway.annotated.packages", "Annotated Packages", - "The list of annotated packages for NullAway"), + "The list of annotated packages for NullAway", + OptionType.STRING_ARRAY), UNANNOTATED_PACKAGES( "UnannotatedSubPackages", "nullaway.unannotated.packages", "Annotated Packages", - "The list of unannotated packages to be excluded from the annotated package list for NullAway"), + "The list of unannotated packages to be excluded from the annotated package list for NullAway", + OptionType.STRING_ARRAY), UNANNOTATED_CLASSES( "UnannotatedSubPackages", "nullaway.unannotated.classes", "Annotated Classes", - "The list of classes within annotated packages to be treated as unannotated for NullAway"), + "The list of classes within annotated packages to be treated as unannotated for NullAway", + OptionType.STRING_ARRAY), KNOWN_INITIALIZERS( "KnownInitializers", "nullaway.known.initializers", "Known Initializers", - "The fully qualified nam of method that NullAway should treat as initializers"), + "The fully qualified nam of method that NullAway should treat as initializers", + OptionType.STRING_ARRAY), EXCLUDED_FIELD_ANNOTATIONS( "ExcludedFieldAnnotations", "nullaway.field.annotations", "Excluded Field Annotations", - "A list of annotations that cause fields to be excluded from being checked for proper initialization"), + "A list of annotations that cause fields to be excluded from being checked for proper initialization", + OptionType.STRING_ARRAY), + ONLY_NULL_MARKED( + "OnlyNullMarked", + "nullaway.only.null.marked", + "Only NullMarked", + "When enabled, NullAway only checks code within @NullMarked scope", + OptionType.BOOLEAN), ; + public enum OptionType { + BOOLEAN, + STRING_ARRAY + } + private final String errorproneOption; private final String key; private final String name; - private String description; + private final String description; + private final OptionType type; - private NullAwayOption(String errorproneOption, String key, String name, String description) { + private NullAwayOption(String errorproneOption, String key, String name, String description, OptionType type) { this.errorproneOption = errorproneOption; this.key = key; this.name = name; this.description = description; + this.type = type; } public String getErrorproneOption() { @@ -68,6 +86,15 @@ public String getKey() { return key; } + /** + * Returns the key prefixed with "sonar." for use as an analysis parameter. + * The SonarQube scanner only forwards properties with the "sonar." prefix from + * build tools (Gradle/Maven). Server-side settings use {@link #getKey()}. + */ + public String getAnalysisParameterKey() { + return "sonar." + key; + } + public String getName() { return name; } @@ -75,4 +102,16 @@ public String getName() { public String getDescription() { return description; } + + public OptionType getType() { + return type; + } + + /** + * Returns true if this option defines package-level scope for NullAway analysis. + * These options are irrelevant in OnlyNullMarked mode. + */ + public boolean isPackageScopeOption() { + return this == ANNOTATED_PACKAGES || this == UNANNOTATED_PACKAGES || this == UNANNOTATED_CLASSES; + } } From ff703ee31976d2bf3cf8c2afce90dda642d24ade Mon Sep 17 00:00:00 2001 From: Hermann Czedik-Eysenberg Date: Thu, 30 Apr 2026 00:01:26 +0200 Subject: [PATCH 6/6] Update documentation - Corrected JDK requirement (17+, not 11+) - Added SonarQube 26.x to compatibility - New Configuration section explaining both server-side and build-tool keys (with sonar. prefix) - Full table of all NullAway options including the new only.null.marked - Full table of all ErrorAway options - Concise error message example - Fixed the "SonarQybe" typo --- README.md | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ad77b8a..326104f 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,13 @@ Additionally, some Error Prone plugins are included: ## Usage -Enable a quality profile including some rules, for NullAway you will need to configure the list of annotated packages +Enable a quality profile including some rules from the Error Prone, NullAway, SLF4J, or Picnic repositories. ## Compatibility -The plugin is compatible with SonarQube from version 9.9 LTS through 10.x and 25.x +The plugin is compatible with SonarQube 9.9 LTS, 10.x, 25.x, and 26.x. -The Sonar analyzer and Error Prone must run on JDK 11 or newer but can analyze Java 8 code. -When running on JDK 16 or newer add the following options due to [JEP 396](https://openjdk.java.net/jeps/396): +The analysis must run on JDK 17 or newer. Due to [JEP 396](https://openjdk.java.net/jeps/396), the following JVM options are required for the scanner process: ``` --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED @@ -32,24 +31,43 @@ When running on JDK 16 or newer add the following options due to [JEP 396](https --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED ``` -See [.mvn/jvm.config](sonar-erroraway-sonar-plugin/src/test/resources/projects/simple/.mvn/jvm.config) for a way to do it with Maven and [gradle.properties](sonar-erroraway-sonar-plugin/src/test/resources/projects/simple/gradle.properties) for a way to do it with Gradle +See [.mvn/jvm.config](sonar-erroraway-sonar-plugin/src/test/resources/projects/simple/.mvn/jvm.config) for Maven and [gradle.properties](sonar-erroraway-sonar-plugin/src/test/resources/projects/simple/gradle.properties) for Gradle examples. -From SonarQybe 10.6 the scanner also auto provisions a JRE and runs the analysis off that JVM. Since the JRE does not include the required compiler module, this needs to be disabled with `sonar.scanner.skipJreProvisioning=true`. +From SonarQube 10.6, the scanner auto-provisions a JRE without the `jdk.compiler` module. Disable this with `sonar.scanner.skipJreProvisioning=true`. -When these options are not set you will receive errors: +Without these options you will see: ``` -Exception in thread "main" java.util.ServiceConfigurationError: com.google.errorprone.bugpatterns.BugChecker: Provider ... could not be instantiated -... -Caused by: java.lang.IllegalAccessError: class ... (in unnamed module @...) cannot access class com.sun.tools.javac.code.Symbol (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.code to unnamed module @... +java.lang.IllegalAccessError: ... cannot access class com.sun.tools.javac.code.Symbol (in module jdk.compiler) ``` -## NullAway configuration - -NullAway needs to be configured with the `nullaway.annotated.packages` option, for instance: - -``` -nullaway.annotated.packages=com.foo,org.bar -``` +## Configuration + +Options can be set in two places: +1. **SonarQube Server** — under Project Settings, use the keys listed below. +2. **Build tool** (Gradle/Maven) — prefix the key with `sonar.` (e.g. `sonar.nullaway.annotated.packages`). The scanner only forwards `sonar.*` properties from build tools. + +### NullAway options + +| Key | Type | Description | +|-----|------|-------------| +| `nullaway.annotated.packages` | multi-value | Packages to check for null safety. Required unless `nullaway.only.null.marked` is set. | +| `nullaway.unannotated.packages` | multi-value | Sub-packages to exclude from the annotated package list. | +| `nullaway.unannotated.classes` | multi-value | Classes within annotated packages to treat as unannotated. | +| `nullaway.known.initializers` | multi-value | Fully qualified method names that NullAway should treat as initializers. | +| `nullaway.field.annotations` | multi-value | Annotations that exclude fields from initialization checks. | +| `nullaway.only.null.marked` | boolean | Only check code within `@NullMarked` scope. Package-scope options are ignored when enabled. | + +### ErrorAway options + +| Key | Type | Description | +|-----|------|-------------| +| `erroraway.classpath.maven.coordinates` | multi-value | Maven coordinates of dependencies needed to compile the project. | +| `erroraway.annotation.processors.maven.coordinates` | multi-value | Maven coordinates of annotation processors. | +| `erroraway.maven.repositories` | multi-value | Maven remote repository URLs. | +| `erroraway.maven.local.repository` | string | Path to the Maven local repository. | +| `erroraway.maven.user.settings.file` | string | Path to the Maven user settings file. | +| `erroraway.maven.work.offline` | boolean | Let Maven work offline. | +| `erroraway.maven.use.temp.local.repository` | boolean | Use a temporary folder for the Maven local repository. | ## Developing the ErrorAway plugin