Skip to content

Make Eclipse and AspectJ compilers run on JDK 11 again #358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plexus-compilers/plexus-compiler-aspectj/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<description>AspectJ Compiler support for Plexus Compiler component.</description>

<properties>
<javaVersion>17</javaVersion>
<javaVersion>11</javaVersion>
</properties>

<dependencies>
Expand Down
33 changes: 32 additions & 1 deletion plexus-compilers/plexus-compiler-eclipse/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<description>Eclipse Compiler support for Plexus Compiler component.</description>

<properties>
<javaVersion>17</javaVersion>
<javaVersion>11</javaVersion>
</properties>

<dependencies>
Expand Down Expand Up @@ -57,4 +57,35 @@
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<excludes>
<exclude>**/EclipseJavaCompilerDelegate.java</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>compile-java-17</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>17</release>
<includes>
<include>**/EclipseJavaCompilerDelegate.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
Expand All @@ -52,8 +55,6 @@
import org.codehaus.plexus.compiler.CompilerOutputStyle;
import org.codehaus.plexus.compiler.CompilerResult;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.jdt.core.compiler.CompilationProgress;
import org.eclipse.jdt.core.compiler.batch.BatchCompiler;

/**
*
Expand All @@ -63,12 +64,28 @@
public class EclipseJavaCompiler extends AbstractCompiler {
public EclipseJavaCompiler() {
super(CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".java", ".class", null);
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.
Class<?> delegateClass = Class.forName("org.codehaus.plexus.compiler.eclipse.EclipseJavaCompilerDelegate");
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType getClassLoaderMT = MethodType.methodType(ClassLoader.class);
MethodType batchCompileMT = MethodType.methodType(boolean.class, List.class, PrintWriter.class);
getClassLoaderMH = lookup.findStatic(delegateClass, "getClassLoader", getClassLoaderMT);
batchCompileMH = lookup.findStatic(delegateClass, "batchCompile", batchCompileMT);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}

// ----------------------------------------------------------------------
// Compiler Implementation
// ----------------------------------------------------------------------
static boolean isJdkSupported = Runtime.version().feature() >= 17;
boolean errorsAsWarnings = false;
private MethodHandle getClassLoaderMH;
private MethodHandle batchCompileMH;

@Override
public String getCompilerId() {
Expand All @@ -77,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 @@ -324,31 +344,15 @@ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {

getLog().debug("ecj command line: " + args);

success = BatchCompiler.compile(
args.toArray(new String[args.size()]), devNull, devNull, new CompilationProgress() {
@Override
public void begin(int i) {}

@Override
public void done() {}

@Override
public boolean isCanceled() {
return false;
}

@Override
public void setTaskName(String s) {}

@Override
public void worked(int i, int i1) {}
});
success = (boolean) batchCompileMH.invoke(args, devNull);
getLog().debug(sw.toString());

if (errorF.length() < 80) {
throw new EcjFailureException(sw.toString());
}
messageList = new EcjResponseParser().parse(errorF, errorsAsWarnings);
} catch (Throwable e) {
throw new Exception(e);
} finally {
if (null != errorF) {
try {
Expand Down Expand Up @@ -507,15 +511,19 @@ private static boolean haveSourceOrReleaseArgument(List<String> args) {
return false;
}

private JavaCompiler getEcj() {
ServiceLoader<JavaCompiler> javaCompilerLoader =
ServiceLoader.load(JavaCompiler.class, BatchCompiler.class.getClassLoader());
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();
} catch (Throwable e) {
throw new RuntimeException(e);
}
ServiceLoader<JavaCompiler> javaCompilerLoader = ServiceLoader.load(JavaCompiler.class, classLoader);
Class<?> c = null;
try {
c = Class.forName(
"org.eclipse.jdt.internal.compiler.tool.EclipseCompiler",
false,
BatchCompiler.class.getClassLoader());
c = Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompiler", false, classLoader);
} catch (ClassNotFoundException e) {
// Ignore
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.codehaus.plexus.compiler.eclipse;

import java.io.PrintWriter;
import java.util.List;

import org.eclipse.jdt.core.compiler.CompilationProgress;
import org.eclipse.jdt.core.compiler.batch.BatchCompiler;

/**
* Wraps API calls involving Java 17 class files from ECJ. {@link EclipseJavaCompiler} delegates to this class.
* <p>
* <b>Note:</b> This class needs to be compiled with target 17, while all the other classes in this module can be
* compiled with target 11, as long as they do not directly import this class but use {@link Class#forName(String)} and
* method handles to invoke any methods from here.
*/
public class EclipseJavaCompilerDelegate {
static ClassLoader getClassLoader() {
return BatchCompiler.class.getClassLoader();
}

static boolean batchCompile(List<String> args, PrintWriter devNull) {
return BatchCompiler.compile(
args.toArray(new String[0]), devNull, devNull, new BatchCompilerCompilationProgress());
}

private static class BatchCompilerCompilationProgress extends CompilationProgress {
@Override
public void begin(int i) {}

@Override
public void done() {}

@Override
public boolean isCanceled() {
return false;
}

@Override
public void setTaskName(String s) {}

@Override
public void worked(int i, int i1) {}
}
}
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;
}
}
11 changes: 10 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-java</id>
<id>enforce-maven-and-java-bytecode</id>
<goals>
<goal>enforce</goal>
</goals>
Expand All @@ -192,6 +192,15 @@
<version>[17,)</version>
<message>[ERROR] OLD JDK [${java.version}] in use. This projects requires JDK 17 or newer</message>
</requireJavaVersion>
<enforceBytecodeVersion>
<maxJdkVersion>11</maxJdkVersion>
<excludes>
<!-- Java 17 -->
<exclude>org.aspectj:aspectjtools</exclude>
<exclude>org.eclipse.jdt:ecj</exclude>
<exclude>org.codehaus.plexus:plexus-compiler-eclipse</exclude>
</excludes>
</enforceBytecodeVersion>
</rules>
</configuration>
</execution>
Expand Down