Set up Eclipse to work with Java 9 and later

To create .classpath with java 9, run:

  $ tools/eclipse/project.py --java 9

Start Eclipse, and follow the instructions provided in dev-eclipse.txt to
switch to Java 9 or later.

To run gerrit from Eclipse, the system classpath is cast to
URLClassLoader to retrieve the needed JARs. In Java 9 system classpath
cannot be cast to URLClassLoader. To rectify, extract the classpath from
Bazel.

Change-Id: Ie341cd4dfee5520f689fc50f34aa5395b74b5e7d
This commit is contained in:
David Ostrovsky 2018-06-25 23:45:15 +02:00 committed by David Ostrovsky
parent f51cf2323b
commit 8aae31c376
4 changed files with 88 additions and 24 deletions

View File

@ -3,7 +3,7 @@
This document is about configuring Gerrit Code Review into an This document is about configuring Gerrit Code Review into an
Eclipse workspace for development and debugging with GWT. Eclipse workspace for development and debugging with GWT.
Java 6 or later SDK is also required to run GWT's compiler and Java 8 or later SDK is also required to run GWT's compiler and
runtime debugging environment. runtime debugging environment.
@ -49,6 +49,19 @@ the same way you would when
link:dev-build-plugins.html#_bundle_custom_plugin_in_release_war[bundling in release.war] link:dev-build-plugins.html#_bundle_custom_plugin_in_release_war[bundling in release.war]
and run `tools/eclipse/project.py`. and run `tools/eclipse/project.py`.
[[Newer Java versions]]
Java 9 and later are supported, but some adjustments must be done, because
Java 8 is still the default:
* Add JRE, e.g.: directory: /usr/lib64/jvm/java-9-openjdk, name: java-9-openjdk-9
* Change execution environemnt for gerrit project to: JavaSE-9 (java-9-openjdk-9)
* Check that compiler compliance level in gerrit project is set to: 9
* Add this parameter to VM argument for gerrit_daemin launcher:
----
--add-modules java.activation \
--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED
----
[[Formatting]] [[Formatting]]
== Code Formatter Settings == Code Formatter Settings

View File

@ -23,14 +23,15 @@ import com.google.common.flogger.FluentLogger;
import com.google.common.html.HtmlEscapers; import com.google.common.html.HtmlEscapers;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.google.gerrit.common.TimeUtil; import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.launcher.GerritLauncher;
import com.google.gerrit.util.http.CacheHeaders; import com.google.gerrit.util.http.CacheHeaders;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.RawParseUtils;
@ -122,20 +123,19 @@ public class BazelBuild {
} }
} }
private Properties loadBuildProperties(Path propPath) throws IOException {
Properties properties = new Properties();
try (InputStream in = Files.newInputStream(propPath)) {
properties.load(in);
} catch (NoSuchFileException e) {
// Ignore; will be run from PATH, with a descriptive error if it fails.
}
return properties;
}
private ProcessBuilder newBuildProcess(Label label) throws IOException { private ProcessBuilder newBuildProcess(Label label) throws IOException {
Properties properties = loadBuildProperties(sourceRoot.resolve(".bazel_path")); Properties properties = GerritLauncher.loadBuildProperties(sourceRoot.resolve(".bazel_path"));
String bazel = firstNonNull(properties.getProperty("bazel"), "bazel"); String bazel = firstNonNull(properties.getProperty("bazel"), "bazel");
ProcessBuilder proc = new ProcessBuilder(bazel, "build", label.fullName()); List<String> cmd = new ArrayList<>();
cmd.add(bazel);
cmd.add("build");
if (GerritLauncher.isJdk9OrLater()) {
String v = GerritLauncher.getJdkVersionPostJdk8();
cmd.add("--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java" + v);
cmd.add("--java_toolchain=@bazel_tools//tools/jdk:toolchain_java" + v);
}
cmd.add(label.fullName());
ProcessBuilder proc = new ProcessBuilder(cmd);
if (properties.containsKey("PATH")) { if (properties.containsKey("PATH")) {
proc.environment().put("PATH", properties.getProperty("PATH")); proc.environment().put("PATH", properties.getProperty("PATH"));
} }

View File

@ -34,6 +34,7 @@ import java.net.URLClassLoader;
import java.nio.file.FileSystem; import java.nio.file.FileSystem;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.CodeSource; import java.security.CodeSource;
@ -44,6 +45,7 @@ import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Scanner; import java.util.Scanner;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
@ -644,6 +646,25 @@ public final class GerritLauncher {
return resolveInSourceRoot("eclipse-out"); return resolveInSourceRoot("eclipse-out");
} }
public static boolean isJdk9OrLater() {
return Double.parseDouble(System.getProperty("java.class.version")) >= 53.0;
}
public static String getJdkVersionPostJdk8() {
// 9.0.4 => 9
return System.getProperty("java.version").substring(0, 1);
}
public static Properties loadBuildProperties(Path propPath) throws IOException {
Properties properties = new Properties();
try (InputStream in = Files.newInputStream(propPath)) {
properties.load(in);
} catch (NoSuchFileException e) {
// Ignore; will be run from PATH, with a descriptive error if it fails.
}
return properties;
}
static final String SOURCE_ROOT_RESOURCE = "/com/google/gerrit/launcher/workspace-root.txt"; static final String SOURCE_ROOT_RESOURCE = "/com/google/gerrit/launcher/workspace-root.txt";
/** /**
@ -708,14 +729,36 @@ public final class GerritLauncher {
return ret; return ret;
} }
private static ClassLoader useDevClasspath() throws MalformedURLException, FileNotFoundException { private static ClassLoader useDevClasspath() throws IOException {
Path out = getDeveloperEclipseOut(); Path out = getDeveloperEclipseOut();
List<URL> dirs = new ArrayList<>(); List<URL> dirs = new ArrayList<>();
dirs.add(out.resolve("classes").toUri().toURL()); dirs.add(out.resolve("classes").toUri().toURL());
ClassLoader cl = GerritLauncher.class.getClassLoader(); ClassLoader cl = GerritLauncher.class.getClassLoader();
for (URL u : ((URLClassLoader) cl).getURLs()) {
if (includeJar(u)) { if (isJdk9OrLater()) {
dirs.add(u); Path rootPath = resolveInSourceRoot(".").normalize();
Properties properties = loadBuildProperties(rootPath.resolve(".bazel_path"));
Path outputBase = Paths.get(properties.getProperty("output_base"));
Path runtimeClasspath =
rootPath.resolve("bazel-bin/tools/eclipse/main_classpath_collect.runtime_classpath");
for (String f : Files.readAllLines(runtimeClasspath, UTF_8)) {
URL url;
if (f.startsWith("external")) {
url = outputBase.resolve(f).toUri().toURL();
} else {
url = rootPath.resolve(f).toUri().toURL();
}
if (includeJar(url)) {
dirs.add(url);
}
}
} else {
for (URL u : ((URLClassLoader) cl).getURLs()) {
if (includeJar(u)) {
dirs.add(u);
}
} }
} }
return URLClassLoader.newInstance( return URLClassLoader.newInstance(
@ -724,7 +767,9 @@ public final class GerritLauncher {
private static boolean includeJar(URL u) { private static boolean includeJar(URL u) {
String path = u.getPath(); String path = u.getPath();
return path.endsWith(".jar") && !path.endsWith("-src.jar"); return path.endsWith(".jar")
&& !path.endsWith("-src.jar")
&& !path.contains("/com/google/gerrit");
} }
private GerritLauncher() {} private GerritLauncher() {}

View File

@ -32,7 +32,7 @@ AUTO = '//lib/auto:auto-value'
JRE = '/'.join([ JRE = '/'.join([
'org.eclipse.jdt.launching.JRE_CONTAINER', 'org.eclipse.jdt.launching.JRE_CONTAINER',
'org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType', 'org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType',
'JavaSE-1.8', 'JavaSE-9',
]) ])
# Map of targets to corresponding classpath collector rules # Map of targets to corresponding classpath collector rules
cp_targets = { cp_targets = {
@ -52,10 +52,12 @@ opts.add_option('--name', help='name of the generated project',
action='store', default='gerrit', dest='project_name') action='store', default='gerrit', dest='project_name')
opts.add_option('-b', '--batch', action='store_true', opts.add_option('-b', '--batch', action='store_true',
dest='batch', help='Bazel batch option') dest='batch', help='Bazel batch option')
opts.add_option('-j', '--java', action='store',
dest='java', help='Post Java 8 support (9|10|11|...)')
args, _ = opts.parse_args() args, _ = opts.parse_args()
batch_option = '--batch' if args.batch else None batch_option = '--batch' if args.batch else None
custom_java = args.java
def _build_bazel_cmd(*args): def _build_bazel_cmd(*args):
cmd = ['bazel'] cmd = ['bazel']
@ -63,6 +65,9 @@ def _build_bazel_cmd(*args):
cmd.append('--batch') cmd.append('--batch')
for arg in args: for arg in args:
cmd.append(arg) cmd.append(arg)
if custom_java:
cmd.append('--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java%s' % custom_java)
cmd.append('--java_toolchain=@bazel_tools//tools/jdk:toolchain_java%s' % custom_java)
return cmd return cmd
@ -70,9 +75,10 @@ def retrieve_ext_location():
return check_output(_build_bazel_cmd('info', 'output_base')).strip() return check_output(_build_bazel_cmd('info', 'output_base')).strip()
def gen_bazel_path(): def gen_bazel_path(ext_location):
bazel = check_output(['which', 'bazel']).strip().decode('UTF-8') bazel = check_output(['which', 'bazel']).strip().decode('UTF-8')
with open(path.join(ROOT, ".bazel_path"), 'w') as fd: with open(path.join(ROOT, ".bazel_path"), 'w') as fd:
fd.write("output_base=%s\n" % ext_location)
fd.write("bazel=%s\n" % bazel) fd.write("bazel=%s\n" % bazel)
fd.write("PATH=%s\n" % environ["PATH"]) fd.write("PATH=%s\n" % environ["PATH"])
@ -301,7 +307,7 @@ try:
gen_project(args.project_name) gen_project(args.project_name)
gen_classpath(ext_location) gen_classpath(ext_location)
gen_factorypath(ext_location) gen_factorypath(ext_location)
gen_bazel_path() gen_bazel_path(ext_location)
# TODO(davido): Remove this when GWT gone # TODO(davido): Remove this when GWT gone
gwt_working_dir = ".gwt_work_dir" gwt_working_dir = ".gwt_work_dir"