Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Throw CompilerException in performCompile|getEcj, not in constructor
This shifts the focus from a supposed Maven component wiring error to the root cause, expressed in the error message: Fatal error compiling: ECJ needs JRE 17+ We need to add safeguards throwing the exception in both methods accessing class EclipseJavaCompilerDelegate, because we cannot predict who calls which one first. Omitting one safeguard might lead to the return of the infamous "No such compiler 'eclipse'" error. The new static boolean field EclipseJavaCompiler.isJdkSupported also enables us to write a simple unit test, asserting on the error message, if the field value is false. Relates to #347.
  • Loading branch information
kriegaex committed Feb 2, 2024
commit 8804303cfd498145f0f441c7afe1df5a1f1eccda
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
public class EclipseJavaCompiler extends AbstractCompiler {
public EclipseJavaCompiler() {
super(CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".java", ".class", null);
if (Runtime.version().feature() < 17) throw new EcjFailureException("ECJ only works on Java 17+");
if (!isJdkSupported) return;
try {
// Do not directly import EclipseJavaCompilerDelegate or any ECJ classes compiled to target 17.
// This ensures that the plugin still runs on Java 11 and can report the error above.
Expand All @@ -82,9 +82,10 @@ public EclipseJavaCompiler() {
// ----------------------------------------------------------------------
// Compiler Implementation
// ----------------------------------------------------------------------
static boolean isJdkSupported = Runtime.version().feature() >= 17;
boolean errorsAsWarnings = false;
private final MethodHandle getClassLoaderMH;
private final MethodHandle batchCompileMH;
private MethodHandle getClassLoaderMH;
private MethodHandle batchCompileMH;

@Override
public String getCompilerId() {
Expand All @@ -93,6 +94,9 @@ public String getCompilerId() {

@Override
public CompilerResult performCompile(CompilerConfiguration config) throws CompilerException {
// Safeguard before using method handle accessing EclipseJavaCompilerDelegate
if (!isJdkSupported) throw new CompilerException("ECJ needs JRE 17+");

List<String> args = new ArrayList<>();
args.add("-noExit"); // Make sure ecj does not System.exit on us 8-/

Expand Down Expand Up @@ -507,7 +511,9 @@ private static boolean haveSourceOrReleaseArgument(List<String> args) {
return false;
}

private JavaCompiler getEcj() {
private JavaCompiler getEcj() throws CompilerException {
// Safeguard before using method handle accessing EclipseJavaCompilerDelegate
if (!isJdkSupported) throw new CompilerException("ECJ needs JRE 17+");
ClassLoader classLoader;
try {
classLoader = (ClassLoader) getClassLoaderMH.invoke();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.codehaus.plexus.compiler.eclipse;

import javax.inject.Inject;
import javax.inject.Named;

import java.io.File;
import java.util.Set;
import java.util.stream.Collectors;

import org.codehaus.plexus.compiler.Compiler;
import org.codehaus.plexus.compiler.CompilerConfiguration;
import org.codehaus.plexus.compiler.CompilerException;
import org.codehaus.plexus.testing.PlexusTest;
import org.codehaus.plexus.util.FileUtils;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;

import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
import static org.junit.jupiter.api.Assertions.assertThrows;

@PlexusTest
@Isolated("changes static variable")
public class EclipseCompilerUnsupportedJdkTest {
static final boolean IS_JDK_SUPPORTED = EclipseJavaCompiler.isJdkSupported;

@Inject
@Named("eclipse")
Compiler compiler;

@BeforeAll
public static void setUpClass() {
EclipseJavaCompiler.isJdkSupported = false;
}

@AfterAll
public static void cleanUpClass() {
EclipseJavaCompiler.isJdkSupported = IS_JDK_SUPPORTED;
}

@Test
public void testUnsupportedJdk() {
CompilerException error = assertThrows(CompilerException.class, () -> compiler.performCompile(getConfig()));
MatcherAssert.assertThat(error.getMessage(), Matchers.containsString("ECJ needs JRE 17+"));
}

private CompilerConfiguration getConfig() throws Exception {
String sourceDir = getBasedir() + "/src/test-input/src/main";
Set<File> sourceFiles = FileUtils.getFileNames(new File(sourceDir), "**/*.java", null, false, true).stream()
.map(File::new)
.collect(Collectors.toSet());
CompilerConfiguration compilerConfig = new CompilerConfiguration();
compilerConfig.addSourceLocation(sourceDir);
compilerConfig.setOutputLocation(getBasedir() + "/target/eclipse/classes");
compilerConfig.setSourceFiles(sourceFiles);
compilerConfig.setTargetVersion("1.8");
compilerConfig.setSourceVersion("1.8");
return compilerConfig;
}
}