]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12108 Support Java 11 RTE
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Tue, 14 May 2019 21:02:43 +0000 (16:02 -0500)
committerSonarTech <sonartech@sonarsource.com>
Thu, 16 May 2019 18:21:08 +0000 (20:21 +0200)
server/sonar-main/src/main/java/org/sonar/application/command/CeJvmOptions.java
server/sonar-main/src/main/java/org/sonar/application/command/CommandFactoryImpl.java
server/sonar-main/src/main/java/org/sonar/application/command/JavaVersion.java [new file with mode: 0644]
server/sonar-main/src/main/java/org/sonar/application/command/WebJvmOptions.java
server/sonar-main/src/test/java/org/sonar/application/command/CeJvmOptionsTest.java
server/sonar-main/src/test/java/org/sonar/application/command/CommandFactoryImplTest.java
server/sonar-main/src/test/java/org/sonar/application/command/WebJvmOptionsTest.java
sonar-application/src/main/java/org/sonar/application/App.java
sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/System2.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java

index 6b4502813f4072f36d8e17cdb80e4f20791f6033..44a58d1d52d373f15b80900d5ea5676404899d0c 100644 (file)
@@ -24,15 +24,21 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class CeJvmOptions extends JvmOptions<CeJvmOptions> {
-  public CeJvmOptions(File tmpDir) {
-    super(mandatoryOptions(tmpDir));
+
+  public CeJvmOptions(File tmpDir, JavaVersion javaVersion) {
+    super(mandatoryOptions(tmpDir, javaVersion));
   }
 
-  private static Map<String, String> mandatoryOptions(File tmpDir) {
+  private static Map<String, String> mandatoryOptions(File tmpDir, JavaVersion javaVersion) {
     Map<String, String> res = new LinkedHashMap<>(3);
     res.put("-Djava.awt.headless=", "true");
     res.put("-Dfile.encoding=", "UTF-8");
     res.put("-Djava.io.tmpdir=", tmpDir.getAbsolutePath());
+
+    if (javaVersion.isAtLeastJava11()) {
+      // avoid illegal reflective access operations done by MyBatis
+      res.put("--add-opens=java.base/java.util=ALL-UNNAMED", "");
+    }
     return res;
   }
 }
index 2afbc0310c9f4562063489054ca16e2bf2947066..738cabf841d044d5a693e626423da2ade61590b5 100644 (file)
@@ -68,11 +68,13 @@ public class CommandFactoryImpl implements CommandFactory {
   private final Props props;
   private final File tempDir;
   private final System2 system2;
+  private final JavaVersion javaVersion;
 
-  public CommandFactoryImpl(Props props, File tempDir, System2 system2) {
+  public CommandFactoryImpl(Props props, File tempDir, System2 system2, JavaVersion javaVersion) {
     this.props = props;
     this.tempDir = tempDir;
     this.system2 = system2;
+    this.javaVersion = javaVersion;
     String javaToolOptions = system2.getenv(ENV_VAR_JAVA_TOOL_OPTIONS);
     if (javaToolOptions != null && !javaToolOptions.trim().isEmpty()) {
       LoggerFactory.getLogger(CommandFactoryImpl.class)
@@ -149,7 +151,7 @@ public class CommandFactoryImpl implements CommandFactory {
   public JavaCommand createWebCommand(boolean leader) {
     File homeDir = props.nonNullValueAsFile(PATH_HOME.getKey());
 
-    WebJvmOptions jvmOptions = new WebJvmOptions(tempDir)
+    WebJvmOptions jvmOptions = new WebJvmOptions(tempDir, javaVersion)
       .addFromMandatoryProperty(props, WEB_JAVA_OPTS.getKey())
       .addFromMandatoryProperty(props, WEB_JAVA_ADDITIONAL_OPTS.getKey());
     addProxyJvmOptions(jvmOptions);
@@ -175,7 +177,7 @@ public class CommandFactoryImpl implements CommandFactory {
   public JavaCommand createCeCommand() {
     File homeDir = props.nonNullValueAsFile(PATH_HOME.getKey());
 
-    CeJvmOptions jvmOptions = new CeJvmOptions(tempDir)
+    CeJvmOptions jvmOptions = new CeJvmOptions(tempDir, javaVersion)
       .addFromMandatoryProperty(props, CE_JAVA_OPTS.getKey())
       .addFromMandatoryProperty(props, CE_JAVA_ADDITIONAL_OPTS.getKey());
     addProxyJvmOptions(jvmOptions);
diff --git a/server/sonar-main/src/main/java/org/sonar/application/command/JavaVersion.java b/server/sonar-main/src/main/java/org/sonar/application/command/JavaVersion.java
new file mode 100644 (file)
index 0000000..448f8d5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.application.command;
+
+public class JavaVersion {
+  public static final JavaVersion INSTANCE = new JavaVersion();
+
+  public boolean isAtLeastJava11() {
+    try {
+      String.class.getMethod("isBlank");
+      return true;
+    } catch (NoSuchMethodException e) {
+      return false;
+    }
+  }
+}
index 998f2e25974033666795398d5638c5a09967189a..8e55debe854ef83dc6b5803db247cf1d25a04ee7 100644 (file)
@@ -24,15 +24,25 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class WebJvmOptions extends JvmOptions<WebJvmOptions> {
-  public WebJvmOptions(File tmpDir) {
-    super(mandatoryOptions(tmpDir));
+  public WebJvmOptions(File tmpDir, JavaVersion javaVersion) {
+    super(mandatoryOptions(tmpDir, javaVersion));
   }
 
-  private static Map<String, String> mandatoryOptions(File tmpDir) {
+  private static Map<String, String> mandatoryOptions(File tmpDir, JavaVersion javaVersion) {
     Map<String, String> res = new LinkedHashMap<>(3);
     res.put("-Djava.awt.headless=", "true");
     res.put("-Dfile.encoding=", "UTF-8");
     res.put("-Djava.io.tmpdir=", tmpDir.getAbsolutePath());
+
+    if (javaVersion.isAtLeastJava11()) {
+      // avoid illegal reflective access operations done by MyBatis
+      res.put("--add-opens=java.base/java.util=ALL-UNNAMED", "");
+
+      // avoid illegal reflective access operations done by Tomcat
+      res.put("--add-opens=java.base/java.lang=ALL-UNNAMED", "");
+      res.put("--add-opens=java.base/java.io=ALL-UNNAMED", "");
+      res.put("--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED", "");
+    }
     return res;
   }
 }
index 98dcb5c9eff923b7de7671ade17d7f4a41c5aa50..863ee7633404340d119601fd735a728419564e40 100644 (file)
@@ -21,22 +21,42 @@ package org.sonar.application.command;
 
 import java.io.File;
 import java.io.IOException;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class CeJvmOptionsTest {
   @Rule
   public TemporaryFolder temporaryFolder = new TemporaryFolder();
 
-  @Test
-  public void constructor_sets_mandatory_JVM_options() throws IOException {
-    File tmpDir = temporaryFolder.newFolder();
-    CeJvmOptions underTest = new CeJvmOptions(tmpDir);
+  private File tmpDir;
+  private JavaVersion javaVersion = mock(JavaVersion.class);
+  private CeJvmOptions underTest;
+
+  @Before
+  public void setUp() throws IOException {
+    tmpDir = temporaryFolder.newFolder();
+  }
 
+  @Test
+  public void constructor_sets_mandatory_JVM_options_before_java11() {
+    when(javaVersion.isAtLeastJava11()).thenReturn(false);
+    underTest = new CeJvmOptions(tmpDir, javaVersion);
     assertThat(underTest.getAll()).containsExactly(
       "-Djava.awt.headless=true", "-Dfile.encoding=UTF-8", "-Djava.io.tmpdir=" + tmpDir.getAbsolutePath());
   }
+
+  @Test
+  public void constructor_sets_mandatory_JVM_options_for_java11() {
+    when(javaVersion.isAtLeastJava11()).thenReturn(true);
+    underTest = new CeJvmOptions(tmpDir, javaVersion);
+    assertThat(underTest.getAll()).containsExactly(
+      "-Djava.awt.headless=true", "-Dfile.encoding=UTF-8", "-Djava.io.tmpdir=" + tmpDir.getAbsolutePath(),
+      "--add-opens=java.base/java.util=ALL-UNNAMED");
+  }
 }
index 0868f4150a89709bbc20934119dcc70e285a3fbd..1f3a059a34c692737ba346e3024446003fb924b2 100644 (file)
@@ -32,15 +32,14 @@ import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.mockito.Mockito;
 import org.sonar.application.es.EsInstallation;
+import org.sonar.application.logging.ListAppender;
 import org.sonar.process.ProcessId;
 import org.sonar.process.ProcessProperties;
 import org.sonar.process.Props;
 import org.sonar.process.System2;
-import org.sonar.application.logging.ListAppender;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.when;
 
 public class CommandFactoryImplTest {
@@ -50,6 +49,8 @@ public class CommandFactoryImplTest {
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
+  private System2 system2 = Mockito.mock(System2.class);
+  private JavaVersion javaVersion = Mockito.mock(JavaVersion.class);
   private File homeDir;
   private File tempDir;
   private File logsDir;
@@ -71,22 +72,19 @@ public class CommandFactoryImplTest {
 
   @Test
   public void constructor_logs_no_warning_if_env_variable_JAVA_TOOL_OPTIONS_is_not_set() {
-    System2 system2 = Mockito.mock(System2.class);
-    when(system2.getenv(anyString())).thenReturn(null);
     attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class);
 
-    new CommandFactoryImpl(new Props(new Properties()), tempDir, system2);
+    new CommandFactoryImpl(new Props(new Properties()), tempDir, system2, javaVersion);
 
     assertThat(listAppender.getLogs()).isEmpty();
   }
 
   @Test
   public void constructor_logs_warning_if_env_variable_JAVA_TOOL_OPTIONS_is_set() {
-    System2 system2 = Mockito.mock(System2.class);
     when(system2.getenv("JAVA_TOOL_OPTIONS")).thenReturn("sds");
     attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class);
 
-    new CommandFactoryImpl(new Props(new Properties()), tempDir, system2);
+    new CommandFactoryImpl(new Props(new Properties()), tempDir, system2, javaVersion);
 
     assertThat(listAppender.getLogs())
       .extracting(ILoggingEvent::getMessage)
@@ -97,11 +95,10 @@ public class CommandFactoryImplTest {
 
   @Test
   public void constructor_logs_warning_if_env_variable_ES_JAVA_OPTS_is_set() {
-    System2 system2 = Mockito.mock(System2.class);
     when(system2.getenv("ES_JAVA_OPTS")).thenReturn("xyz");
     attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class);
 
-    new CommandFactoryImpl(new Props(new Properties()), tempDir, system2);
+    new CommandFactoryImpl(new Props(new Properties()), tempDir, system2, javaVersion);
 
     assertThat(listAppender.getLogs())
       .extracting(ILoggingEvent::getMessage)
@@ -120,7 +117,6 @@ public class CommandFactoryImplTest {
 
   @Test
   public void createEsCommand_for_unix_returns_command_for_default_settings() throws Exception {
-    System2 system2 = Mockito.mock(System2.class);
     when(system2.isOsWindows()).thenReturn(false);
     prepareEsFileSystem();
 
@@ -157,7 +153,6 @@ public class CommandFactoryImplTest {
 
   @Test
   public void createEsCommand_for_windows_returns_command_for_default_settings() throws Exception {
-    System2 system2 = Mockito.mock(System2.class);
     when(system2.isOsWindows()).thenReturn(true);
     prepareEsFileSystem();
 
@@ -326,7 +321,7 @@ public class CommandFactoryImplTest {
 
     Props props = new Props(p);
     ProcessProperties.completeDefaults(props);
-    return new CommandFactoryImpl(props, tempDir, system2);
+    return new CommandFactoryImpl(props, tempDir, system2, javaVersion);
   }
 
   private <T> void attachMemoryAppenderToLoggerOf(Class<T> loggerClass) {
index 0f0b42e72f3072e30047900cae405e32f09a576f..8cc87861f5fa3817789c0532d37881ad99faaee4 100644 (file)
@@ -21,23 +21,46 @@ package org.sonar.application.command;
 
 import java.io.File;
 import java.io.IOException;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class WebJvmOptionsTest {
   @Rule
   public TemporaryFolder temporaryFolder = new TemporaryFolder();
 
-  @Test
-  public void constructor_sets_mandatory_JVM_options() throws IOException {
-    File tmpDir = temporaryFolder.newFolder();
-    WebJvmOptions underTest = new WebJvmOptions(tmpDir);
+  private File tmpDir;
+  private JavaVersion javaVersion = mock(JavaVersion.class);
+  private WebJvmOptions underTest;
+
+  @Before
+  public void setUp() throws IOException {
+    tmpDir = temporaryFolder.newFolder();
+  }
 
+  @Test
+  public void constructor_sets_mandatory_JVM_options_before_java11() {
+    when(javaVersion.isAtLeastJava11()).thenReturn(false);
+    underTest = new WebJvmOptions(tmpDir, javaVersion);
     assertThat(underTest.getAll()).containsExactly(
       "-Djava.awt.headless=true", "-Dfile.encoding=UTF-8", "-Djava.io.tmpdir=" + tmpDir.getAbsolutePath());
   }
 
+  @Test
+  public void constructor_sets_mandatory_JVM_options_for_java11() {
+    when(javaVersion.isAtLeastJava11()).thenReturn(true);
+    underTest = new WebJvmOptions(tmpDir, javaVersion);
+    assertThat(underTest.getAll()).containsExactly(
+      "-Djava.awt.headless=true", "-Dfile.encoding=UTF-8", "-Djava.io.tmpdir=" + tmpDir.getAbsolutePath(),
+      "--add-opens=java.base/java.util=ALL-UNNAMED",
+      "--add-opens=java.base/java.lang=ALL-UNNAMED",
+      "--add-opens=java.base/java.io=ALL-UNNAMED",
+      "--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED");
+  }
+
 }
index 268d4c997e87a78c9a4932a8699fcdfc445bc7e8..d262fe5df9c4de6141526be6ce5fd142788d667d 100644 (file)
 package org.sonar.application;
 
 import java.io.IOException;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.internal.MetadataLoader;
 import org.sonar.application.command.CommandFactory;
 import org.sonar.application.command.CommandFactoryImpl;
+import org.sonar.application.command.JavaVersion;
 import org.sonar.application.config.AppSettings;
 import org.sonar.application.config.AppSettingsLoader;
 import org.sonar.application.config.AppSettingsLoaderImpl;
@@ -38,8 +42,13 @@ import static org.sonar.process.ProcessProperties.Property.CLUSTER_NAME;
 public class App {
 
   private final SystemExit systemExit = new SystemExit();
+  private final JavaVersion javaVersion;
   private StopRequestWatcher stopRequestWatcher;
 
+  public App(JavaVersion javaVersion) {
+    this.javaVersion = javaVersion;
+  }
+
   public void start(String[] cliArguments) throws IOException {
     AppSettingsLoader settingsLoader = new AppSettingsLoaderImpl(cliArguments);
     AppSettings settings = settingsLoader.load();
@@ -47,13 +56,14 @@ public class App {
     AppLogging logging = new AppLogging(settings);
     logging.configure();
     AppFileSystem fileSystem = new AppFileSystem(settings);
+    checkJavaVersion();
 
     try (AppState appState = new AppStateFactory(settings).create()) {
       appState.registerSonarQubeVersion(getSonarqubeVersion());
       appState.registerClusterName(settings.getProps().nonNullValue(CLUSTER_NAME.getKey()));
       AppReloader appReloader = new AppReloaderImpl(settingsLoader, fileSystem, appState, logging);
       fileSystem.reset();
-      CommandFactory commandFactory = new CommandFactoryImpl(settings.getProps(), fileSystem.getTempDir(), System2.INSTANCE);
+      CommandFactory commandFactory = new CommandFactoryImpl(settings.getProps(), fileSystem.getTempDir(), System2.INSTANCE, JavaVersion.INSTANCE);
 
       try (ProcessLauncher processLauncher = new ProcessLauncherImpl(fileSystem.getTempDir())) {
         Scheduler scheduler = new SchedulerImpl(settings, appReloader, commandFactory, processLauncher, appState);
@@ -74,8 +84,18 @@ public class App {
     systemExit.exit(0);
   }
 
+  private void checkJavaVersion() {
+    if (MetadataLoader.loadEdition(org.sonar.api.utils.System2.INSTANCE) == SonarEdition.SONARCLOUD) {
+      return;
+    }
+
+    if (!javaVersion.isAtLeastJava11()) {
+      LoggerFactory.getLogger(this.getClass()).warn("SonarQube will require Java 11+ starting on next version");
+    }
+  }
+
   public static void main(String... args) throws IOException {
-    new App().start(args);
+    new App(JavaVersion.INSTANCE).start(args);
   }
 
   private class ShutdownHook extends Thread {
index c739fa666abdcf8b92a6b155a4653f475ba3c8e8..92b2085ef3dd623e6868131569671a098b1511ae 100644 (file)
  */
 package org.sonar.duplications.java;
 
-import org.apache.commons.io.IOUtils;
-import org.junit.Test;
-import org.sonar.duplications.DuplicationsTestUtil;
-import org.sonar.duplications.statement.Statement;
-import org.sonar.duplications.statement.StatementChunker;
-import org.sonar.duplications.token.TokenChunker;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -33,6 +26,12 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.sonar.duplications.DuplicationsTestUtil;
+import org.sonar.duplications.statement.Statement;
+import org.sonar.duplications.statement.StatementChunker;
+import org.sonar.duplications.token.TokenChunker;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -318,6 +317,51 @@ public class JavaStatementBuilderTest {
     assertThat(statements.get(1).getValue()).isEqualTo("something()");
   }
 
+  /**
+   * Java 8.
+   */
+  @Test
+  public void shouldHandleLambda() {
+    List<Statement> statements;
+    statements = chunk("List<String> result = lines.stream().filter(line -> !\"mkyong\".equals(line)).collect(Collectors.toList());");
+    assertThat(statements.size()).isEqualTo(1);
+    assertThat(statements).extracting(Statement::getValue).containsExactly("List<String>result=lines.stream().filter(line->!$CHARS.equals(line)).collect(Collectors.toList())");
+
+    statements = chunk("items.forEach((k,v)->{System.out.println(\"Item : \" + k + \" Count : \" + v); if(\"E\".equals(k)) { System.out.println(\"Hello E\");}});");
+    assertThat(statements.size()).isEqualTo(5);
+    assertThat(statements).extracting(Statement::getValue)
+      .containsExactly("items.forEach((k,v)->",
+        "System.out.println($CHARS+k+$CHARS+v)",
+        "if($CHARS.equals(k))",
+        "System.out.println($CHARS)",
+        ")");
+  }
+
+  /**
+   * Java 9.
+   */
+  @Test
+  public void shouldHandleModuleInfo() {
+    List<Statement> statements;
+    statements = chunk("module com.application.infra { requires com.application.domain; exports com.application.infra.api; }");
+    assertThat(statements.size()).isEqualTo(3);
+    assertThat(statements).extracting(Statement::getValue)
+      .containsExactly("modulecom.application.infra",
+      "requirescom.application.domain",
+      "exportscom.application.infra.api");
+  }
+
+  /**
+   * Java 11.
+   */
+  @Test
+  public void shouldHandleVar() {
+    List<Statement> statements;
+    statements = chunk("IFunc f = (@NonNull var x, final var y) -> Foo.foo(x, y);");
+    assertThat(statements.size()).isEqualTo(1);
+    assertThat(statements).extracting(Statement::getValue).containsExactly("IFuncf=(@NonNullvarx,finalvary)->Foo.foo(x,y)");
+  }
+
   @Test
   public void realExamples() {
     assertThat(chunk(DuplicationsTestUtil.findFile("/java/MessageResources.java")).size()).isGreaterThan(0);
index 2f2ee31eef1f3840b367018052458105b662e40b..36dc553a74e94f648c0387125e5a954d3821b3e6 100644 (file)
@@ -21,14 +21,13 @@ package org.sonar.api.utils;
 
 import java.net.URL;
 import java.time.Clock;
-import java.util.Date;
 import java.util.Map;
 import java.util.Properties;
 import java.util.TimeZone;
 import javax.annotation.CheckForNull;
 import org.apache.commons.lang.SystemUtils;
-import org.sonar.api.scanner.ScannerSide;
 import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.scanner.ScannerSide;
 import org.sonar.api.server.ServerSide;
 
 /**
@@ -61,7 +60,6 @@ import org.sonar.api.server.ServerSide;
  * Note that the name System2 was chosen to not conflict with {@link java.lang.System}.
  * <br>
  * An instance is available in IoC container since 4.3.
- * 
  * Since 6.4 you can also inject {@link Clock} instead of {@link System2} if you are only interested by date/time operations
  *
  * @since 4.2
@@ -98,6 +96,7 @@ public class System2 {
 
   /**
    * Shortcut for {@code System{@link #setProperty(String, String)}}
+   *
    * @since 6.4
    */
   public System2 setProperty(String key, String value) {
@@ -129,6 +128,7 @@ public class System2 {
 
   /**
    * True if Java 7 or Java 8 runtime environment
+   *
    * @since 4.3
    * @deprecated in 6.4. Java 8+ is required, so this method always returns {@code true}.
    */
@@ -142,24 +142,16 @@ public class System2 {
   }
 
   /**
-   * @deprecated in 5.2. Please use {@link #now()}
-   */
-  @Deprecated
-  public Date newDate() {
-    return new Date();
-  }
-
-  /**
-   * @since 5.1
    * @return the JVM's default time zone
+   * @since 5.1
    */
   public TimeZone getDefaultTimeZone() {
     return TimeZone.getDefault();
   }
 
   /**
-   * @since 5.5
    * @see Class#getResource(String)
+   * @since 5.5
    */
   public URL getResource(String name) {
     return getClass().getResource(name);
@@ -167,6 +159,7 @@ public class System2 {
 
   /**
    * Closes the object and throws an {@link java.lang.IllegalStateException} on error.
+   *
    * @since 5.1
    */
   public void close(AutoCloseable closeable) {
index 690509a8daa6cb4410f4d33c4ddde01ca5e85892..9b407ba2a3d02a3e1769a0d78eab2b4c9d18c124 100644 (file)
@@ -22,10 +22,10 @@ package org.sonar.scanner.bootstrap;
 import java.time.Clock;
 import java.util.List;
 import java.util.Map;
-import org.sonar.api.SonarEdition;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.Plugin;
+import org.sonar.api.SonarEdition;
 import org.sonar.api.SonarQubeSide;
 import org.sonar.api.SonarQubeVersion;
 import org.sonar.api.internal.MetadataLoader;
@@ -78,9 +78,20 @@ public class GlobalContainer extends ComponentContainer {
     addBootstrapComponents();
   }
 
+  private static void checkJavaVersion() {
+    try {
+      String.class.getMethod("isBlank");
+    } catch (NoSuchMethodException e) {
+      LOG.warn("SonarQube scanners will require Java 11+ starting on next version");
+    }
+  }
+
   private void addBootstrapComponents() {
     Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE);
     SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
+    if (edition != SonarEdition.SONARCLOUD) {
+      checkJavaVersion();
+    }
     LOG.debug("{} {}", edition.getLabel(), apiVersion);
     add(
       // plugins