diff --git a/acceptance-tests/acceptance-tests-avaje-inject/pom.xml b/acceptance-tests/acceptance-tests-avaje-inject/pom.xml
new file mode 100644
index 000000000..cfe188fc8
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/pom.xml
@@ -0,0 +1,77 @@
+
+
+ 4.0.0
+
+
+ io.github.ascopes.jct
+ acceptance-tests
+ 0.0.1-SNAPSHOT
+ ../pom.xml
+
+
+ acceptance-tests-avaje-inject
+
+
+ 8.10
+
+
+
+
+ ${project.groupId}
+ java-compiler-testing
+ test
+
+
+
+ io.avaje
+ avaje-inject
+ ${avaje-inject.version}
+ test
+
+
+
+ io.avaje
+ avaje-inject-generator
+ ${avaje-inject.version}
+ test
+
+
+
+ org.apache.groovy
+ groovy
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ true
+
+
+
+
+
diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/groovy/io/github/ascopes/jct/acceptancetests/avajeinject/AvajeInjectTest.groovy b/acceptance-tests/acceptance-tests-avaje-inject/src/test/groovy/io/github/ascopes/jct/acceptancetests/avajeinject/AvajeInjectTest.groovy
new file mode 100644
index 000000000..f58988d2b
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/groovy/io/github/ascopes/jct/acceptancetests/avajeinject/AvajeInjectTest.groovy
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.github.ascopes.jct.acceptancetests.avajeinject
+
+
+import io.github.ascopes.jct.compilers.JctCompiler
+import io.github.ascopes.jct.filemanagers.LoggingMode
+import io.github.ascopes.jct.junit.JavacCompilerTest
+import io.github.ascopes.jct.workspaces.Workspaces
+import org.junit.jupiter.api.DisplayName
+
+import static io.github.ascopes.jct.assertions.JctAssertions.assertThatCompilation
+
+@DisplayName("Avaje Inject acceptance tests")
+class AvajeInjectTest {
+ @DisplayName("Dependency injection code gets generated as expected")
+ @JavacCompilerTest(modules = true)
+ void dependencyInjectionCodeGetsGeneratedAsExpected(JctCompiler compiler) {
+ // Given
+ try (def workspace = Workspaces.newWorkspace()) {
+ workspace
+ .createSourcePathPackage()
+ .rootDirectory()
+ .copyContentsFrom("src", "test", "resources", "code")
+
+ // When
+ def compilation = compiler
+ .diagnosticLoggingMode(LoggingMode.STACKTRACES)
+ .compile(workspace)
+
+ // Then
+ assertThatCompilation(compilation)
+ .isSuccessfulWithoutWarnings()
+ .classOutput()
+ .packages()
+ .allFilesExist(
+ 'org/example/CoffeeMaker.class',
+ 'org/example/Grinder.class',
+ 'org/example/Pump.class',
+ 'org/example/CoffeeMaker$DI.class',
+ 'org/example/Grinder$DI.class',
+ 'org/example/Pump$DI.class',
+ )
+ }
+ }
+}
diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/module-info.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/module-info.java
new file mode 100644
index 000000000..c4118d411
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/module-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+module org.example {
+ exports org.example;
+
+ requires io.avaje.inject;
+
+ provides io.avaje.inject.spi.Module with org.example.ExampleModule;
+}
diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/CoffeeMaker.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/CoffeeMaker.java
new file mode 100644
index 000000000..c375b4280
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/CoffeeMaker.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+/**
+ * Makes coffee.
+ */
+@Singleton
+public class CoffeeMaker {
+
+ private final Grinder grinder;
+ private final Pump pump;
+
+ @Inject
+ public CoffeeMaker(Grinder grinder, Pump pump) {
+ this.grinder = grinder;
+ this.pump = pump;
+ }
+
+ public void makeCoffee() {
+ // ...
+ }
+}
diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Grinder.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Grinder.java
new file mode 100644
index 000000000..0ea9c93f6
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Grinder.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import jakarta.inject.Singleton;
+
+/**
+ * Grinds coffee.
+ */
+@Singleton
+public class Grinder {
+ // ...
+}
diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Pump.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Pump.java
new file mode 100644
index 000000000..2210b1ac6
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Pump.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import jakarta.inject.Singleton;
+
+/**
+ * Pumps coffee.
+ */
+@Singleton
+public class Pump {
+ // ...
+}
diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/junit-platform.properties b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/junit-platform.properties
new file mode 100644
index 000000000..bcdc4a0f4
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/junit-platform.properties
@@ -0,0 +1,3 @@
+junit.jupiter.execution.parallel.enabled=true
+junit.jupiter.execution.parallel.mode.classes.default=SAME_THREAD
+junit.jupiter.execution.parallel.mode.default=CONCURRENT
diff --git a/acceptance-tests/acceptance-tests-error-prone/pom.xml b/acceptance-tests/acceptance-tests-error-prone/pom.xml
new file mode 100644
index 000000000..5cd83d4ac
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-error-prone/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+
+
+ io.github.ascopes.jct
+ acceptance-tests
+ 0.0.1-SNAPSHOT
+ ../pom.xml
+
+
+ acceptance-tests-error-prone
+
+
+
+ --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
+ --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
+ --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
+ --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
+
+
+ 2.16
+
+
+
+
+ ${project.groupId}
+ java-compiler-testing
+ test
+
+
+
+ com.google.errorprone
+ error_prone_core
+ ${error-prone.version}
+
+
+
+ org.apache.groovy
+ groovy
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ true
+
+
+
+
+
diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/groovy/io/github/ascopes/jct/acceptancetests/errorprone/ErrorProneTest.groovy b/acceptance-tests/acceptance-tests-error-prone/src/test/groovy/io/github/ascopes/jct/acceptancetests/errorprone/ErrorProneTest.groovy
new file mode 100644
index 000000000..a2047132d
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-error-prone/src/test/groovy/io/github/ascopes/jct/acceptancetests/errorprone/ErrorProneTest.groovy
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.github.ascopes.jct.acceptancetests.errorprone
+
+import io.github.ascopes.jct.compilers.JctCompiler
+import io.github.ascopes.jct.junit.JavacCompilerTest
+import io.github.ascopes.jct.workspaces.Workspaces
+import org.junit.jupiter.api.DisplayName
+
+import static io.github.ascopes.jct.assertions.JctAssertions.assertThatCompilation
+
+@DisplayName("Error-prone acceptance tests")
+class ErrorProneTest {
+
+ @DisplayName("Happy paths work as expected")
+ @JavacCompilerTest
+ void happyPathsWorkAsExpected(JctCompiler compiler) {
+ try (def workspace = Workspaces.newWorkspace()) {
+ // Given
+ workspace
+ .createSourcePathPackage()
+ .createDirectory("org", "example")
+ .copyContentsFrom("src", "test", "resources", "code", "nullness", "happy")
+
+ // When
+ def compilation = compiler
+ .addCompilerOptions(
+ "-Xplugin:ErrorProne",
+ "-XDcompilePolicy=simple",
+ )
+ .compile(workspace)
+
+ // Then
+ assertThatCompilation(compilation)
+ .isSuccessfulWithoutWarnings()
+ }
+ }
+
+ @DisplayName("Sad paths fail as expected")
+ @JavacCompilerTest
+ void sadPathsFailAsExpected(JctCompiler compiler) {
+ try (def workspace = Workspaces.newWorkspace()) {
+ // Given
+ workspace
+ .createSourcePathPackage()
+ .createDirectory("org", "example")
+ .copyContentsFrom("src", "test", "resources", "code", "nullness", "sad")
+
+ // When
+ def compilation = compiler
+ .addCompilerOptions(
+ "-Xplugin:ErrorProne",
+ "-XDcompilePolicy=simple",
+ )
+ .compile(workspace)
+
+ // Then
+ assertThatCompilation(compilation)
+ .isFailure()
+ .diagnostics()
+ .errors()
+ .singleElement()
+ .message()
+ .startsWith(
+ "[MustBeClosedChecker] This method returns a resource which must be managed "
+ + "carefully, not just left for garbage collection."
+ )
+ }
+ }
+}
diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/happy/HappyCase.java b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/happy/HappyCase.java
new file mode 100644
index 000000000..7578763f5
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/happy/HappyCase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import com.google.errorprone.annotations.MustBeClosed;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * This should pass error-prone because it always closes an auto-closeable resource.
+ */
+public class HappyCase {
+
+ /**
+ * Do something.
+ *
+ * @param args arguments.
+ * @throws IOException any exception.
+ */
+ public static void main(String[] args) throws IOException {
+ try (InputStream inputStream = inputStream()) {
+ inputStream.read();
+ }
+ }
+
+ @MustBeClosed
+ private static InputStream inputStream() throws IOException {
+ Path tempFile = Files.createTempFile("foo", "bar");
+ return Files.newInputStream(tempFile);
+ }
+}
diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/sad/SadCase.java b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/sad/SadCase.java
new file mode 100644
index 000000000..9505542a2
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/sad/SadCase.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import com.google.errorprone.annotations.MustBeClosed;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * This should fail error-prone because it never closes an auto-closeable resource.
+ */
+public class SadCase {
+
+ /**
+ * Do something.
+ *
+ * @param args arguments.
+ * @throws IOException any exception.
+ */
+ public static void main(String[] args) throws IOException {
+ InputStream inputStream = inputStream();
+ inputStream.read();
+ }
+
+ @MustBeClosed
+ private static InputStream inputStream() throws IOException {
+ Path tempFile = Files.createTempFile("foo", "bar");
+ return Files.newInputStream(tempFile);
+ }
+}
diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/resources/junit-platform.properties b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/junit-platform.properties
new file mode 100644
index 000000000..bcdc4a0f4
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/junit-platform.properties
@@ -0,0 +1,3 @@
+junit.jupiter.execution.parallel.enabled=true
+junit.jupiter.execution.parallel.mode.classes.default=SAME_THREAD
+junit.jupiter.execution.parallel.mode.default=CONCURRENT
diff --git a/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/happy/HappyCase.java b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/happy/HappyCase.java
new file mode 100644
index 000000000..b3660e1f0
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/happy/HappyCase.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/**
+ * This should pass checkerframework.
+ */
+public class HappyCase {
+
+ public static void main(String[] args) {
+ @Nullable String foo = null;
+ System.out.println(foo);
+ }
+}
diff --git a/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/sad/SadCase.java b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/sad/SadCase.java
new file mode 100644
index 000000000..3084eeb8d
--- /dev/null
+++ b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/sad/SadCase.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 - 2022 Ashley Scopes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.example;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+/**
+ * This should fail checkerframework because it assigns a null value to a non-null holder.
+ */
+public class SadCase {
+
+ public static void main(String[] args) {
+ @NonNull String foo = null;
+ System.out.println(foo);
+ }
+}
diff --git a/acceptance-tests/pom.xml b/acceptance-tests/pom.xml
index 0fb824796..b9a8aa2c1 100644
--- a/acceptance-tests/pom.xml
+++ b/acceptance-tests/pom.xml
@@ -15,8 +15,10 @@
pom
+ acceptance-tests-avaje-inject
acceptance-tests-checkerframework
acceptance-tests-dagger
+ acceptance-tests-error-prone
acceptance-tests-google-auto-factory
acceptance-tests-google-auto-service
acceptance-tests-google-auto-value
diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java
index 811e30c91..1ca8d8daf 100644
--- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java
+++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java
@@ -149,7 +149,7 @@ public JctCompilationImpl build() {
);
var outputLines = writer.toString().lines().collect(Collectors.toList());
-
+
if (result == CompilationResult.SKIPPED) {
LOGGER.warn("There was nothing to compile...");
}