parsed = SslConfiguration.parseArgs(arguments.split(","), logger);
+ if (parsed.isPresent()) {
+ sslConfig = parsed.get();
+ } else {
+ return false;
}
}
return true;
@@ -813,51 +676,7 @@ protected WebAppContext createWebAppContext(TreeLogger logger, File appRootDir)
}
protected ServerConnector getConnector(Server server, TreeLogger logger) {
- HttpConfiguration config = defaultConfig();
- if (useSsl) {
- TreeLogger sslLogger = logger.branch(TreeLogger.INFO,
- "Listening for SSL connections");
- if (sslLogger.isLoggable(TreeLogger.TRACE)) {
- sslLogger.log(TreeLogger.TRACE, "Using keystore " + keyStore);
- }
- SslContextFactory ssl = new SslContextFactory();
- if (clientAuth != null) {
- switch (clientAuth) {
- case NONE:
- ssl.setWantClientAuth(false);
- ssl.setNeedClientAuth(false);
- break;
- case WANT:
- sslLogger.log(TreeLogger.TRACE, "Requesting client certificates");
- ssl.setWantClientAuth(true);
- ssl.setNeedClientAuth(false);
- break;
- case REQUIRE:
- sslLogger.log(TreeLogger.TRACE, "Requiring client certificates");
- ssl.setWantClientAuth(true);
- ssl.setNeedClientAuth(true);
- break;
- }
- }
- ssl.setKeyStorePath(keyStore);
- ssl.setTrustStorePath(keyStore);
- ssl.setKeyStorePassword(keyStorePassword);
- ssl.setTrustStorePassword(keyStorePassword);
- config.addCustomizer(new SecureRequestCustomizer());
- return new ServerConnector(server,
- null, null, null, 0, 2,
- new SslConnectionFactory(ssl, "http/1.1"),
- new HttpConnectionFactory(config));
- }
- return new ServerConnector(server, new HttpConnectionFactory(config));
- }
-
- protected HttpConfiguration defaultConfig() {
- HttpConfiguration config = new HttpConfiguration();
- config.setRequestHeaderSize(16386);
- config.setSendServerVersion(false);
- config.setSendDateHeader(true);
- return config;
+ return JettyLauncherUtils.getConnector(server, sslConfig, logger);
}
private void addPreventers(Server server) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncherUtils.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncherUtils.java
new file mode 100644
index 00000000000..944c1b152f1
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncherUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * 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 com.google.gwt.dev.shell.jetty;
+
+import com.google.gwt.core.ext.TreeLogger;
+
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+/**
+ * Shared static methods for both JettyLauncher and StaticResourceServer, useful for
+ * any Jetty-based implementation of a ServletContainerLauncher.
+ */
+public class JettyLauncherUtils {
+
+ private JettyLauncherUtils() {
+ // non-instantiable
+ }
+
+ /**
+ * Setup a connector for the bind address/port.
+ *
+ * @param connector
+ * @param bindAddress
+ * @param port
+ */
+ public static void setupConnector(ServerConnector connector,
+ String bindAddress, int port) {
+ if (bindAddress != null) {
+ connector.setHost(bindAddress);
+ }
+ connector.setPort(port);
+
+ // Allow binding to a port even if it's still in state TIME_WAIT.
+ connector.setReuseAddress(true);
+ }
+
+ public static ServerConnector getConnector(Server server, SslConfiguration sslConfig, TreeLogger logger) {
+ HttpConfiguration config = defaultConfig();
+ if (sslConfig.isUseSsl()) {
+ TreeLogger sslLogger = logger.branch(TreeLogger.INFO,
+ "Listening for SSL connections");
+ if (sslLogger.isLoggable(TreeLogger.TRACE)) {
+ sslLogger.log(TreeLogger.TRACE, "Using keystore " + sslConfig.getKeyStore());
+ }
+ SslContextFactory ssl = new SslContextFactory();
+ if (sslConfig.getClientAuth() != null) {
+ switch (sslConfig.getClientAuth()) {
+ case NONE:
+ ssl.setWantClientAuth(false);
+ ssl.setNeedClientAuth(false);
+ break;
+ case WANT:
+ sslLogger.log(TreeLogger.TRACE, "Requesting client certificates");
+ ssl.setWantClientAuth(true);
+ ssl.setNeedClientAuth(false);
+ break;
+ case REQUIRE:
+ sslLogger.log(TreeLogger.TRACE, "Requiring client certificates");
+ ssl.setWantClientAuth(true);
+ ssl.setNeedClientAuth(true);
+ break;
+ }
+ }
+ ssl.setKeyStorePath(sslConfig.getKeyStore());
+ ssl.setTrustStorePath(sslConfig.getKeyStore());
+ ssl.setKeyStorePassword(sslConfig.getKeyStorePassword());
+ ssl.setTrustStorePassword(sslConfig.getKeyStorePassword());
+ config.addCustomizer(new SecureRequestCustomizer());
+ return new ServerConnector(server,
+ null, null, null, 0, 2,
+ new SslConnectionFactory(ssl, "http/1.1"),
+ new HttpConnectionFactory(config));
+ }
+ return new ServerConnector(server, new HttpConnectionFactory(config));
+ }
+
+ private static HttpConfiguration defaultConfig() {
+ HttpConfiguration config = new HttpConfiguration();
+ config.setRequestHeaderSize(16386);
+ config.setSendServerVersion(false);
+ config.setSendDateHeader(true);
+ return config;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyTreeLogger.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyTreeLogger.java
new file mode 100644
index 00000000000..c31ca4b5eef
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyTreeLogger.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * 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 com.google.gwt.dev.shell.jetty;
+
+import com.google.gwt.core.ext.TreeLogger;
+
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * An adapter for the Jetty logging system to GWT's TreeLogger. This implementation class is only
+ * public to allow {@link org.eclipse.jetty.util.log.Log} to instantiate it.
+ *
+ * The weird static data / default construction setup is a game we play with
+ * {@link org.eclipse.jetty.util.log.Log}'s static initializer to prevent the initial log message
+ * from going to stderr.
+ */
+public class JettyTreeLogger implements Logger {
+ private final TreeLogger logger;
+
+ public JettyTreeLogger(TreeLogger logger) {
+ if (logger == null) {
+ throw new NullPointerException();
+ }
+ this.logger = logger;
+ }
+
+ public void debug(String msg, long arg) {
+ logger.log(TreeLogger.SPAM, format(msg, arg));
+ }
+
+ public void debug(String msg, Object... args) {
+ if (logger.isLoggable(TreeLogger.SPAM)) {
+ logger.log(TreeLogger.SPAM, format(msg, args));
+ }
+ }
+
+ public void debug(String msg, Throwable th) {
+ logger.log(TreeLogger.SPAM, msg, th);
+ }
+
+ public void debug(Throwable th) {
+ logger.log(TreeLogger.SPAM, "", th);
+ }
+
+ public Logger getLogger(String name) {
+ return this;
+ }
+
+ public String getName() {
+ return "";
+ }
+
+ public void info(String msg, Object... args) {
+ if (logger.isLoggable(TreeLogger.TRACE)) {
+ logger.log(TreeLogger.TRACE, format(msg, args));
+ }
+ }
+
+ public void info(String msg, Throwable th) {
+ logger.log(TreeLogger.TRACE, msg, th);
+ }
+
+ public void info(Throwable th) {
+ logger.log(TreeLogger.TRACE, "", th);
+ }
+
+ public boolean isDebugEnabled() {
+ return logger.isLoggable(TreeLogger.SPAM);
+ }
+
+ public void setDebugEnabled(boolean enabled) {
+ // ignored
+ }
+
+ public void warn(String msg, Object... args) {
+ if (logger.isLoggable(TreeLogger.WARN)) {
+ logger.log(TreeLogger.WARN, format(msg, args));
+ }
+ }
+
+ public void warn(String msg, Throwable th) {
+ logger.log(TreeLogger.WARN, msg, th);
+ }
+
+ public void warn(Throwable th) {
+ logger.log(TreeLogger.WARN, "", th);
+ }
+
+ public void ignore(Throwable th) {
+ logger.log(TreeLogger.SPAM, "IGNORE", th);
+ }
+
+ /**
+ * Copied from org.eclipse.log.StdErrLog.
+ */
+ private String format(String msg, Object... args) {
+ if (msg == null) {
+ msg = "";
+ for (int i = 0; i < args.length; i++) {
+ msg += "{} ";
+ }
+ }
+ String braces = "{}";
+ int start = 0;
+ StringBuilder builder = new StringBuilder();
+ for (Object arg : args) {
+ int bracesIndex = msg.indexOf(braces, start);
+ if (bracesIndex < 0) {
+ builder.append(msg.substring(start));
+ builder.append(" ");
+ builder.append(arg);
+ start = msg.length();
+ } else {
+ builder.append(msg.substring(start, bracesIndex));
+ builder.append(String.valueOf(arg));
+ start = bracesIndex + braces.length();
+ }
+ }
+ builder.append(msg.substring(start));
+ return builder.toString();
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/SslConfiguration.java b/dev/core/src/com/google/gwt/dev/shell/jetty/SslConfiguration.java
new file mode 100644
index 00000000000..3d6da8ef1a9
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/SslConfiguration.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * 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 com.google.gwt.dev.shell.jetty;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.util.Util;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Optional;
+
+/**
+ * Configuration object to parse selected command line args, store SSL options for use by in the
+ * server.
+ */
+public class SslConfiguration {
+ private final ClientAuthType clientAuth;
+
+ private final String keyStore;
+
+ private final String keyStorePassword;
+
+ private final boolean useSsl;
+
+ public static Optional parseArgs(String[] args, TreeLogger logger) {
+ boolean useSsl = false;
+ String keyStore = null;
+ String keyStorePassword = null;
+ ClientAuthType clientAuth = ClientAuthType.NONE;
+
+ // TODO(jat): better parsing of the args
+ for (String arg : args) {
+ int equals = arg.indexOf('=');
+ String tag;
+ String value = null;
+ if (equals < 0) {
+ tag = arg;
+ } else {
+ tag = arg.substring(0, equals);
+ value = arg.substring(equals + 1);
+ }
+ if ("ssl".equals(tag)) {
+ useSsl = true;
+ URL keyStoreUrl = JettyLauncher.class.getResource("localhost.keystore");
+ if (keyStoreUrl == null) {
+ logger.log(TreeLogger.ERROR, "Default GWT keystore not found");
+ return Optional.empty();
+ }
+ keyStore = keyStoreUrl.toExternalForm();
+ keyStorePassword = "localhost";
+ } else if ("keystore".equals(tag)) {
+ useSsl = true;
+ keyStore = value;
+ } else if ("password".equals(tag)) {
+ useSsl = true;
+ keyStorePassword = value;
+ } else if ("pwfile".equals(tag)) {
+ useSsl = true;
+ keyStorePassword = Util.readFileAsString(new File(value));
+ if (keyStorePassword == null) {
+ logger.log(TreeLogger.ERROR,
+ "Unable to read keystore password from '" + value + "'");
+ return Optional.empty();
+ }
+ keyStorePassword = keyStorePassword.trim();
+ } else if ("clientAuth".equals(tag)) {
+ useSsl = true;
+ try {
+ clientAuth = ClientAuthType.valueOf(value);
+ } catch (IllegalArgumentException e) {
+ logger.log(TreeLogger.WARN, "Ignoring invalid clientAuth of '"
+ + value + "'");
+ }
+ } else {
+ logger.log(TreeLogger.ERROR, "Unexpected argument to "
+ + JettyLauncher.class.getSimpleName() + ": " + arg);
+ return Optional.empty();
+ }
+ }
+ if (useSsl) {
+ if (keyStore == null) {
+ logger.log(TreeLogger.ERROR, "A keystore is required to use SSL");
+ return Optional.empty();
+ }
+ if (keyStorePassword == null) {
+ logger.log(TreeLogger.ERROR,
+ "A keystore password is required to use SSL");
+ return Optional.empty();
+ }
+ }
+ return Optional.of(new SslConfiguration(clientAuth, keyStore, keyStorePassword, useSsl));
+ }
+
+ public SslConfiguration(ClientAuthType clientAuth, String keyStore, String keyStorePassword, boolean useSsl) {
+ this.clientAuth = clientAuth;
+ this.keyStore = keyStore;
+ this.keyStorePassword = keyStorePassword;
+ this.useSsl = useSsl;
+ }
+
+ public ClientAuthType getClientAuth() {
+ return clientAuth;
+ }
+
+ public String getKeyStore() {
+ return keyStore;
+ }
+
+ public String getKeyStorePassword() {
+ return keyStorePassword;
+ }
+
+ public boolean isUseSsl() {
+ return useSsl;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/SourceLevel.java b/dev/core/src/com/google/gwt/dev/util/arg/SourceLevel.java
index d07680b3e1b..821628fc860 100644
--- a/dev/core/src/com/google/gwt/dev/util/arg/SourceLevel.java
+++ b/dev/core/src/com/google/gwt/dev/util/arg/SourceLevel.java
@@ -26,7 +26,8 @@ public enum SourceLevel {
JAVA8("1.8", "8"),
JAVA9("9", "1.9"),
JAVA10("10", "1.10"),
- JAVA11("11", "1.11");
+ JAVA11("11", "1.11"),
+ JAVA17("17", "1.17");
/**
* The default java sourceLevel.
diff --git a/dev/core/test/com/google/gwt/core/ext/linker/ArtifactSetTest.java b/dev/core/test/com/google/gwt/core/ext/linker/ArtifactSetTest.java
index b7db647e804..cf09f867025 100644
--- a/dev/core/test/com/google/gwt/core/ext/linker/ArtifactSetTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/linker/ArtifactSetTest.java
@@ -27,6 +27,7 @@
*/
public class ArtifactSetTest extends TestCase {
+ @SuppressWarnings("SelfComparison")
public void testScriptOrder() {
StandardScriptReference fooScript = new StandardScriptReference("foo", 0);
StandardScriptReference barScript = new StandardScriptReference("bar", 1);
@@ -65,6 +66,7 @@ public void testScriptOrder() {
}
}
+ @SuppressWarnings("SelfComparison")
public void testStyleOrder() {
StandardStylesheetReference fooStyle = new StandardStylesheetReference(
"foo", 0);
diff --git a/dev/core/test/com/google/gwt/core/ext/linker/TypeIndexedSetTest.java b/dev/core/test/com/google/gwt/core/ext/linker/TypeIndexedSetTest.java
index 752ef60a152..f8a43a2e583 100644
--- a/dev/core/test/com/google/gwt/core/ext/linker/TypeIndexedSetTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/linker/TypeIndexedSetTest.java
@@ -52,6 +52,7 @@ public int hashCode() {
}
@Override
+ @SuppressWarnings("BoxedPrimitiveEquality")
public boolean equals(Object o) {
return (o instanceof RootComparable) && (((RootComparable) o).value == this.value);
}
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java
index 0176bb029c7..b88089b73e9 100644
--- a/dev/core/test/com/google/gwt/dev/CompilerTest.java
+++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -39,6 +39,7 @@
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.io.Files;
import com.google.gwt.util.tools.Utility;
+
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
diff --git a/dev/core/test/com/google/gwt/dev/GwtVersionTest.java b/dev/core/test/com/google/gwt/dev/GwtVersionTest.java
index 5cc726f5d80..283cbfd27a5 100644
--- a/dev/core/test/com/google/gwt/dev/GwtVersionTest.java
+++ b/dev/core/test/com/google/gwt/dev/GwtVersionTest.java
@@ -39,6 +39,7 @@ public void testCompareEqualsHashCode() {
/**
* Test that GwtVersion.compareTo produced expected results.
*/
+ @SuppressWarnings("SelfComparison")
public void testCompareTo() {
GwtVersion v1 = new GwtVersion("0.0.0");
assertEquals(0, v1.compareTo(v1));
diff --git a/dev/core/test/com/google/gwt/dev/HostedModeOptionsMock.java b/dev/core/test/com/google/gwt/dev/HostedModeOptionsMock.java
new file mode 100644
index 00000000000..81e9d583f37
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/HostedModeOptionsMock.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2024 Google Inc.
+ *
+ * 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 com.google.gwt.dev;
+
+/**
+ * Make {@link com.google.gwt.dev.DevMode.HostedModeOptionsImpl} visible as mock for tests..
+ */
+public class HostedModeOptionsMock extends DevMode.HostedModeOptionsImpl {
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java b/dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java
index a5feaf6b911..f6e7bc1b4b3 100644
--- a/dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/BinaryTypeReferenceRestrictionsCheckerTest.java
@@ -37,6 +37,7 @@
import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IRecordComponent;
import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
@@ -181,6 +182,16 @@ public ITypeAnnotationWalker enrichWithExternalAnnotationsFor(
public ExternalAnnotationStatus getExternalAnnotationStatus() {
return null;
}
+
+ @Override
+ public IRecordComponent[] getRecordComponents() {
+ return null;
+ }
+
+ @Override
+ public boolean isRecord() {
+ return false;
+ }
}
private static final String BINARY_TYPE_NAME = "BinaryType";
diff --git a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
index 3e15454933e..b878acf3ecf 100644
--- a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
@@ -260,6 +260,7 @@ private void testArrayStore() {
assertEquals(g, a);
}
+ @SuppressWarnings("ReturnValueIgnored")
private void testDeadTypes() {
if (false) {
new Object() {
diff --git a/dev/core/test/com/google/gwt/dev/javac/typemodel/test/GenericClass.java b/dev/core/test/com/google/gwt/dev/javac/typemodel/test/GenericClass.java
index e7d1a094fba..01ea06c01cf 100644
--- a/dev/core/test/com/google/gwt/dev/javac/typemodel/test/GenericClass.java
+++ b/dev/core/test/com/google/gwt/dev/javac/typemodel/test/GenericClass.java
@@ -28,6 +28,7 @@
* follows: class GenericClass>
* implements Comparable { ... }
*/
+@SuppressWarnings("ComparableType")
public class GenericClass implements Comparable,
Serializable {
/**
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/Java17AstTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/Java17AstTest.java
new file mode 100644
index 00000000000..9665ab535ca
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/Java17AstTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2024 Google Inc.
+ *
+ * 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 com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
+import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.ast.JInterfaceType;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests that {@link GwtAstBuilder} correctly builds the AST for
+ * features introduced in Java 17.
+ */
+public class Java17AstTest extends FullCompileTestBase {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ addAll(JavaResourceBase.createMockJavaResource("test.TextBlock",
+ "package test;",
+ "public interface TextBlock {",
+ "String text =\"\"\"",
+ "line 1",
+ "line 2",
+ "line 3",
+ "\"\"\";",
+ "}"
+ ));
+
+ addAll(JavaResourceBase.createMockJavaResource("test.Shape",
+ "package test;",
+ "public sealed class Shape permits Square, Circle {",
+ "}"
+ ));
+
+ addAll(JavaResourceBase.createMockJavaResource("test.Square",
+ "package test;",
+ "public final class Square extends Shape {",
+ "}"
+ ));
+
+ addAll(JavaResourceBase.createMockJavaResource("test.Circle",
+ "package test;",
+ "public final class Circle extends Shape {",
+ "}"
+ ));
+
+ addAll(JavaResourceBase.createMockJavaResource("test.Months",
+ "package test;",
+ "public enum Months {",
+ "JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER;",
+ "}"
+ ));
+ }
+
+ public void testTextBlocks() throws Exception {
+ JProgram program = compileSnippet("void", "new TextBlock(){};");
+ JInterfaceType textBlock = (JInterfaceType) findType(program, "TextBlock");
+ JStringLiteral initializer = (JStringLiteral) textBlock.getFields().get(0).getInitializer();
+ String multiLineString = initializer.getValue();
+ List lines = Arrays.asList(multiLineString.split("\n"));
+ assertEquals(3, lines.size());
+ assertEquals("line 1", lines.get(0));
+ assertEquals("line 2", lines.get(1));
+ assertEquals("line 3", lines.get(2));
+ }
+
+ public void testSealedClassesPermitted() throws Exception {
+ compileSnippet("void", "Shape square = new Square();");
+ compileSnippet("void", "Shape circle = new Circle();");
+ }
+
+ public void testSealedClassesNotPermitted() {
+ try {
+ addSnippetClassDecl("public final class Rectangle extends Shape {" +
+ "}");
+ compileSnippet("void", "Shape rectangle = new Rectangle();");
+ fail("Compile should have failed but succeeded.");
+ } catch (Exception e) {
+ if (!(e.getCause() instanceof UnableToCompleteException)
+ && !(e instanceof UnableToCompleteException)) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+ }
+
+ public void testRecordsNotSupported() {
+ try {
+ addSnippetClassDecl("public record Point(int x, int y) {}");
+ compileSnippet("void", "Point rectangle = new Point(0, 0);");
+ fail("Compile should have failed but succeeded.");
+ } catch (Exception e) {
+ if (!(e.getCause() instanceof UnableToCompleteException)
+ && !(e instanceof UnableToCompleteException)) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+ }
+
+ public void testSwitchExpressionsNotSupported() {
+ try {
+ compileSnippet("void", "var month = Months.JUNE;" +
+ "var result = switch(month) {\n" +
+ " case JANUARY, JUNE, JULY -> 3;\n" +
+ " case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1;\n" +
+ " case MARCH, MAY, APRIL, AUGUST -> 2;\n" +
+ " default -> 0;" +
+ "};");
+ fail("Compile should have failed but succeeded, switch expression is not supported.");
+ } catch (Exception e) {
+ if (!(e.getCause() instanceof InternalCompilerException)
+ && !(e instanceof InternalCompilerException)) {
+ e.printStackTrace();
+ fail();
+ }
+ assertEquals("Switch expressions not yet supported", e.getMessage());
+ }
+ }
+
+ public void testSwitchExpressionsInitializerShouldFail() {
+ try {
+ compileSnippet("void", " int i = switch(1) {\n" +
+ " case 1:\n" +
+ " yield 2;\n" +
+ " default:\n" +
+ " yield 7;\n" +
+ " };");
+ fail("Compile should have failed but succeeded, switch expressions as initializer should fail.");
+ } catch (Exception e) {
+ if (!(e.getCause() instanceof InternalCompilerException)
+ && !(e instanceof InternalCompilerException)) {
+ e.printStackTrace();
+ fail();
+ }
+ assertEquals("Switch expressions not yet supported", e.getMessage());
+ }
+ }
+
+ @Override
+ protected void optimizeJava() {
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
index 1eb65dd7561..118ed75a72d 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
@@ -17,7 +17,6 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.MinimalRebuildCache;
-import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
@@ -1268,6 +1267,77 @@ public void testJsNameGlobalNamespacesSucceeds() throws Exception {
assertBuggySucceeds();
}
+ public void testJsMethodWithDollarsign() throws Exception {
+ addSnippetImport("jsinterop.annotations.JsType");
+ addSnippetImport("jsinterop.annotations.JsMethod");
+ addSnippetImport("jsinterop.annotations.JsProperty");
+ addSnippetImport("jsinterop.annotations.JsPackage");
+ addSnippetClassDecl(
+ "@JsType public static class Buggy {",
+ " public void $() {",
+ " }",
+ " public void $method(String l) {",
+ " }",
+ " public void method$(String l) {",
+ " }",
+ " public void method$name(String l) {",
+ " }",
+ "}");
+ assertBuggySucceeds();
+ }
+
+ public void testJsFieldWithDollarsign() throws Exception {
+ addSnippetImport("jsinterop.annotations.JsType");
+ addSnippetImport("jsinterop.annotations.JsMethod");
+ addSnippetImport("jsinterop.annotations.JsProperty");
+ addSnippetImport("jsinterop.annotations.JsPackage");
+ addSnippetClassDecl(
+ "@JsType public static class Buggy {",
+ " public String $;",
+ " public String $field;",
+ " public String field$;",
+ " public String field$name;",
+ "}");
+ assertBuggySucceeds();
+ }
+
+ public void testJsPropertyWithDollarsign() throws Exception {
+ addSnippetImport("jsinterop.annotations.JsType");
+ addSnippetImport("jsinterop.annotations.JsProperty");
+ addSnippetClassDecl(
+ "@JsType public static class Buggy {",
+ " @JsProperty",
+ " public String get$() {",
+ " return null;",
+ " }",
+ " @JsProperty",
+ " public void set$(String value) {",
+ " }",
+ " @JsProperty",
+ " public String get$1() {",
+ " return null;",
+ " }",
+ " @JsProperty",
+ " public void set$1(String value) {",
+ " }",
+ " @JsProperty",
+ " public String getVal$() {",
+ " return null;",
+ " }",
+ " @JsProperty",
+ " public void setVal$(String value) {",
+ " }",
+ " @JsProperty",
+ " public String getVal$1() {",
+ " return null;",
+ " }",
+ " @JsProperty",
+ " public void setVal$1(String value) {",
+ " }",
+ "}");
+ assertBuggySucceeds();
+ }
+
public void testSingleJsTypeSucceeds() throws Exception {
addSnippetImport("jsinterop.annotations.JsType");
addSnippetClassDecl(
@@ -2555,20 +2625,6 @@ public void testUnusableByJsSyntheticMembersSucceeds() throws Exception {
assertBuggySucceeds();
}
- private static final MockJavaResource jsFunctionInterface = new MockJavaResource(
- "test.MyJsFunctionInterface") {
- @Override
- public CharSequence getContent() {
- StringBuilder code = new StringBuilder();
- code.append("package test;\n");
- code.append("import jsinterop.annotations.JsFunction;\n");
- code.append("@JsFunction public interface MyJsFunctionInterface {\n");
- code.append("int foo(int x);\n");
- code.append("}\n");
- return code;
- }
- };
-
public final void assertBuggySucceeds(String... expectedWarnings)
throws Exception {
Result result = assertCompileSucceeds("Buggy buggy = null;", expectedWarnings);
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java
index 1f84956eaee..d6dd76099b3 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/DefaultFiltersTest.java
@@ -16,11 +16,10 @@
package com.google.gwt.dev.resource.impl;
import com.google.gwt.dev.resource.impl.DefaultFilters.FilterFileType;
+import com.google.gwt.thirdparty.apache.ant.types.ZipScanner;
import junit.framework.TestCase;
-import com.google.gwt.thirdparty.apache.ant.types.ZipScanner;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
diff --git a/dev/core/test/com/google/gwt/dev/shell/SuperDevListenerTest.java b/dev/core/test/com/google/gwt/dev/shell/SuperDevListenerTest.java
new file mode 100644
index 00000000000..354d04260e0
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/shell/SuperDevListenerTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2024 Google Inc.
+ *
+ * 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 com.google.gwt.dev.shell;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.DevMode;
+import com.google.gwt.dev.HostedModeOptionsMock;
+import com.google.gwt.dev.jjs.JsOutputOption;
+import com.google.gwt.dev.util.arg.OptionMethodNameDisplayMode;
+import com.google.gwt.dev.util.arg.SourceLevel;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
+import com.google.gwt.util.regexfilter.WhitelistRegexFilter;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A wide variety of tests on {@link SuperDevListener}.
+ */
+public class SuperDevListenerTest extends TestCase {
+ private static final int TEST_PORT = 9998;
+ private static final String MODULE_NAME = "Test_Module_Name";
+ private final TreeLogger treeLogger = new FailErrorLogger();
+ private final DevMode.HostedModeOptions options = new HostedModeOptionsMock();
+ private final WhitelistRegexFilter whitelistRegexFilter = new WhitelistRegexFilter();
+ private File warDir;
+ @Override
+ public void setUp() throws IOException {
+ warDir = Files.createTempDirectory("war-file").toFile();
+ warDir.deleteOnExit();
+ setUpOptions(options);
+ }
+
+ private void setUpOptions(DevMode.HostedModeOptions optionsToPrepare) {
+ optionsToPrepare.setCodeServerPort(TEST_PORT);
+ optionsToPrepare.setSourceLevel(SourceLevel.JAVA17);
+ optionsToPrepare.setWarDir(warDir);
+ optionsToPrepare.setOutput(JsOutputOption.DETAILED);
+ optionsToPrepare.setGenerateJsInteropExports(false);
+ optionsToPrepare.setIncrementalCompileEnabled(true);
+ optionsToPrepare.setMethodNameDisplayMode(OptionMethodNameDisplayMode.Mode.NONE);
+ optionsToPrepare.setStrict(false);
+ optionsToPrepare.setModuleNames(ImmutableList.of(MODULE_NAME));
+ }
+
+ public void testDefaultArgs() {
+ final SuperDevListener superDevListener = new SuperDevListener(treeLogger, options);
+ final List codeServerArgs = superDevListener.getCodeServerArgs();
+ assertEquals("Wrong default arguments", 10, codeServerArgs.size());
+ assertTrue("Precompile flag should set", codeServerArgs.contains("-noprecompile"));
+ assertTrue("Port should set", codeServerArgs.contains("-port"));
+ assertTrue("Port should set", codeServerArgs.contains(Integer.toString(TEST_PORT)));
+ assertTrue("SourceLevel should set", codeServerArgs.contains("-sourceLevel"));
+ assertTrue("SourceLevel should set", codeServerArgs.contains(SourceLevel.JAVA17.getStringValue()));
+ assertTrue("LauncherDir should set", codeServerArgs.contains("-launcherDir"));
+ assertTrue("LauncherDir should set", codeServerArgs.contains(warDir.getAbsolutePath()));
+ assertTrue("Style should set", codeServerArgs.contains("-style"));
+ assertTrue("Style should set", codeServerArgs.contains("DETAILED"));
+ assertTrue("Module name should set", codeServerArgs.contains(MODULE_NAME));
+ }
+
+ public void testDefaultNonSuperDevModePort() {
+ final int port = 9997;
+ options.setCodeServerPort(port);
+ final SuperDevListener superDevListener = new SuperDevListener(treeLogger, options);
+ final List codeServerArgs = superDevListener.getCodeServerArgs();
+ assertTrue("Port should set", codeServerArgs.contains("-port"));
+ assertTrue("SuperDevMode Default port should set", codeServerArgs.contains("9876"));
+ }
+
+ public void testWithJsInteropAndSingleIncludeAndExclude() {
+ options.setGenerateJsInteropExports(true);
+ options.getJsInteropExportFilter().add("-com.google.gwt.exclude.First");
+ options.getJsInteropExportFilter().add("com.google.gwt.include.First");
+
+ final SuperDevListener superDevListener = new SuperDevListener(treeLogger, options);
+ final List codeServerArgs = superDevListener.getCodeServerArgs();
+ assertTrue("GenerateJsInteropExports should set", codeServerArgs.contains("-generateJsInteropExports"));
+ assertTrue("ExcludeJsInteropExports should set", codeServerArgs.contains("-excludeJsInteropExports"));
+ assertTrue("ExcludeJsInteropExports should set", codeServerArgs.contains("com.google.gwt.exclude.First"));
+ assertTrue("IncludeJsInteropExports should set", codeServerArgs.contains("-includeJsInteropExports"));
+ assertTrue("IncludeJsInteropExports should set", codeServerArgs.contains("com.google.gwt.include.First"));
+ }
+
+ public void testWithJsInteropIncludesAndExcludes() {
+ options.setGenerateJsInteropExports(true);
+ options.getJsInteropExportFilter().add("-com.google.gwt.exclude.First");
+ options.getJsInteropExportFilter().add("com.google.gwt.include.First");
+ options.getJsInteropExportFilter().add("-com.google.gwt.exclude.Second");
+ options.getJsInteropExportFilter().add("com.google.gwt.include.Second");
+
+ final SuperDevListener superDevListener = new SuperDevListener(treeLogger, options);
+ final List codeServerArgs = superDevListener.getCodeServerArgs();
+ final int generateJsExportsIndex = codeServerArgs.indexOf("-generateJsInteropExports") + 1;
+ final List expectedJsExports = createExpectedJsIncludesAndExcludesgetStrings();
+
+ assertTrue("GenerateJsInteropExports should set", generateJsExportsIndex > 0);
+ final List actualJsExports = codeServerArgs.subList(generateJsExportsIndex, codeServerArgs.size());
+ for (int expectedIndex = 0; expectedIndex < expectedJsExports.size(); expectedIndex++) {
+ assertEquals("Setting for JS export not found", expectedJsExports.get(expectedIndex),
+ actualJsExports.get(expectedIndex));
+ }
+ }
+
+ public void testWithJsInteropAndCustomRegexFilter() {
+ final HostedModeOptionsMockWithCustomRegexFilter customOptions = new HostedModeOptionsMockWithCustomRegexFilter();
+ setUpOptions(customOptions);
+ customOptions.setGenerateJsInteropExports(true);
+ customOptions.getJsInteropExportFilter().add("-com.google.gwt.exclude.First");
+ customOptions.getJsInteropExportFilter().add("com.google.gwt.include.First");
+ customOptions.getJsInteropExportFilter().add("-com.google.gwt.exclude.Second");
+ customOptions.getJsInteropExportFilter().add("com.google.gwt.include.Second");
+ customOptions.getJsInteropExportFilter().add("+com.google.gwt.include.Third");
+ customOptions.getJsInteropExportFilter().add("*com.google.gwt.include.Fourth");
+
+ final SuperDevListener superDevListener = new SuperDevListener(treeLogger, customOptions);
+ final List codeServerArgs = superDevListener.getCodeServerArgs();
+ final int generateJsExportsIndex = codeServerArgs.indexOf("-generateJsInteropExports") + 1;
+ final List expectedJsExports = createExpectedJsIncludesAndExcludesgetStrings();
+ expectedJsExports.add("-includeJsInteropExports");
+ expectedJsExports.add("com.google.gwt.include.Third");
+ expectedJsExports.add("-includeJsInteropExports");
+ expectedJsExports.add("*com.google.gwt.include.Fourth");
+
+ assertTrue("GenerateJsInteropExports should set", generateJsExportsIndex > 0);
+ final List actualJsExports = codeServerArgs.subList(generateJsExportsIndex, codeServerArgs.size());
+ for (int expectedIndex = 0; expectedIndex < expectedJsExports.size(); expectedIndex++) {
+ assertEquals("Setting for JS export not found", expectedJsExports.get(expectedIndex),
+ actualJsExports.get(expectedIndex));
+ }
+ }
+
+ private static List createExpectedJsIncludesAndExcludesgetStrings() {
+ final List expectedJsExports = new ArrayList<>();
+ expectedJsExports.add("-excludeJsInteropExports");
+ expectedJsExports.add("com.google.gwt.exclude.First");
+ expectedJsExports.add("-includeJsInteropExports");
+ expectedJsExports.add("com.google.gwt.include.First");
+ expectedJsExports.add("-excludeJsInteropExports");
+ expectedJsExports.add("com.google.gwt.exclude.Second");
+ expectedJsExports.add("-includeJsInteropExports");
+ expectedJsExports.add("com.google.gwt.include.Second");
+ return expectedJsExports;
+ }
+
+ private static class HostedModeOptionsMockWithCustomRegexFilter extends HostedModeOptionsMock {
+ private final WhitelistRegexFilter whitelistRegexFilter = new CustomWhitelistRegexFilter();
+ @Override
+ public WhitelistRegexFilter getJsInteropExportFilter() {
+ return whitelistRegexFilter;
+ }
+ }
+ private static class CustomWhitelistRegexFilter extends WhitelistRegexFilter {
+ private final List values = new ArrayList<>();
+ @Override
+ public List getValues() {
+ return values;
+ }
+ @Override
+ public void add(String regex) {
+ values.add(regex);
+ }
+ @Override
+ public void addAll(List newValues) {
+ values.addAll(newValues);
+ }
+ }
+}
diff --git a/dev/core/test/org/apache/commons/collections/AbstractTestObject.java b/dev/core/test/org/apache/commons/collections/AbstractTestObject.java
index 135c7e0d63d..4bc2e948a9d 100644
--- a/dev/core/test/org/apache/commons/collections/AbstractTestObject.java
+++ b/dev/core/test/org/apache/commons/collections/AbstractTestObject.java
@@ -120,6 +120,7 @@ public void testObjectHashCodeEqualsSelfHashCode() {
assertEquals("hashCode should be repeatable", obj.hashCode(), obj.hashCode());
}
+ @SuppressWarnings("SelfEquals")
public void testObjectHashCodeEqualsContract() {
Object obj1 = makeObject();
if (obj1.equals(obj1)) {
diff --git a/dev/core/test/org/apache/commons/collections/collection/AbstractTestCollection.java b/dev/core/test/org/apache/commons/collections/collection/AbstractTestCollection.java
index 0de0fe304da..48ddd32b4f6 100644
--- a/dev/core/test/org/apache/commons/collections/collection/AbstractTestCollection.java
+++ b/dev/core/test/org/apache/commons/collections/collection/AbstractTestCollection.java
@@ -805,6 +805,7 @@ public void testCollectionIterator() {
/**
* Tests removals from {@link Collection#iterator()}.
*/
+ @SuppressWarnings("ReturnValueIgnored")
public void testCollectionIteratorRemove() {
if (!isRemoveSupported()) return;
diff --git a/distro-source/build.xml b/distro-source/build.xml
index 90e0448383c..55c712802f2 100755
--- a/distro-source/build.xml
+++ b/distro-source/build.xml
@@ -31,10 +31,8 @@
-
-
+
-
diff --git a/doc/build.xml b/doc/build.xml
index 97c85ef8e47..3d0f89d353b 100644
--- a/doc/build.xml
+++ b/doc/build.xml
@@ -90,7 +90,7 @@