diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..ca79ca5b4d5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/full-check.yml b/.github/workflows/full-check.yml index 9d98ad5f809..fe3a0829ffd 100644 --- a/.github/workflows/full-check.yml +++ b/.github/workflows/full-check.yml @@ -1,4 +1,4 @@ -# Run all tests and builds all aspects of GWT using Java 8, 11, and 17. Runs +# Run all tests and builds all aspects of GWT using Java 11, 17, and 21. Runs # nightly (plus or minus timzeones) on the main branch, and will also run right # away on a push to a release branch. Release zips are uploaded as part of the # build, though maven snapshots are not yet deployed. @@ -20,20 +20,20 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java-version: [ '8', '11', '17' ] + java-version: [ '11', '17', '21' ] steps: - name: Checkout GWT itself into one directory - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: 'gwt' - name: Checkout GWT tools into a sibling directory - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: 'gwtproject/tools' path: 'tools' - name: Set up JDK ${{ matrix.java-version }} - # GWT presently requires Java8 to build just the SDK and some tests, or 11 to build everything, but can run on newer Java versions - uses: actions/setup-java@v3 + # GWT requires Java 11+ to build + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java-version }} distribution: 'temurin' @@ -57,33 +57,33 @@ jobs: -Dtest.emma.htmlunit.disable=true - name: Report test results - uses: mikepenz/action-junit-report@v3.1.0 + uses: mikepenz/action-junit-report@v4.2.1 if: always() with: report_paths: 'gwt/build/out/**/test/**/reports/TEST-*.xml' - name: Upload checkstyle xml for manual review in its own artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: checkstyle-reports-java${{ matrix.java-version }} path: 'gwt/build/out/**/checkstyle*.xml' - name: Upload test xml files for manual review in its own artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: junit-reports-java${{ matrix.java-version }} path: 'gwt/build/out/**/test/**/reports/TEST-*.xml' - name: On success, upload the release zip - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: gwt-java${{ matrix.java-version }} path: 'gwt/build/dist/gwt-*.zip' - name: Set up sonatype credentials # Using the same java version as above, set up a settings.xml file - uses: actions/setup-java@v3 - if: ${{ github.event_name == 'schedule' && github.repository_owner == 'gwtproject' && matrix.java-version == '17' }} + uses: actions/setup-java@v4 + if: ${{ github.event_name == 'schedule' && github.repository_owner == 'gwtproject' && matrix.java-version == '21' }} with: java-version: ${{ matrix.java-version }} distribution: 'temurin' @@ -93,7 +93,7 @@ jobs: server-password: SONATYPE_PASSWORD - name: Nightly builds should be deployed as snapshots to sonatype - if: ${{ github.event_name == 'schedule' && github.repository_owner == 'gwtproject' && matrix.java-version == '17' }} + if: ${{ github.event_name == 'schedule' && github.repository_owner == 'gwtproject' && matrix.java-version == '21' }} env: SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} diff --git a/.github/workflows/quick-check.yml b/.github/workflows/quick-check.yml index 75c861c4699..5dfdfd55cc1 100644 --- a/.github/workflows/quick-check.yml +++ b/.github/workflows/quick-check.yml @@ -8,22 +8,22 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java-version: ['8', '11', '17'] + java-version: ['11', '17', '21'] steps: - name: Checkout GWT itself into one directory - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: 'gwt' # we need depth=2 to see which style violations overlap with the current changes fetch-depth: 2 - name: Checkout GWT tools into a sibling directory - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: 'gwtproject/tools' path: 'tools' - name: Set up JDK ${{ matrix.java-version }} - # GWT presently requires Java8 to build just the SDK and some tests, or 11+ to build everything, and can run on newer Java versions - uses: actions/setup-java@v3 + # GWT presently requires Java 11+ to build + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java-version }} distribution: 'temurin' @@ -44,8 +44,8 @@ jobs: ANT_OPTS=-Xmx2g ant clean dist doc checkstyle apicheck - - name: Create pull request comments/annotations for checkstyle from the java 17 build, even on failure - if: ${{ always() && github.event_name == 'pull_request' && matrix.java-version == '17' }} + - name: Create pull request comments/annotations for checkstyle from the java 21 build, even on failure + if: ${{ always() && github.event_name == 'pull_request' && matrix.java-version == '21' }} env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -57,8 +57,8 @@ jobs: reviewdog -f=checkstyle -filter-mode=diff_context -reporter=github-pr-review -level=info < $f done - name: Upload checkstyle xml for manual review - uses: actions/upload-artifact@v2 - if: ${{ matrix.java-version == '17' }} + uses: actions/upload-artifact@v4 + if: ${{ matrix.java-version == '21' }} with: name: checkstyle-reports-java${{ matrix.java-version }} path: 'gwt/build/out/**/checkstyle*.xml' diff --git a/build.xml b/build.xml index 4ab2c6e8f58..c10eea6f2c5 100755 --- a/build.xml +++ b/build.xml @@ -98,7 +98,7 @@ - + diff --git a/build_tools/doctool/build.xml b/build_tools/doctool/build.xml index c4870197b61..a210edd4780 100644 --- a/build_tools/doctool/build.xml +++ b/build_tools/doctool/build.xml @@ -11,7 +11,7 @@ - + diff --git a/common.ant.xml b/common.ant.xml index 36a56b4882d..7f8244aea7d 100755 --- a/common.ant.xml +++ b/common.ant.xml @@ -27,12 +27,6 @@ message="This build file is in an inconsistent state (${ant.file} != ${test.ant.file})."/> - - - - @@ -47,7 +41,6 @@ - @@ -55,7 +48,6 @@ - @@ -66,11 +58,9 @@ - - - - + + @@ -170,20 +160,19 @@ - - - - - - - - - - - + fork="true" excludes="@{excludes}"> + + + + + + + + + + @@ -249,7 +238,7 @@ - + @@ -346,8 +335,8 @@ - + @@ -366,8 +355,8 @@ - + - + @@ -40,13 +32,7 @@ + excludes="**/EmulatedCharset.java,**/HashCodes.java,**/ConsoleLogger.java,**/NativeRegExp.java,**/SuperDevModeLogger.java"> @@ -77,11 +63,11 @@ - - - - - + + + + + @@ -133,16 +119,16 @@ - - - + + + + src="${gwt.tools.lib}/eclipse/org.eclipse.jdt.core_3.32.0.v20221108-1853.jar"/> + src="${gwt.tools.lib}/eclipse/jdtCompilerAdapter_3.32.0.v20221108-1853.jar"/> - + @@ -236,15 +217,15 @@ - - - + + + + location="${gwt.tools.lib}/eclipse/org.eclipse.jdt.core_3.32.0.v20221108-1853.jar"/> + location="${gwt.tools.lib}/eclipse/jdtCompilerAdapter_3.32.0.v20221108-1853.jar"/> @@ -259,12 +240,7 @@ - + diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java index 273e63cf4f2..de636e81258 100644 --- a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java +++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java @@ -121,7 +121,7 @@ void start(final TreeLogger logger) throws UnableToCompleteException { ServerConnector connector = new ServerConnector(newServer); connector.setHost(bindAddress); connector.setPort(port); - connector.setReuseAddress(false); + connector.setReuseAddress(true); newServer.addConnector(connector); ServletContextHandler newHandler = new ServletContextHandler(ServletContextHandler.GZIP); diff --git a/dev/core/src/com/google/gwt/core/ext/Linker.java b/dev/core/src/com/google/gwt/core/ext/Linker.java index 4b81f59ba16..23e87a678ca 100644 --- a/dev/core/src/com/google/gwt/core/ext/Linker.java +++ b/dev/core/src/com/google/gwt/core/ext/Linker.java @@ -62,6 +62,7 @@ public abstract class Linker { * intended to support linkers that must compile against older versions of * GWT. */ + @SuppressWarnings("ReturnValueIgnored") public final boolean isShardable() { if (getClass().isAnnotationPresent(Shardable.class)) { return true; diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java index c0e5748c233..c63a0132b78 100644 --- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java +++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java @@ -787,7 +787,8 @@ private static void resolveRecursive(ReferenceBinding outerType) { SourceLevel.JAVA8, ClassFileConstants.JDK1_8, SourceLevel.JAVA9, ClassFileConstants.JDK9, SourceLevel.JAVA10, ClassFileConstants.JDK10, - SourceLevel.JAVA11, ClassFileConstants.JDK11); + SourceLevel.JAVA11, ClassFileConstants.JDK11, + SourceLevel.JAVA17, ClassFileConstants.JDK17); public JdtCompiler(CompilerContext compilerContext, UnitProcessor processor) { this.compilerContext = compilerContext; diff --git a/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java b/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java index 0a4faecf5e8..3391e0c5e90 100644 --- a/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java +++ b/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java @@ -17,7 +17,6 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.dev.javac.MemoryUnitCache.UnitCacheEntry; import com.google.gwt.thirdparty.guava.common.collect.Maps; import java.util.Map; diff --git a/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java b/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java index fb272cd4904..3532013288e 100644 --- a/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java +++ b/dev/core/src/com/google/gwt/dev/javac/UnitCacheSingleton.java @@ -17,7 +17,6 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; - import com.google.gwt.dev.jjs.JJSOptions; import com.google.gwt.thirdparty.guava.common.base.Joiner; import com.google.gwt.util.tools.shared.Md5Utils; diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/HasJsInfo.java b/dev/core/src/com/google/gwt/dev/jjs/ast/HasJsInfo.java index 23e01968f02..05a6f9e8dda 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/HasJsInfo.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/HasJsInfo.java @@ -117,7 +117,7 @@ public String computeName(JMember member) { private static boolean startsWithCamelCase(String string, String prefix) { return string.length() > prefix.length() && string.startsWith(prefix) - && Character.isUpperCase(string.charAt(prefix.length())); + && !Character.isLowerCase(string.charAt(prefix.length())); } } diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java index 58334327c2b..a52a8897613 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java @@ -194,6 +194,7 @@ import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation; import org.eclipse.jdt.internal.compiler.ast.SuperReference; +import org.eclipse.jdt.internal.compiler.ast.SwitchExpression; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; @@ -537,13 +538,25 @@ public void endVisit(BreakStatement x, BlockScope scope) { @Override public void endVisit(CaseStatement x, BlockScope scope) { + if (x.isExpr) { + InternalCompilerException exception = + new InternalCompilerException("Switch expressions not yet supported"); + exception.addNode(new JCaseStatement(makeSourceInfo(x), null)); + throw exception; + } try { SourceInfo info = makeSourceInfo(x); - JExpression caseExpression = pop(x.constantExpression); - if (caseExpression != null && x.constantExpression.resolvedType.isEnum()) { - caseExpression = synthesizeCallToOrdinal(scope, info, caseExpression); + if (x.constantExpressions == null) { + push(new JCaseStatement(info, null)); + } else { + for (Expression constantExpression : x.constantExpressions) { + JExpression caseExpression = pop(constantExpression); + if (caseExpression != null && caseExpression.getType().isEnumOrSubclass() != null) { + caseExpression = synthesizeCallToOrdinal(scope, info, caseExpression); + } + push(new JCaseStatement(info, caseExpression)); + } } - push(new JCaseStatement(info, caseExpression)); } catch (Throwable e) { throw translateException(x, e); } @@ -2534,6 +2547,14 @@ public boolean visit(Initializer x, MethodScope scope) { } } + @Override + public boolean visit(SwitchExpression x, BlockScope blockScope) { + InternalCompilerException exception = + new InternalCompilerException("Switch expressions not yet supported"); + exception.addNode(new JCaseStatement(makeSourceInfo(x), null)); + throw exception; + } + @Override public boolean visit(LocalDeclaration x, BlockScope scope) { try { @@ -2752,6 +2773,12 @@ protected void pushBinaryOp(BinaryExpression x, JBinaryOperator op) { } protected boolean visit(TypeDeclaration x) { + if (x.isRecord()) { + InternalCompilerException exception = + new InternalCompilerException("Records not yet supported"); + exception.addNode(new JClassType(makeSourceInfo(x), intern(x.name), false, false)); + throw exception; + } JDeclaredType type = (JDeclaredType) typeMap.get(x.binding); assert !type.isExternal(); classStack.push(curClass); @@ -3706,7 +3733,6 @@ private JType[] processCastType(TypeBinding type) { } } - private boolean isFunctionalInterfaceWithMethod(ReferenceBinding referenceBinding, Scope scope, String samSignature) { if (!referenceBinding.isInterface()) { diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java index 23fe33c6476..86f4850b650 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java @@ -386,8 +386,9 @@ private InlineResult tryInlineBody(JMethodCall x, Context ctx, return InlineResult.DO_NOT_BLACKLIST; } } - // Fall through! + // CHECKSTYLE_OFF: Fall through! case CORRECT_ORDER: + // CHECKSTYLE_ON default: if (!x.hasSideEffects()) { markCallsAsSideEffectFree(bodyAsExpressionList); diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java index 779bffc0c8e..63e50bda61c 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java @@ -58,6 +58,8 @@ public enum TypeOrder { /** * Maps a type into a type id literal. + * + * @param the runtime type to use when replacing a type id */ public interface TypeMapper { T getOrCreateTypeId(JType type); diff --git a/dev/core/src/com/google/gwt/dev/js/JsUtils.java b/dev/core/src/com/google/gwt/dev/js/JsUtils.java index 4e964d24c56..dbad2c108a2 100644 --- a/dev/core/src/com/google/gwt/dev/js/JsUtils.java +++ b/dev/core/src/com/google/gwt/dev/js/JsUtils.java @@ -47,7 +47,6 @@ import java.util.Collections; import java.util.List; - import java.util.regex.Pattern; /** @@ -480,7 +479,7 @@ public static JsFunction isFunctionDeclaration(JsStatement stmt) { /** * A JavaScript identifier contains only letters, numbers, _, $ and does not begin with a number. * There are actually other valid identifiers, such as ones that contain escaped Unicode - * characters but we disallow those for the time being. + * characters, but we disallow those for the time being. */ public static boolean isValidJsIdentifier(String name) { return JAVASCRIPT_VALID_IDENTIFIER_PATTERN.matcher(name).matches(); diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java b/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java index 1fed6e5185d..4b4455f3ef7 100644 --- a/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java +++ b/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java @@ -198,6 +198,8 @@ public interface RemoteObjectRef { /** * Hook interface for responding to messages. + * + * @param the BrowserChannel type this implementation is built to handle. */ public abstract static class SessionHandler { diff --git a/dev/core/src/com/google/gwt/dev/shell/StaticResourceServer.java b/dev/core/src/com/google/gwt/dev/shell/StaticResourceServer.java new file mode 100644 index 00000000000..e4fdb9fea4a --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/StaticResourceServer.java @@ -0,0 +1,191 @@ +/* + * 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; + +import com.google.gwt.core.ext.ServletContainer; +import com.google.gwt.core.ext.ServletContainerLauncher; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.shell.jetty.ClientAuthType; +import com.google.gwt.dev.shell.jetty.JettyLauncherUtils; +import com.google.gwt.dev.shell.jetty.JettyTreeLogger; +import com.google.gwt.dev.shell.jetty.SslConfiguration; + +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ErrorPageErrorHandler; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.WebAppContext; + +import java.io.File; +import java.util.Optional; + +/** + * Simple webserver that only hosts static resources. Intended to be the replacement + * for JettyLauncher. + */ +public class StaticResourceServer extends ServletContainerLauncher { + + private String bindAddress = null; + + private SslConfiguration sslConfig = new SslConfiguration(ClientAuthType.NONE, null, null, false); + + @Override + public String getName() { + return "StaticResourceServer"; + } + + @Override + public void setBindAddress(String bindAddress) { + this.bindAddress = bindAddress; + } + + @Override + public boolean isSecure() { + return sslConfig.isUseSsl(); + } + + private void checkStartParams(TreeLogger logger, int port, File appRootDir) { + if (logger == null) { + throw new NullPointerException("logger cannot be null"); + } + + if (port < 0 || port > 65535) { + throw new IllegalArgumentException( + "port must be either 0 (for auto) or less than 65536"); + } + + if (appRootDir == null) { + throw new NullPointerException("app root directory cannot be null"); + } + } + + @Override + public boolean processArguments(TreeLogger logger, String arguments) { + if (arguments != null && arguments.length() > 0) { + Optional parsed = SslConfiguration.parseArgs(arguments.split(","), logger); + if (parsed.isPresent()) { + sslConfig = parsed.get(); + } else { + return false; + } + } + return true; + } + + + @Override + public ServletContainer start(TreeLogger logger, int port, File appRootDir) throws Exception { + TreeLogger branch = logger.branch(TreeLogger.TRACE, + "Starting StaticResourceServer on port " + port, null); + + checkStartParams(branch, port, appRootDir); + + // During startup, use the branch logger, we'll reset this later to the root logger + Log.setLog(new JettyTreeLogger(branch)); + + Server server = new Server(); + + ServerConnector connector = JettyLauncherUtils.getConnector(server, sslConfig, branch); + JettyLauncherUtils.setupConnector(connector, bindAddress, port); + server.addConnector(connector); + + WebAppContext webAppContext = new WebAppContext(null, "/", null, null, null, + new ErrorPageErrorHandler(), ServletContextHandler.NO_SECURITY); + webAppContext.setWar(appRootDir.getAbsolutePath()); + webAppContext.setSecurityHandler(new ConstraintSecurityHandler()); + + server.setHandler(webAppContext); + + server.start(); + server.setStopAtShutdown(true); + + // Now that we're started, log to the top level logger. + Log.setLog(new JettyTreeLogger(logger)); + + // DevMode#doStartUpServer() fails from time to time (rarely) due + // to an unknown error. Adding some logging to pinpoint the problem. + int connectorPort = connector.getLocalPort(); + if (connector.getLocalPort() < 0) { + branch.log(TreeLogger.ERROR, String.format( + "Failed to connect to open channel with port %d (return value %d)", + port, connectorPort)); + } + + return new StaticServerImpl(connectorPort, appRootDir, branch, server); + } + + private static final class StaticServerImpl extends ServletContainer { + private final int port; + private final File appRootDir; + private final TreeLogger logger; + private final Server server; + + private StaticServerImpl(int port, File appRootDir, TreeLogger logger, Server server) { + this.port = port; + this.appRootDir = appRootDir; + this.logger = logger; + this.server = server; + } + + @Override + public int getPort() { + return port; + } + + @Override + public void refresh() throws UnableToCompleteException { + String msg = "Reloading web app to reflect changes in " + + appRootDir.getAbsolutePath(); + TreeLogger branch = logger.branch(TreeLogger.INFO, msg); + // Temporarily log Jetty on the branch. + Log.setLog(new JettyTreeLogger(branch)); + try { + server.stop(); + server.start(); + branch.log(TreeLogger.INFO, "Reload completed successfully"); + } catch (Exception e) { + branch.log(TreeLogger.ERROR, "Unable to restart StaticResourceServer server", + e); + throw new UnableToCompleteException(); + } finally { + // Reset the top-level logger. + Log.setLog(new JettyTreeLogger(logger)); + } + } + + @Override + public void stop() throws UnableToCompleteException { + TreeLogger branch = logger.branch(TreeLogger.INFO, + "Stopping StaticResourceServer server"); + // Temporarily log Jetty on the branch. + Log.setLog(new JettyTreeLogger(branch)); + try { + server.stop(); + server.setStopAtShutdown(false); + branch.log(TreeLogger.TRACE, "Stopped successfully"); + } catch (Exception e) { + branch.log(TreeLogger.ERROR, "Unable to stop embedded StaticResourceServer server", e); + throw new UnableToCompleteException(); + } finally { + // Reset the top-level logger. + Log.setLog(new JettyTreeLogger(logger)); + } + } + } +} diff --git a/dev/core/src/com/google/gwt/dev/shell/SuperDevListener.java b/dev/core/src/com/google/gwt/dev/shell/SuperDevListener.java index 76cb5833a59..0a6fb34bd99 100644 --- a/dev/core/src/com/google/gwt/dev/shell/SuperDevListener.java +++ b/dev/core/src/com/google/gwt/dev/shell/SuperDevListener.java @@ -23,6 +23,7 @@ import com.google.gwt.dev.DevMode.HostedModeOptions; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.util.arg.OptionMethodNameDisplayMode; +import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting; import com.google.gwt.thirdparty.guava.common.base.Stopwatch; import com.google.gwt.thirdparty.guava.common.collect.ListMultimap; import com.google.gwt.thirdparty.guava.common.collect.Lists; @@ -63,6 +64,11 @@ public int getSocketPort() { return codeServerPort; } + @VisibleForTesting + List getCodeServerArgs() { + return codeServerArgs; + } + @Override public URL makeStartupUrl(String url) throws UnableToCompleteException { try { @@ -174,7 +180,7 @@ private static List makeCodeServerArgs(HostedModeOptions options, int po args.add(regex.substring(1)); } else { args.add("-includeJsInteropExports"); - args.add(regex); + args.add(regex.startsWith("+") ? regex.substring(1) : regex); } } if (!options.isIncrementalCompileEnabled()) { diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/ClientAuthType.java b/dev/core/src/com/google/gwt/dev/shell/jetty/ClientAuthType.java new file mode 100644 index 00000000000..c772e478fca --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/jetty/ClientAuthType.java @@ -0,0 +1,25 @@ +/* + * 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; + +/** + * Represents the type of SSL client certificate authentication desired. + */ +public enum ClientAuthType { + NONE, + WANT, + REQUIRE, +} diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java index 69b1dc9dd79..c5d3cbcccd9 100644 --- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java +++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java @@ -27,26 +27,20 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Response; -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.server.handler.RequestLogHandler; import org.eclipse.jetty.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.preventers.AppContextLeakPreventer; import org.eclipse.jetty.util.preventers.DOMLeakPreventer; import org.eclipse.jetty.util.preventers.GCThreadLeakPreventer; import org.eclipse.jetty.util.preventers.SecurityProviderLeakPreventer; -import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.webapp.ClasspathPattern; import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.WebAppClassLoader; @@ -63,11 +57,46 @@ import java.util.Enumeration; import java.util.Iterator; import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; /** * A {@link ServletContainerLauncher} for an embedded Jetty server. + *

+ * @deprecated please migrate to {@link com.google.gwt.dev.shell.StaticResourceServer}, + * or provide your own implementation. */ +@Deprecated public class JettyLauncher extends ServletContainerLauncher { + private static final AtomicBoolean hasLoggedDeprecationWarning = new AtomicBoolean(false); + + /** + * Disable warning about JettyLauncher being deprecated when running tests, as this only is + * intended to apply to DevMode - The test runner can be updated at the same time as any other + * changes are made to JettyLauncher. + */ + public static void suppressDeprecationWarningForTests() { + hasLoggedDeprecationWarning.set(true); + } + + /** + * Warns, only once, that JettyLauncher is deprecated for removal. Call when it is clear that + * the developer is actively deploying code to, or loading resources from, the embedded Jetty + * instance. + * + * @param log existing TreeLogger to append warning to + */ + private static void maybeLogDeprecationWarning(TreeLogger log) { + if (hasLoggedDeprecationWarning.compareAndSet(false, true)) { + log.log(TreeLogger.Type.WARN, "DevMode will default to -noserver in a future release, and " + + "JettyLauncher may be removed or changed. Please consider running your own " + + "application server and either passing -noserver to DevMode or migrating to " + + "CodeServer. Alternatively, consider implementing your own " + + "ServletContainerLauncher to continue running your application server from " + + "DevMode."); + } + } /** * Log jetty requests/responses to TreeLogger. @@ -93,6 +122,10 @@ public void log(Request request, Response response) { // Copied from NCSARequestLog status = 404; } + if (status != 404) { + // Ignore 404 errors, log the first other call to the server if we haven't logged yet + maybeLogDeprecationWarning(logger); + } TreeLogger.Type logStatus, logHeaders; if (status >= 500) { logStatus = TreeLogger.ERROR; @@ -150,120 +183,15 @@ private void logHeaders(TreeLogger logger, TreeLogger.Type logLevel, HttpFields } /** - * An adapter for the Jetty logging system to GWT's TreeLogger. This - * implementation class is only public to allow {@link Log} to instantiate it. - * - * The weird static data / default construction setup is a game we play with - * {@link Log}'s static initializer to prevent the initial log message from - * going to stderr. + * An adapter for the Jetty logging system to GWT's TreeLogger. + * @deprecated use {@link com.google.gwt.dev.shell.jetty.JettyTreeLogger} instead. */ - public static class JettyTreeLogger implements Logger { - private final TreeLogger logger; - + @Deprecated + public static class JettyTreeLogger extends com.google.gwt.dev.shell.jetty.JettyTreeLogger { 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(); + super(logger); } } - /** * The resulting {@link ServletContainer} this is launched. */ @@ -566,6 +494,15 @@ private WebAppContextWithReload(TreeLogger logger, String webApp, protected void doStart() throws Exception { setClassLoader(new WebAppClassLoaderExtension()); super.doStart(); + + // After start, warn if a servlet/filter was configured other than those provided by Jetty + boolean hasNonJettyFiltersOrServlets = Stream.concat( + getServletContext().getServletRegistrations().values().stream(), + getServletContext().getFilterRegistrations().values().stream() + ).anyMatch(r -> !r.getClassName().startsWith("org.eclipse.jetty")); + if (hasNonJettyFiltersOrServlets) { + maybeLogDeprecationWarning(logger); + } } @Override @@ -581,15 +518,6 @@ protected void doStop() throws Exception { } } - /** - * Represents the type of SSL client certificate authentication desired. - */ - private enum ClientAuth { - NONE, - WANT, - REQUIRE, - } - /** * System property to suppress warnings about loading web app classes from the * system classpath. @@ -605,13 +533,7 @@ private enum ClientAuth { */ private static void setupConnector(ServerConnector connector, String bindAddress, int port) { - if (bindAddress != null) { - connector.setHost(bindAddress.toString()); - } - connector.setPort(port); - - // Allow binding to a port even if it's still in state TIME_WAIT. - connector.setReuseAddress(true); + JettyLauncherUtils.setupConnector(connector, bindAddress, port); } // default value used if setBaseLogLevel isn't called @@ -619,15 +541,10 @@ private static void setupConnector(ServerConnector connector, private String bindAddress = null; - private ClientAuth clientAuth; - - private String keyStore; - - private String keyStorePassword; + private SslConfiguration sslConfig = new SslConfiguration(ClientAuthType.NONE, null, null, false); private final Object privateInstanceLock = new Object(); - private boolean useSsl; @Override public String getName() { @@ -636,71 +553,17 @@ public String getName() { @Override public boolean isSecure() { - return useSsl; + return sslConfig.isUseSsl(); } @Override public boolean processArguments(TreeLogger logger, String arguments) { if (arguments != null && arguments.length() > 0) { - // TODO(jat): better parsing of the args - for (String arg : arguments.split(",")) { - 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 = getClass().getResource("localhost.keystore"); - if (keyStoreUrl == null) { - logger.log(TreeLogger.ERROR, "Default GWT keystore not found"); - return false; - } - 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 false; - } - keyStorePassword = keyStorePassword.trim(); - } else if ("clientAuth".equals(tag)) { - useSsl = true; - try { - clientAuth = ClientAuth.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 false; - } - } - if (useSsl) { - if (keyStore == null) { - logger.log(TreeLogger.ERROR, "A keystore is required to use SSL"); - return false; - } - if (keyStorePassword == null) { - logger.log(TreeLogger.ERROR, - "A keystore password is required to use SSL"); - return false; - } + Optional 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 @@ - + @@ -124,7 +124,7 @@ - + diff --git a/eclipse/settings/code-style/gwt-checkstyle-suppressions.xml b/eclipse/settings/code-style/gwt-checkstyle-suppressions.xml deleted file mode 100644 index c5181f9688f..00000000000 --- a/eclipse/settings/code-style/gwt-checkstyle-suppressions.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/eclipse/settings/code-style/gwt-checkstyle-tests.xml b/eclipse/settings/code-style/gwt-checkstyle-tests.xml index a9b5a73977f..9b6bfb18dd5 100644 --- a/eclipse/settings/code-style/gwt-checkstyle-tests.xml +++ b/eclipse/settings/code-style/gwt-checkstyle-tests.xml @@ -7,13 +7,13 @@ Checkstyle-Configuration: GWT Checks for Tests Description: A more lenient set of style checks for test cases, needed because test often need to do funkier stuff. --> - + - + @@ -23,7 +23,6 @@ A more lenient set of style checks for test cases, needed because test often nee - @@ -90,20 +89,17 @@ A more lenient set of style checks for test cases, needed because test often nee - - + - - - - - - - - + + + + + + @@ -215,33 +211,30 @@ A more lenient set of style checks for test cases, needed because test often nee + + + + + + + + + + + + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - + + diff --git a/eclipse/settings/code-style/gwt-checkstyle.xml b/eclipse/settings/code-style/gwt-checkstyle.xml index 2455ce28a60..222dfb5b7fd 100644 --- a/eclipse/settings/code-style/gwt-checkstyle.xml +++ b/eclipse/settings/code-style/gwt-checkstyle.xml @@ -7,13 +7,13 @@ Checkstyle-Configuration: GWT Checks Description: --> - + - + @@ -21,13 +21,12 @@ Description: + + + + - - - - - - + @@ -40,6 +39,7 @@ Description: + @@ -53,7 +53,7 @@ Description: - + @@ -86,20 +86,17 @@ Description: - - + - - - - - - - - + + + + + + @@ -198,33 +195,31 @@ Description: - - - - + - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - + + + - - - - - + + - - - diff --git a/maven/google-poms/gwt/pom-template.xml b/maven/google-poms/gwt/pom-template.xml index dc7f26bd3d5..777f51ed37f 100644 --- a/maven/google-poms/gwt/pom-template.xml +++ b/maven/google-poms/gwt/pom-template.xml @@ -22,7 +22,7 @@ 9.4.44.v20210927 - 9.2 + 9.6 diff --git a/maven/lib-gwt.sh b/maven/lib-gwt.sh index bb8ac49f7e4..4d3028523e7 100644 --- a/maven/lib-gwt.sh +++ b/maven/lib-gwt.sh @@ -115,14 +115,10 @@ function maven-gwt() { gwtPomFile=$pomDir/gwt/gwt-$i/pom.xml SOURCES_FILE=gwt-${i}-sources.jar SOURCES_PATH_FILE=$GWT_EXTRACT_DIR/$SOURCES_FILE - # If there are no sources, use gwt-user sources. - # This is a bit hacky but Sonatype requires a - # source jar for Central, and lack of sources - # should only happen for gwt-servlet and - # gwt-servlet-jakarta, which are basically a - # subset of gwt-user. + # If there are no sources, fail, this is a requirement of maven central if [ ! -f $SOURCES_PATH_FILE ]; then - SOURCES_PATH_FILE=$GWT_EXTRACT_DIR/gwt-user-sources.jar + echo "ERROR: sources jar not found for $i" + exit 1 fi maven-deploy-file $mavenRepoUrl $mavenRepoId "$CUR_FILE" $gwtPomFile "$JAVADOC_FILE_PATH" "$SOURCES_PATH_FILE" || die diff --git a/maven/poms/gwt/pom-template.xml b/maven/poms/gwt/pom-template.xml index 0f288bae1e9..0825e6cf471 100644 --- a/maven/poms/gwt/pom-template.xml +++ b/maven/poms/gwt/pom-template.xml @@ -22,7 +22,7 @@ 9.4.44.v20210927 - 9.2 + 9.6 diff --git a/maven/poms/requestfactory/pom-template.xml b/maven/poms/requestfactory/pom-template.xml index be33a705e5d..24964e89754 100644 --- a/maven/poms/requestfactory/pom-template.xml +++ b/maven/poms/requestfactory/pom-template.xml @@ -52,6 +52,11 @@ requestfactory-server ${project.version} + + org.gwtproject.web.bindery + requestfactory-server-jakarta + ${project.version} + javax.validation validation-api diff --git a/samples/validation/src/main/java/com/google/gwt/sample/validation/shared/Person.java b/samples/validation/src/main/java/com/google/gwt/sample/validation/shared/Person.java index c24ef952c19..6724a112a5f 100644 --- a/samples/validation/src/main/java/com/google/gwt/sample/validation/shared/Person.java +++ b/samples/validation/src/main/java/com/google/gwt/sample/validation/shared/Person.java @@ -16,7 +16,6 @@ package com.google.gwt.sample.validation.shared; import com.google.gwt.sample.validation.server.ServerConstraint; - import com.google.gwt.user.client.rpc.IsSerializable; import java.util.Map; diff --git a/servlet/build.xml b/servlet/build.xml index 60901a6876c..47d554892f1 100644 --- a/servlet/build.xml +++ b/servlet/build.xml @@ -13,7 +13,7 @@ location="${gwt.build.lib}/gwt-${ant.project.name}-deps.jar" /> + depends="-servlet, -servlet-jakarta, -servlet-sources, -servlet-jakarta-sources, -deps" /> @@ -30,7 +30,6 @@ - @@ -43,13 +42,28 @@ - - - - - + + + + + + + + + + + + + + + + + + + + @@ -62,7 +76,6 @@ - @@ -75,12 +88,28 @@ - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java index 313037c1aa8..2bfe463048f 100644 --- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java +++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiCompatibilityChecker.java @@ -24,12 +24,11 @@ import com.google.gwt.dev.util.arg.SourceLevel; import com.google.gwt.dev.util.log.AbstractTreeLogger; import com.google.gwt.dev.util.log.PrintWriterTreeLogger; +import com.google.gwt.thirdparty.apache.ant.types.ZipScanner; import com.google.gwt.util.tools.ArgHandlerFlag; import com.google.gwt.util.tools.ArgHandlerString; import com.google.gwt.util.tools.ToolBase; -import com.google.gwt.thirdparty.apache.ant.types.ZipScanner; - import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; diff --git a/user/build.xml b/user/build.xml index 1f43783a4c0..2af156012ff 100755 --- a/user/build.xml +++ b/user/build.xml @@ -14,27 +14,16 @@ - - - - + + - - - - - - + + - - - + @@ -59,7 +48,6 @@ --> - - - - - + + release="11"> + + - - - - - - - - - - - - @@ -373,8 +293,6 @@ - - diff --git a/user/src/com/google/gwt/cell/client/CheckboxCell.java b/user/src/com/google/gwt/cell/client/CheckboxCell.java index 8e9c46200e2..77eda41a440 100644 --- a/user/src/com/google/gwt/cell/client/CheckboxCell.java +++ b/user/src/com/google/gwt/cell/client/CheckboxCell.java @@ -46,6 +46,7 @@ public class CheckboxCell extends AbstractEditableCell { /** * Construct a new {@link CheckboxCell}. */ + @SuppressWarnings("BoxedPrimitiveEquality") public CheckboxCell() { this(false); } @@ -91,7 +92,8 @@ public boolean isEditing(Context context, Element parent, Boolean value) { } @Override - public void onBrowserEvent(Context context, Element parent, Boolean value, + @SuppressWarnings("BoxedPrimitiveEquality") + public void onBrowserEvent(Context context, Element parent, Boolean value, NativeEvent event, ValueUpdater valueUpdater) { String type = event.getType(); diff --git a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml index 48fa48ed1dd..38a9dbe1f55 100644 --- a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml +++ b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml @@ -15,20 +15,4 @@ - - - - - - - - - - - - - - - - diff --git a/user/src/com/google/gwt/core/StackTrace.gwt.xml b/user/src/com/google/gwt/core/StackTrace.gwt.xml index 879dbe42164..024183c50d2 100644 --- a/user/src/com/google/gwt/core/StackTrace.gwt.xml +++ b/user/src/com/google/gwt/core/StackTrace.gwt.xml @@ -45,9 +45,14 @@ - + + + + + + diff --git a/user/src/com/google/gwt/i18n/shared/DateTimeFormat.java b/user/src/com/google/gwt/i18n/shared/DateTimeFormat.java index 59c8fdb125c..f66fe02cb25 100644 --- a/user/src/com/google/gwt/i18n/shared/DateTimeFormat.java +++ b/user/src/com/google/gwt/i18n/shared/DateTimeFormat.java @@ -1906,9 +1906,10 @@ private boolean subParse(String text, int[] pos, PatternPart part, cal.setTzOffset(0); return true; } - // $FALL-THROUGH$ + // CHECKSTYLE_OFF: Fall through case 'z': // time zone offset case 'v': // time zone generic + // CHECKSTYLE_ON return subParseTimeZoneInGMT(text, start, pos, cal); default: return false; diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java index a11b1452834..277613cad0e 100644 --- a/user/src/com/google/gwt/junit/JUnitShell.java +++ b/user/src/com/google/gwt/junit/JUnitShell.java @@ -248,6 +248,7 @@ public String[] getDefaultArgs() { * ----- Options from DevMode ------- */ // Hard code the server. + JettyLauncher.suppressDeprecationWarningForTests(); options.setServletContainerLauncher(shell.new MyJettyLauncher()); // DISABLE: ArgHandlerStartupURLs registerHandler(new ArgHandlerWarDir(options) { diff --git a/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java b/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java index 730aa37e5ba..47e4f357a75 100644 --- a/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java +++ b/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java @@ -46,6 +46,7 @@ public class BeanParser implements ElementParser { * methods that extend the normal bean naming pattern. So, that implementations of * {@link IsWidget} behave like UIObjects, they have to be translated. */ + @SuppressWarnings("DoubleBraceInitialization") private static final Map ADD_PROPERTY_TO_SETTER_MAP = new HashMap() { { put("addStyleNames", "addStyleName"); diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java index 04a07a75c4d..34f28fea57a 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java +++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java @@ -320,7 +320,7 @@ public boolean isAllowed(JClassType type) { JPA_ENTITY_ANNOTATION = Class.forName("javax.persistence.Entity").asSubclass(Annotation.class); } catch (ClassNotFoundException e) { - // Ignore, JPA_ENTITY_CAPABLE_ANNOTATION will be null + // Ignore, JPA_ENTITY_CAPABLE_ANNOTATION will be null } } @@ -869,6 +869,11 @@ public SerializableTypeOracle build(TreeLogger logger) throws UnableToCompleteEx if (tic.maybeEnhanced() || (enhancedClasses != null && enhancedClasses.contains(type.getQualifiedSourceName()))) { + logger.log(TreeLogger.WARN, "The class " + type.getQualifiedSourceName() + " has " + + "JPA/JDO annotations or is explicitly configured as an enhanced class using the " + + "configuration property rpc.enhancedClasses. This makes the server vulnerable " + + "to an issue with deserialization of unsafe data. See " + + "https://github.com/gwtproject/gwt/issues/9709 for more information."); type.setEnhanced(); } } diff --git a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java index 141d342ed1d..1bd73e142ef 100644 --- a/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java +++ b/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java @@ -16,6 +16,8 @@ package com.google.gwt.user.server.rpc; import static com.google.gwt.user.client.rpc.RpcRequestBuilder.MODULE_BASE_HEADER; +import static com.google.gwt.user.server.rpc.SerializationPolicyLoader.ENABLE_ENHANCED_CLASSES; +import static com.google.gwt.user.server.rpc.SerializationPolicyLoader.ENABLE_GWT_ENHANCED_CLASSES_PROPERTY; import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException; import com.google.gwt.user.client.rpc.RpcTokenException; @@ -94,6 +96,20 @@ static SerializationPolicy loadSerializationPolicy(HttpServlet servlet, try { serializationPolicy = SerializationPolicyLoader.loadFromStream(is, null); + if (serializationPolicy.hasClientFields()) { + if (ENABLE_ENHANCED_CLASSES) { + servlet.log("WARNING: Service deserializes enhanced JPA/JDO classes, which is " + + "unsafe. See https://github.com/gwtproject/gwt/issues/9709 for more " + + "detail on the vulnerability that this presents."); + } else { + servlet.log("ERROR: Service deserializes enhanced JPA/JDO classes, which is " + + "unsafe. Review build logs to see which classes are affected, or set " + + ENABLE_GWT_ENHANCED_CLASSES_PROPERTY + " to true to allow using this " + + "service. See https://github.com/gwtproject/gwt/issues/9709 for more " + + "detail."); + serializationPolicy = null; + } + } } catch (ParseException e) { servlet.log("ERROR: Failed to parse the policy file '" + serializationPolicyFilePath + "'", e); diff --git a/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java b/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java index f0390240ceb..246c6c3c8e1 100644 --- a/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java +++ b/user/src/com/google/gwt/user/server/rpc/SerializationPolicy.java @@ -82,4 +82,14 @@ public abstract void validateDeserialize(Class clazz) */ public abstract void validateSerialize(Class clazz) throws SerializationException; + + /** + * Returns true if there may be any unsafe client fields in the serialization policy. The default + * implementation returns true to ensure that custom implementations validate accordingly. + * + * @return true if the client may send unsafely serialized data, false otherwise + */ + public boolean hasClientFields() { + return true; + } } diff --git a/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java b/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java index d860e1d7d35..ba206670d06 100644 --- a/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java +++ b/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java @@ -51,6 +51,19 @@ public final class SerializationPolicyLoader { */ public static final String SERIALIZATION_POLICY_FILE_ENCODING = "UTF-8"; + /** + * System property to enable gwt-rpc enhanced classes. To use this, set the JVM system property + * with name {@value ENABLE_GWT_ENHANCED_CLASSES_PROPERTY} to {@code true}, any other value will + * leave this feature disabled in the server at runtime. + */ + public static final String ENABLE_GWT_ENHANCED_CLASSES_PROPERTY = "gwt.enhancedClasses.enabled"; + + /** + * Flag to enable using enhanced classes, for applications that need them and are taking + * appropriate steps to secure them. Defaults to false. + */ + public static final boolean ENABLE_ENHANCED_CLASSES = "true".equals(System.getProperty(ENABLE_GWT_ENHANCED_CLASSES_PROPERTY)); + private static final String FORMAT_ERROR_MESSAGE = "Expected: className, " + "[true | false], [true | false], [true | false], [true | false], typeId, signature"; diff --git a/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java b/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java index 62413b6eced..c11c4a7b9de 100644 --- a/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java +++ b/user/src/com/google/gwt/user/server/rpc/impl/LegacySerializationPolicy.java @@ -174,4 +174,9 @@ private boolean isInstantiable(Class clazz) { } return SerializabilityUtil.hasCustomFieldSerializer(clazz) != null; } + + @Override + public boolean hasClientFields() { + return false; + } } diff --git a/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java b/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java index febcb1a863e..be870671058 100644 --- a/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java +++ b/user/src/com/google/gwt/user/server/rpc/impl/SerializabilityUtil.java @@ -915,6 +915,19 @@ private static void generateSerializationSignature(Class instanceType, CRC32 for (Enum constant : constants) { crc.update(constant.name().getBytes(StandardCharsets.UTF_8)); } + } else if (Enum.class.equals(instanceType)) { + // Edge case around Java 21 where a new non-final field was added to Enum. While the Enum + // class is rarely serialized itself (see the block above to deal with enum types), it can + // happen - this code ensures that the server always treats the Enum type the same way, + // regardless of JRE changes. + // See https://github.com/gwtproject/gwt/issues/9912 + if (policy.shouldSerializeFinalFields()) { + crc.update("name".getBytes(StandardCharsets.UTF_8)); + crc.update(getSerializedTypeName(String.class).getBytes(StandardCharsets.UTF_8)); + crc.update("ordinal".getBytes(StandardCharsets.UTF_8)); + crc.update(getSerializedTypeName(int.class).getBytes(StandardCharsets.UTF_8)); + } + generateSerializationSignature(Object.class, crc, policy); } else if (!instanceType.isPrimitive()) { Field[] fields = applyFieldSerializationPolicy(instanceType, policy); Set clientFieldNames = policy.getClientFieldNamesForEnhancedClass(instanceType); diff --git a/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java b/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java index 05c333df9a0..aadd64517b2 100644 --- a/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java +++ b/user/src/com/google/gwt/user/server/rpc/impl/StandardSerializationPolicy.java @@ -131,6 +131,11 @@ public Set getClientFieldNamesForEnhancedClass(Class clazz) { return fieldNames == null ? null : Collections.unmodifiableSet(fieldNames); } + @Override + public boolean hasClientFields() { + return clientFields != null && !clientFields.isEmpty(); + } + public final String getTypeIdForClass(Class clazz) throws SerializationException { return typeIds.get(clazz); diff --git a/user/src/com/google/gwt/user/tools/WebAppCreator.java b/user/src/com/google/gwt/user/tools/WebAppCreator.java index eba228a8db3..b787baaf97f 100644 --- a/user/src/com/google/gwt/user/tools/WebAppCreator.java +++ b/user/src/com/google/gwt/user/tools/WebAppCreator.java @@ -456,6 +456,10 @@ private abstract static class Procrastinator { } public static void main(String[] args) { + System.err.println("WebAppCreator is deprecated - please refer to " + + "https://www.gwtproject.org/gettingstarted.html for other ways to create a new " + + "application with GWT, including with Maven archetypes. These encourage better " + + "separation of classpaths, and do not need IDE-specific setup."); System.exit(doMain(args) ? 0 : 1); } diff --git a/user/src/com/google/gwt/view/client/DefaultSelectionModel.java b/user/src/com/google/gwt/view/client/DefaultSelectionModel.java index 588d1c71dcf..f7ac705102f 100644 --- a/user/src/com/google/gwt/view/client/DefaultSelectionModel.java +++ b/user/src/com/google/gwt/view/client/DefaultSelectionModel.java @@ -123,6 +123,7 @@ protected Map getExceptions(Map output) { return output; } + @SuppressWarnings("BoxedPrimitiveEquality") private void resolveChanges() { boolean changed = false; for (Map.Entry> entry : selectionChanges.entrySet()) { diff --git a/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java b/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java index fd9816e931d..620b796ee01 100644 --- a/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java +++ b/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java @@ -112,34 +112,38 @@ private static Map calculateData(Class beanType) { if (toReturn == null) { Map getters = new HashMap(); List setters = new ArrayList(); - for (Method method : beanType.getMethods()) { - if (BeanMethod.GET.matches(method)) { - // match methods on their name for now, to find the most specific - // override - String name = method.getName(); - - Type genericReturnType = TypeUtils.resolveGenerics(beanType, method.getGenericReturnType()); - Class returnType = TypeUtils.ensureBaseType(genericReturnType); - - Data data = getters.get(name); - if (data == null || data.type.isAssignableFrom(returnType)) { - // no getter seen yet for the property, or a less specific one - PropertyType propertyType; - if (TypeUtils.isValueType(returnType)) { - propertyType = PropertyType.VALUE; - } else if (Collection.class.isAssignableFrom(returnType)) { - propertyType = PropertyType.COLLECTION; - } else if (Map.class.isAssignableFrom(returnType)) { - propertyType = PropertyType.MAP; - } else { - propertyType = PropertyType.REFERENCE; + if (!(Collection.class.isAssignableFrom(beanType) + || Map.class.isAssignableFrom(beanType))) { + for (Method method : beanType.getMethods()) { + if (BeanMethod.GET.matches(method)) { + // match methods on their name for now, to find the most specific + // override + String name = method.getName(); + + Type genericReturnType = TypeUtils.resolveGenerics(beanType, + method.getGenericReturnType()); + Class returnType = TypeUtils.ensureBaseType(genericReturnType); + + Data data = getters.get(name); + if (data == null || data.type.isAssignableFrom(returnType)) { + // no getter seen yet for the property, or a less specific one + PropertyType propertyType; + if (TypeUtils.isValueType(returnType)) { + propertyType = PropertyType.VALUE; + } else if (Collection.class.isAssignableFrom(returnType)) { + propertyType = PropertyType.COLLECTION; + } else if (Map.class.isAssignableFrom(returnType)) { + propertyType = PropertyType.MAP; + } else { + propertyType = PropertyType.REFERENCE; + } + data = new Data(method, genericReturnType, returnType, propertyType); + + getters.put(name, data); } - data = new Data(method, genericReturnType, returnType, propertyType); - - getters.put(name, data); + } else if (BeanMethod.SET.matches(method) || BeanMethod.SET_BUILDER.matches(method)) { + setters.add(method); } - } else if (BeanMethod.SET.matches(method) || BeanMethod.SET_BUILDER.matches(method)) { - setters.add(method); } } diff --git a/user/src/com/google/web/bindery/requestfactory/server/RequestFactoryJarExtractor.java b/user/src/com/google/web/bindery/requestfactory/server/RequestFactoryJarExtractor.java index c7628acdc1f..daeb5a2fdec 100644 --- a/user/src/com/google/web/bindery/requestfactory/server/RequestFactoryJarExtractor.java +++ b/user/src/com/google/web/bindery/requestfactory/server/RequestFactoryJarExtractor.java @@ -18,7 +18,6 @@ import com.google.gwt.dev.util.Name; import com.google.gwt.dev.util.Name.SourceOrBinaryName; import com.google.gwt.dev.util.Util; - import com.google.web.bindery.event.shared.SimpleEventBus; import com.google.web.bindery.requestfactory.apt.RfValidator; import com.google.web.bindery.requestfactory.apt.ValidationTool; diff --git a/user/super/com/google/gwt/emul/java/lang/Boolean.java b/user/super/com/google/gwt/emul/java/lang/Boolean.java index af7a3ae1804..4aafa9c1c66 100644 --- a/user/super/com/google/gwt/emul/java/lang/Boolean.java +++ b/user/super/com/google/gwt/emul/java/lang/Boolean.java @@ -18,9 +18,7 @@ import static javaemul.internal.InternalPreconditions.checkNotNull; import java.io.Serializable; - import javaemul.internal.JsUtils; - import jsinterop.annotations.JsMethod; /** @@ -125,5 +123,5 @@ public String toString() { protected static boolean $isInstance(Object instance) { return "boolean".equals(JsUtils.typeOf(instance)); } - //CHECKSTYLE_ON: End utility methods + // CHECKSTYLE_ON: End utility methods } diff --git a/user/super/com/google/gwt/emul/java/lang/CharSequence.java b/user/super/com/google/gwt/emul/java/lang/CharSequence.java index dc76d004e30..560bd9f8751 100644 --- a/user/super/com/google/gwt/emul/java/lang/CharSequence.java +++ b/user/super/com/google/gwt/emul/java/lang/CharSequence.java @@ -22,9 +22,7 @@ import java.util.Spliterators; import java.util.stream.IntStream; import java.util.stream.StreamSupport; - import javaemul.internal.JsUtils; - import jsinterop.annotations.JsMethod; /** diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java index fbca4e7aa12..c59eed0b6cc 100644 --- a/user/super/com/google/gwt/emul/java/lang/Class.java +++ b/user/super/com/google/gwt/emul/java/lang/Class.java @@ -18,7 +18,6 @@ import com.google.gwt.core.client.JavaScriptObject; import java.lang.reflect.Type; - import javaemul.internal.annotations.DoNotInline; /** diff --git a/user/super/com/google/gwt/emul/java/lang/Comparable.java b/user/super/com/google/gwt/emul/java/lang/Comparable.java index 73191d04f1b..d54dac31429 100644 --- a/user/super/com/google/gwt/emul/java/lang/Comparable.java +++ b/user/super/com/google/gwt/emul/java/lang/Comparable.java @@ -16,7 +16,6 @@ package java.lang; import javaemul.internal.JsUtils; - import jsinterop.annotations.JsMethod; /** diff --git a/user/super/com/google/gwt/emul/java/lang/Double.java b/user/super/com/google/gwt/emul/java/lang/Double.java index 8efc156ff9d..44f250523d0 100644 --- a/user/super/com/google/gwt/emul/java/lang/Double.java +++ b/user/super/com/google/gwt/emul/java/lang/Double.java @@ -219,5 +219,5 @@ public String toString() { protected static boolean $isInstance(Object instance) { return "number".equals(JsUtils.typeOf(instance)); } - //CHECKSTYLE_ON: End utility methods + // CHECKSTYLE_ON: End utility methods } diff --git a/user/super/com/google/gwt/emul/java/lang/Enum.java b/user/super/com/google/gwt/emul/java/lang/Enum.java index 13d01144e8a..b044a57b6cb 100644 --- a/user/super/com/google/gwt/emul/java/lang/Enum.java +++ b/user/super/com/google/gwt/emul/java/lang/Enum.java @@ -19,6 +19,7 @@ import static javaemul.internal.InternalPreconditions.checkNotNull; import com.google.gwt.core.client.JavaScriptObject; + import java.io.Serializable; import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsNonNull; diff --git a/user/super/com/google/gwt/emul/java/lang/Throwable.java b/user/super/com/google/gwt/emul/java/lang/Throwable.java index 60c8a1208c9..1492bb0f003 100644 --- a/user/super/com/google/gwt/emul/java/lang/Throwable.java +++ b/user/super/com/google/gwt/emul/java/lang/Throwable.java @@ -21,9 +21,7 @@ import java.io.PrintStream; import java.io.Serializable; - import javaemul.internal.annotations.DoNotInline; - import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsNonNull; import jsinterop.annotations.JsPackage; diff --git a/user/super/com/google/gwt/emul/java/math/MathContext.java b/user/super/com/google/gwt/emul/java/math/MathContext.java index 3522877af30..fa04a4d86b2 100644 --- a/user/super/com/google/gwt/emul/java/math/MathContext.java +++ b/user/super/com/google/gwt/emul/java/math/MathContext.java @@ -38,7 +38,6 @@ import static javaemul.internal.InternalPreconditions.checkNotNull; import java.io.Serializable; - import javaemul.internal.NativeRegExp; /** diff --git a/user/super/com/google/gwt/emul/java/util/Collection.java b/user/super/com/google/gwt/emul/java/util/Collection.java index 583efd50ce8..15c10ba8ed0 100644 --- a/user/super/com/google/gwt/emul/java/util/Collection.java +++ b/user/super/com/google/gwt/emul/java/util/Collection.java @@ -20,7 +20,6 @@ import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; - import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsType; diff --git a/user/super/com/google/gwt/emul/java/util/Collections.java b/user/super/com/google/gwt/emul/java/util/Collections.java index ec35c326848..a5bfd207a4b 100644 --- a/user/super/com/google/gwt/emul/java/util/Collections.java +++ b/user/super/com/google/gwt/emul/java/util/Collections.java @@ -23,7 +23,6 @@ import java.io.Serializable; import java.util.function.Predicate; import java.util.function.UnaryOperator; - import jsinterop.annotations.JsNonNull; /** diff --git a/user/super/com/google/gwt/emul/java/util/Date.java b/user/super/com/google/gwt/emul/java/util/Date.java index fe19568d63c..67a72fb905e 100644 --- a/user/super/com/google/gwt/emul/java/util/Date.java +++ b/user/super/com/google/gwt/emul/java/util/Date.java @@ -16,7 +16,6 @@ package java.util; import java.io.Serializable; - import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; diff --git a/user/super/com/google/gwt/emul/java/util/List.java b/user/super/com/google/gwt/emul/java/util/List.java index d1d20110b82..115195390c3 100644 --- a/user/super/com/google/gwt/emul/java/util/List.java +++ b/user/super/com/google/gwt/emul/java/util/List.java @@ -18,8 +18,8 @@ import static javaemul.internal.InternalPreconditions.checkNotNull; import java.util.function.UnaryOperator; +import java.util.stream.Collectors; import javaemul.internal.ArrayHelper; - import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsNonNull; @@ -164,4 +164,9 @@ default Spliterator spliterator() { } @JsNonNull List subList(int fromIndex, int toIndex); + + static List copyOf(Collection coll) { + // TODO if the given collection is immutable and has no nulls, return it + return coll.stream().collect(Collectors.toUnmodifiableList()); + } } diff --git a/user/super/com/google/gwt/emul/java/util/Map.java b/user/super/com/google/gwt/emul/java/util/Map.java index fd3178b0411..06d057017be 100644 --- a/user/super/com/google/gwt/emul/java/util/Map.java +++ b/user/super/com/google/gwt/emul/java/util/Map.java @@ -22,7 +22,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; - +import java.util.stream.Collectors; import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsNonNull; import jsinterop.annotations.JsType; @@ -412,4 +412,10 @@ default void replaceAll(BiFunction function) int size(); @JsNonNull Collection values(); + + static Map copyOf(Map map) { + // TODO if the given map is immutable and has no nulls, return it + return map.entrySet().stream().collect(Collectors.toUnmodifiableMap(Entry::getKey, + Entry::getValue)); + } } diff --git a/user/super/com/google/gwt/emul/java/util/Set.java b/user/super/com/google/gwt/emul/java/util/Set.java index eddd4dffe90..6ec721d989a 100644 --- a/user/super/com/google/gwt/emul/java/util/Set.java +++ b/user/super/com/google/gwt/emul/java/util/Set.java @@ -18,6 +18,7 @@ import static javaemul.internal.InternalPreconditions.checkArgument; import static javaemul.internal.InternalPreconditions.checkNotNull; +import java.util.stream.Collectors; import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsType; @@ -98,4 +99,9 @@ static Set of(E... elements) { default Spliterator spliterator() { return Spliterators.spliterator(this, Spliterator.DISTINCT); } + + static Set copyOf(Collection coll) { + // TODO if the given collection is immutable and has no nulls, return it + return coll.stream().collect(Collectors.toUnmodifiableSet()); + } } diff --git a/user/super/com/google/gwt/emul/java/util/Vector.java b/user/super/com/google/gwt/emul/java/util/Vector.java index a71b5e3b33c..a43c07209a6 100644 --- a/user/super/com/google/gwt/emul/java/util/Vector.java +++ b/user/super/com/google/gwt/emul/java/util/Vector.java @@ -21,7 +21,6 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; - import jsinterop.annotations.JsNonNull; /** diff --git a/user/super/com/google/gwt/emul/java/util/function/BinaryOperator.java b/user/super/com/google/gwt/emul/java/util/function/BinaryOperator.java index caf01d201e1..a7d21ffa43f 100644 --- a/user/super/com/google/gwt/emul/java/util/function/BinaryOperator.java +++ b/user/super/com/google/gwt/emul/java/util/function/BinaryOperator.java @@ -15,10 +15,10 @@ */ package java.util.function; -import java.util.Comparator; - import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; +import java.util.Comparator; + /** * See * the official Java API doc for details. diff --git a/user/super/com/google/gwt/emul/java/util/function/Predicate.java b/user/super/com/google/gwt/emul/java/util/function/Predicate.java index b9ad769b307..1e8caa6fb3f 100644 --- a/user/super/com/google/gwt/emul/java/util/function/Predicate.java +++ b/user/super/com/google/gwt/emul/java/util/function/Predicate.java @@ -15,10 +15,10 @@ */ package java.util.function; -import java.util.Objects; - import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; +import java.util.Objects; + /** * See * the official Java API doc for details. diff --git a/user/super/com/google/gwt/emul/java/util/stream/Collectors.java b/user/super/com/google/gwt/emul/java/util/stream/Collectors.java index 60d908edb95..519b375422f 100644 --- a/user/super/com/google/gwt/emul/java/util/stream/Collectors.java +++ b/user/super/com/google/gwt/emul/java/util/stream/Collectors.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.DoubleSummaryStatistics; import java.util.HashMap; @@ -27,6 +28,7 @@ import java.util.List; import java.util.LongSummaryStatistics; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.StringJoiner; @@ -175,13 +177,14 @@ public static Collector joining(CharSequence delimiter) { return new CollectorImpl<>( downstream.supplier(), (A a, T t) -> { - Stream stream = mapper.apply(t); + try (Stream stream = mapper.apply(t)) { if (stream == null) { return; } stream.forEach(u -> { downstream.accumulator().accept(a, u); }); + } }, downstream.combiner(), downstream.finisher() @@ -339,6 +342,11 @@ public static Collector> toList() { return toCollection(ArrayList::new); } + public static Collector> toUnmodifiableList() { + Collector> mapping = mapping(Objects::requireNonNull, toList()); + return collectingAndThen(mapping, Collections::unmodifiableList); + } + public static Collector> toMap( final Function keyMapper, final Function valueMapper) { @@ -357,6 +365,29 @@ public static Collector> toList() { return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); } + public static Collector> toUnmodifiableMap( + Function keyMapper, + Function valueMapper) { + return collectingAndThen( + toMap(disallowNulls(keyMapper), disallowNulls(valueMapper)), + Collections::unmodifiableMap + ); + } + + public static Collector> toUnmodifiableMap( + Function keyMapper, + Function valueMapper, + BinaryOperator mergeFunction) { + return collectingAndThen( + toMap(disallowNulls(keyMapper), disallowNulls(valueMapper), mergeFunction), + Collections::unmodifiableMap + ); + } + + private static Function disallowNulls(Function func) { + return func.andThen(Objects::requireNonNull); + } + public static > Collector toMap( final Function keyMapper, final Function valueMapper, @@ -389,6 +420,11 @@ public static Collector> toSet() { ); } + public static Collector> toUnmodifiableSet() { + Collector> mapping = mapping(Objects::requireNonNull, toSet()); + return collectingAndThen(mapping, Collections::unmodifiableSet); + } + private static D streamAndCollect(Collector downstream, List list) { A a = downstream.supplier().get(); for (T t : list) { diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java10Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java10Test.java deleted file mode 100644 index 165815343b8..00000000000 --- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java10Test.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2018 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.test; - -import com.google.gwt.core.client.GwtScriptOnly; -import com.google.gwt.junit.client.GWTTestCase; - -import java.util.ArrayList; -import java.util.function.Supplier; - -import java.io.Serializable; - -/** - * Tests Java 10 features. It is super sourced so that gwt can be compiled under Java 7. - * - * IMPORTANT: For each test here there must exist the corresponding method in the non super sourced - * version. - * - * Eventually this test will graduate and not be super sourced. - */ -@GwtScriptOnly -public class Java10Test extends GWTTestCase { - - interface VarArgsFunction { - R apply(T... args); - } - - @Override - public String getModuleName() { - return "com.google.gwt.dev.jjs.Java10Test"; - } - - public void testLocalVarType_DenotableTypes() { - var i = 42; - assertEquals(42, i); - var s = "42"; - assertEquals("42", s); - - Supplier initializer = () -> "37"; - var s2 = initializer.get(); - //to be sure that s2 was inferred as a string and not an Object - String s3 = s2; - assertEquals("37", s3); - } - - public void testLocalVarType_Anonymous() { - var o = new Object() { - int i; - String s; - }; - o.i = 42; - o.s = "42"; - assertEquals(42, o.i); - assertEquals("42", o.s); - } - - public void testLocalVarType_Ternary() { - var value = true ? "a" : 'c'; - checkSerializableDispatch(value); - checkComparableDispatch(value); - assertEquals("a", value.toString()); - } - - private void checkSerializableDispatch(Object fail) { - fail("should not be treated as object"); - } - - private void checkSerializableDispatch(Serializable pass) { - // pass - } - - private void checkComparableDispatch(Object fail) { - fail("should not be treated as object"); - } - - private void checkComparableDispatch(Comparable pass) { - // pass - } - - public void testLocalVarType_LambdaCapture() { - var s = "42"; - Supplier supplier = () -> s; - assertEquals("42", supplier.get()); - } - - public void testLocalVarType_VarArg() { - var args = new String[] {"4", "2"}; - VarArgsFunction f = arr -> arr[0] + arr[1]; - assertEquals("42", f.apply(args)); - } - - public void testLocalVarType_LocalClass() { - var i = 37; - class Local { - int m() { - var i = 40; - return i + 2; - } - - int fromOuterScope() { - return i; - } - } - - var l = new Local(); - assertEquals(37, l.fromOuterScope()); - assertEquals(42, l.m()); - } - - public void testLocalVarType_ForLoop() { - var a = new String[] {"4", "2"}; - var s = ""; - for (var i = 0; i < a.length; i++) { - s += a[i]; - } - assertEquals("42", s); - } - - public void testLocalVarType_EnhancedForLoopArray() { - var a = new String[] {"4", "2"}; - var str = ""; - for (var s : a) { - str += s; - } - assertEquals("42", str); - } - - public void testLocalVarType_EnhancedNestedForLoopArray() { - var m = new int[][] {{1, 2}, {3, 4}}; - var summ = 0; - for (var row : m) { - for (var cell : row) { - summ += cell; - } - } - assertEquals(10, summ); - } - - public void testLocalVarType_EnhancedForLoopIterable() { - var list = new ArrayList(); - list.add("4"); - list.add("2"); - var str = ""; - for (var s : list) { - str += s; - } - assertEquals("42", str); - } -} diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java11Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java similarity index 50% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java11Test.java rename to user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java index 9e9c8f662c8..4aa7dd9c26b 100644 --- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java11Test.java +++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java @@ -20,10 +20,9 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; /** - * Tests Java 11 features. It is super sourced so that gwt can be compiles under Java 8. + * Tests Java 17 features. It is super sourced so that gwt can be compiles under Java 11. * * IMPORTANT: For each test here there must exist the corresponding method in the non super sourced * version. @@ -31,29 +30,50 @@ * Eventually this test will graduate and not be super sourced. */ @GwtScriptOnly -public class Java11Test extends GWTTestCase { +public class Java17Test extends GWTTestCase { - @interface NotNull { + public interface TextBlock { + String text = """ + line 1 + line 2 + line 3 + """; } - interface Lambda { - T run(T a, T b); + public sealed class Shape permits Square, Circle { + + } + + public final class Square extends Shape { + + } + + public final class Circle extends Shape { + } @Override public String getModuleName() { - return "com.google.gwt.dev.jjs.Java11Test"; + return "com.google.gwt.dev.jjs.test.Java17Test"; } - public void testLambdaParametersVarType() { - Lambda l = (@NotNull var x, var y) -> x + y; - assertEquals("12", l.run("1", "2")); + public void testTextBlocks() { + List lines = Arrays.asList(TextBlock.text.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() { + Shape square = new Square(); + Shape circle = new Circle(); + + checkIfCompiled(square, circle); } - public void testLambdaParametersVarType_function() { - List l = Arrays.asList("a", "b"); - l = l.stream().map((var s) -> s.toUpperCase()).collect(Collectors.toList()); - assertEquals("A", l.get(0)); - assertEquals("B", l.get(1)); + private void checkIfCompiled(Shape square, Shape circle) { + assertTrue(square instanceof Square); + assertTrue(circle instanceof Circle); } } diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java deleted file mode 100644 index 9f3c4e02899..00000000000 --- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java +++ /dev/null @@ -1,2044 +0,0 @@ -/* - * Copyright 2014 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.test; - -import com.google.gwt.core.client.GwtScriptOnly; -import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.core.client.JsonUtils; -import com.google.gwt.dev.jjs.test.defaultmethods.ImplementsWithDefaultMethodAndStaticInitializer; -import com.google.gwt.dev.jjs.test.defaultmethods.SomeClass; -import com.google.gwt.junit.client.GWTTestCase; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.IntFunction; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import jsinterop.annotations.JsFunction; -import jsinterop.annotations.JsOverlay; -import jsinterop.annotations.JsPackage; -import jsinterop.annotations.JsProperty; -import jsinterop.annotations.JsType; - -/** - * Tests Java 8 features. It is super sourced so that gwt can be compiles under Java 7. - * - * IMPORTANT: For each test here there must exist the corresponding method in the non super sourced - * version. - * - * Eventually this test will graduate and not be super sourced. - */ -@GwtScriptOnly -public class Java8Test extends GWTTestCase { - int local = 42; - - static abstract class SameClass { - public int method1() { return 10; } - public abstract int method2(); - } - - interface Lambda { - T run(int a, int b); - } - - interface Lambda2 { - boolean run(String a, String b); - } - - interface Lambda3 { - boolean run(String a); - } - - class AcceptsLambda { - public T accept(Lambda foo) { - return foo.run(10, 20); - } - public boolean accept2(Lambda2 foo) { - return foo.run("a", "b"); - } - public boolean accept3(Lambda3 foo) { - return foo.run("hello"); - } - } - - class Pojo { - private final int x; - private final int y; - - public Pojo(int x, int y) { - this.x = x; - this.y = y; - } - - public int fooInstance(int a, int b) { - return a + b + x + y; - } - } - - interface DefaultInterface { - void method1(); - // CHECKSTYLE_OFF - default int method2() { return 42; } - default int redeclaredAsAbstract() { - return 88; - } - default Integer addInts(int x, int y) { return x + y; } - default String print() { return "DefaultInterface"; } - // CHECKSTYLE_ON - } - - interface DefaultInterface2 { - void method3(); - // CHECKSTYLE_OFF - default int method4() { return 23; } - default int redeclaredAsAbstract() { - return 77; - } - // CHECKSTYLE_ON - } - - interface DefaultInterfaceSubType extends DefaultInterface { - // CHECKSTYLE_OFF - default int method2() { return 43; } - default String print() { - return "DefaultInterfaceSubType " + DefaultInterface.super.print(); - } - // CHECKSTYLE_ON - } - - static abstract class DualImplementorSuper implements DefaultInterface { - public void method1() { - } - - public abstract int redeclaredAsAbstract(); - } - - static class DualImplementorBoth extends VirtualUpRef implements DefaultInterface, - DefaultInterface2 { - public void method1() { - } - public void method3() { - } - } - - static class DualImplementor extends DualImplementorSuper implements DefaultInterface2 { - public void method3() { - } - - public int redeclaredAsAbstract() { - return DefaultInterface2.super.redeclaredAsAbstract(); - } - } - - // this doesn't implement DefaultInterface, but will provide implementation in subclasses - static class VirtualUpRef { - public int method2() { - return 99; - } - public int redeclaredAsAbstract() { - return 44; - } - } - - class Inner { - int local = 22; - public void run() { - assertEquals(94, new AcceptsLambda().accept((a,b) -> Java8Test.this.local + local + a + b).intValue()); - } - } - - static class Static { - static int staticField; - static { - staticField = 99; - } - static Integer staticMethod(int x, int y) { return x + y + staticField; } - } - - static class StaticFailIfClinitRuns { - static { - fail("clinit() shouldn't run from just taking a reference to a method"); - } - - public static Integer staticMethod(int x, int y) { - return null; - } - } - - static class DefaultInterfaceImpl implements DefaultInterface { - public void method1() { - } - } - - static class DefaultInterfaceImpl2 implements DefaultInterface { - public void method1() { - } - public int method2() { - return 100; - } - } - - static class DefaultInterfaceImplVirtualUpRef extends VirtualUpRef implements DefaultInterface { - public void method1() { - } - } - - static class DefaultInterfaceImplVirtualUpRefTwoInterfaces extends VirtualUpRef - implements DefaultInterfaceSubType { - public void method1() { - } - // CHECKSTYLE_OFF - public String print() { return "DefaultInterfaceImplVirtualUpRefTwoInterfaces"; } - // CHECKSTYLE_ON - } - - @Override - public String getModuleName() { - return "com.google.gwt.dev.jjs.Java8Test"; - } - - public void testLambdaNoCapture() { - assertEquals(30, new AcceptsLambda().accept((a, b) -> a + b).intValue()); - } - - public void testLambdaCaptureLocal() { - int x = 10; - assertEquals(40, new AcceptsLambda().accept((a,b) -> x + a + b).intValue()); - } - - public void testLambdaCaptureLocalWithInnerClass() { - int x = 10; - Lambda l = (a,b) -> new Lambda() { - @Override public Integer run(int a, int b) { - int t = x; - return t + a + b; - } - }.run(a,b); - assertEquals(40, new AcceptsLambda().accept(l).intValue()); - } - - public void testLambdaCaptureLocalAndField() { - int x = 10; - assertEquals(82, new AcceptsLambda().accept((a,b) -> x + local + a + b).intValue()); - } - - public void testLambdaCaptureLocalAndFieldWithInnerClass() { - int x = 10; - Lambda l = (a,b) -> new Lambda() { - @Override public Integer run(int j, int k) { - int t = x; - int s = local; - return t + s + a + b; - } - }.run(a,b); - assertEquals(82, new AcceptsLambda().accept(l).intValue()); - } - - public void testCompileLambdaCaptureOuterInnerField() throws Exception { - new Inner().run(); - } - - public void testStaticReferenceBinding() throws Exception { - assertEquals(129, new AcceptsLambda().accept(Static::staticMethod).intValue()); - // if this next line runs a clinit, it fails - Lambda l = dummyMethodToMakeCheckStyleHappy(StaticFailIfClinitRuns::staticMethod); - try { - // but now it should fail - l.run(1,2); - fail("Clinit should have run for the first time"); - } catch (AssertionError ae) { - // success, it was supposed to throw! - } - } - - private static Lambda dummyMethodToMakeCheckStyleHappy(Lambda l) { - return l; - } - - public void testInstanceReferenceBinding() throws Exception { - Pojo instance1 = new Pojo(1, 2); - Pojo instance2 = new Pojo(3, 4); - assertEquals(33, new AcceptsLambda().accept(instance1::fooInstance).intValue()); - assertEquals(37, new AcceptsLambda().accept(instance2::fooInstance).intValue()); - } - - public void testImplicitQualifierReferenceBinding() throws Exception { - assertFalse(new AcceptsLambda().accept2(String::equalsIgnoreCase)); - assertTrue(new AcceptsLambda().accept3("hello world"::contains)); - } - - public void testConstructorReferenceBinding() { - assertEquals(30, new AcceptsLambda().accept(Pojo::new).fooInstance(0, 0)); - } - - public void testStaticInterfaceMethod() { - assertEquals(99, (int) Static.staticMethod(0, 0)); - } - - interface ArrayCtor { - ArrayElem [][][] copy(int i); - } - - interface ArrayCtorBoxed { - ArrayElem [][][] copy(Integer i); - } - - static class ArrayElem { - } - - public void testArrayConstructorReference() { - ArrayCtor ctor = ArrayElem[][][]::new; - ArrayElem[][][] array = ctor.copy(100); - assertEquals(100, array.length); - } - - public void testArrayConstructorReferenceBoxed() { - ArrayCtorBoxed ctor = ArrayElem[][][]::new; - ArrayElem[][][] array = ctor.copy(100); - assertEquals(100, array.length); - } - - interface ThreeArgs { - int foo(int x, int y, int z); - } - - interface ThreeVarArgs { - int foo(int x, int y, int... z); - } - - public static int addMany(int x, int y, int... nums) { - int sum = x + y; - for (int num : nums) { - sum += num; - } - return sum; - } - - public void testVarArgsReferenceBinding() { - ThreeArgs t = Java8Test::addMany; - assertEquals(6, t.foo(1,2,3)); - } - - public void testVarArgsPassthroughReferenceBinding() { - ThreeVarArgs t = Java8Test::addMany; - assertEquals(6, t.foo(1,2,3)); - } - - public void testVarArgsPassthroughReferenceBindingProvidedArray() { - ThreeVarArgs t = Java8Test::addMany; - assertEquals(6, t.foo(1,2, new int[] {3})); - } - - interface I { - int foo(Integer i); - } - - public void testSuperReferenceExpression() { - class Y { - int foo(Integer i) { - return 42; - } - } - - class X extends Y { - int foo(Integer i) { - return 23; - } - - int goo() { - I i = super::foo; - return i.foo(0); - } - } - - assertEquals(42, new X().goo()); - } - - public void testQualifiedSuperReferenceExpression() { - class Y { - int foo(Integer i) { - return 42; - } - } - - class X extends Y { - int foo(Integer i) { - return 23; - } - - int goo() { - I i = X.super::foo; - return i.foo(0); - } - } - - assertEquals(42, new X().goo()); - } - - static class X2 { - protected int field; - void foo() { - int local; - class Y extends X2 { - class Z extends X2 { - void f() { - Ctor c = X2::new; - X2 x = c.makeX(123456); - assertEquals(123456, x.field); - c = Y::new; - x = c.makeX(987654); - x = new Y(987654); - assertEquals(987655, x.field); - c = Z::new; - x = c.makeX(456789); - x = new Z(456789); - assertEquals(456791, x.field); - } - private Z(int z) { - super(z + 2); - } - Z() { - } - } - - private Y(int y) { - super(y + 1); - } - - private Y() { - } - } - new Y().new Z().f(); - } - - private X2(int x) { - this.field = x; - } - X2() { - } - } - - public void testSuperReferenceExpressionWithVarArgs() { - class Base { - int foo(Object... objects) { - return 0; - } - } - - class X extends Base { - int foo(Object... objects) { - throw new AssertionError(); - } - - void goo() { - I i = super::foo; - i.foo(10); - } - } - new X().goo(); - } - - interface Ctor { - X2 makeX(int x); - } - - public void testPrivateConstructorReference() { - new X2().foo(); - } - - public void testDefaultInterfaceMethod() { - assertEquals(42, new DefaultInterfaceImpl().method2()); - } - - public void testDefaultInterfaceMethodVirtualUpRef() { - assertEquals(99, new DefaultInterfaceImplVirtualUpRef().method2()); - assertEquals(99, new DefaultInterfaceImplVirtualUpRefTwoInterfaces().method2()); - assertEquals("SimpleB", new com.google.gwt.dev.jjs.test.package3.SimpleC().m()); - assertEquals("SimpleASimpleB", new com.google.gwt.dev.jjs.test.package1.SimpleD().m()); - } - - public void testDefaultInterfaceMethodMultiple() { - assertEquals(42, new DualImplementor().method2()); - assertEquals(23, new DualImplementor().method4()); - assertEquals(77, new DualImplementor().redeclaredAsAbstract()); - assertEquals(44, new DualImplementorBoth().redeclaredAsAbstract()); - DefaultInterfaceImplVirtualUpRefTwoInterfaces instanceImplementInterfaceSubType = - new DefaultInterfaceImplVirtualUpRefTwoInterfaces(); - DefaultInterfaceSubType interfaceSubType1 = instanceImplementInterfaceSubType; - assertEquals("DefaultInterfaceImplVirtualUpRefTwoInterfaces", - instanceImplementInterfaceSubType.print()); - assertEquals("DefaultInterfaceImplVirtualUpRefTwoInterfaces", interfaceSubType1.print()); - DefaultInterfaceSubType interfaceSubType2 = new DefaultInterfaceSubType() { - @Override - public void method1() { } - }; - assertEquals("DefaultInterfaceSubType DefaultInterface", - interfaceSubType2.print()); - DefaultInterfaceSubType interfaceSubType3 = () -> { }; - assertEquals("DefaultInterfaceSubType DefaultInterface", - interfaceSubType3.print()); - } - - public void testDefenderMethodByInterfaceInstance() { - DefaultInterfaceImpl2 interfaceImpl2 = new DefaultInterfaceImpl2(); - DefaultInterface interface1 = interfaceImpl2; - assertEquals(100, interfaceImpl2.method2()); - assertEquals(100, interface1.method2()); - } - - public void testDefaultMethodReference() { - DefaultInterfaceImplVirtualUpRef x = new DefaultInterfaceImplVirtualUpRef(); - assertEquals(30, (int) new AcceptsLambda().accept(x::addInts)); - } - - interface InterfaceWithTwoDefenderMethods { - // CHECKSTYLE_OFF - default String foo() { return "interface.foo"; } - default String bar() { return this.foo() + " " + foo(); } - // CHECKSTYLE_ON - } - - class ClassImplementOneDefenderMethod implements InterfaceWithTwoDefenderMethods { - public String foo() { - return "class.foo"; - } - } - - public void testThisRefInDefenderMethod() { - ClassImplementOneDefenderMethod c = new ClassImplementOneDefenderMethod(); - InterfaceWithTwoDefenderMethods i1 = c; - InterfaceWithTwoDefenderMethods i2 = new InterfaceWithTwoDefenderMethods() { }; - assertEquals("class.foo class.foo", c.bar()); - assertEquals("class.foo class.foo", i1.bar()); - assertEquals("interface.foo interface.foo", i2.bar()); - } - - interface InterfaceImplementOneDefenderMethod extends InterfaceWithTwoDefenderMethods { - // CHECKSTYLE_OFF - default String foo() { return "interface1.foo"; } - // CHECKSTYLE_ON - } - - interface InterfaceImplementZeroDefenderMethod extends InterfaceWithTwoDefenderMethods { - } - - class ClassImplementsTwoInterfaces implements InterfaceImplementOneDefenderMethod, - InterfaceImplementZeroDefenderMethod { - } - - public void testClassImplementsTwoInterfacesWithSameDefenderMethod() { - ClassImplementsTwoInterfaces c = new ClassImplementsTwoInterfaces(); - assertEquals("interface1.foo", c.foo()); - } - - abstract class AbstractClass implements InterfaceWithTwoDefenderMethods { - } - - class Child1 extends AbstractClass { - public String foo() { - return super.foo() + " child1.foo"; - } - } - - class Child2 extends AbstractClass { - } - - public void testAbstractClassImplementsInterface() { - Child1 child1 = new Child1(); - Child2 child2 = new Child2(); - assertEquals("interface.foo child1.foo", child1.foo()); - assertEquals("interface.foo", child2.foo()); - } - - interface InterfaceI { - // CHECKSTYLE_OFF - default String print() { return "interface1"; } - // CHECKSTYLE_ON - } - interface InterfaceII { - // CHECKSTYLE_OFF - default String print() { return "interface2"; } - // CHECKSTYLE_ON - } - class ClassI { - public String print() { - return "class1"; - } - } - class ClassII extends ClassI implements InterfaceI, InterfaceII { - public String print() { - return super.print() + " " + InterfaceI.super.print() + " " + InterfaceII.super.print(); - } - } - - public void testSuperRefInDefenderMethod() { - ClassII c = new ClassII(); - assertEquals("class1 interface1 interface2", c.print()); - } - - interface II { - // CHECKSTYLE_OFF - default String fun() { return "fun() in i: " + this.foo(); }; - default String foo() { return "foo() in i.\n"; }; - // CHECKSTYLE_ON - } - interface JJ extends II { - // CHECKSTYLE_OFF - default String fun() { return "fun() in j: " + this.foo() + II.super.fun(); }; - default String foo() { return "foo() in j.\n"; } - // CHECKSTYLE_ON - } - class AA { - public String fun() { - return "fun() in a: " + this.foo(); - } - public String foo() { - return "foo() in a.\n"; - } - } - class BB extends AA implements JJ { - public String fun() { - return "fun() in b: " + this.foo() + super.fun() + JJ.super.fun(); - } - public String foo() { - return "foo() in b.\n"; - } - } - class CC extends BB implements JJ { - public String fun() { - return "fun() in c: " + super.fun(); - } - } - - public void testSuperThisRefsInDefenderMethod() { - CC c = new CC(); - II i1 = c; - JJ j1 = c; - BB b = new BB(); - II i2 = b; - JJ j2 = b; - JJ j3 = new JJ() { }; - II i3 = j3; - II i4 = new II() { }; - String c_fun = "fun() in c: fun() in b: foo() in b.\n" - + "fun() in a: foo() in b.\n" - + "fun() in j: foo() in b.\n" - + "fun() in i: foo() in b.\n"; - String b_fun = "fun() in b: foo() in b.\n" - + "fun() in a: foo() in b.\n" - + "fun() in j: foo() in b.\n" - + "fun() in i: foo() in b.\n"; - String j_fun = "fun() in j: foo() in j.\n" - + "fun() in i: foo() in j.\n"; - String i_fun = "fun() in i: foo() in i.\n"; - assertEquals(c_fun, c.fun()); - assertEquals(c_fun, i1.fun()); - assertEquals(c_fun, j1.fun()); - assertEquals(b_fun, b.fun()); - assertEquals(b_fun, i2.fun()); - assertEquals(b_fun, j2.fun()); - assertEquals(j_fun, j3.fun()); - assertEquals(j_fun, i3.fun()); - assertEquals(i_fun, i4.fun()); - } - - interface OuterInterface { - // CHECKSTYLE_OFF - default String m() { - return "I.m;" + new InnerClass().n(); - } - default String n() { - return "I.n;" + this.m(); - } - // CHECKSTYLE_ON - class InnerClass { - public String n() { - return "A.n;" + m(); - } - public String m() { - return "A.m;"; - } - } - } - class OuterClass { - public String m() { - return "B.m;"; - } - public String n1() { - OuterInterface i = new OuterInterface() { }; - return "B.n1;" + i.n() + OuterClass.this.m(); - } - public String n2() { - OuterInterface i = new OuterInterface() { - @Override - public String n() { - return this.m() + OuterClass.this.m(); - } - }; - return "B.n2;" + i.n() + OuterClass.this.m(); - } - } - public void testNestedInterfaceClass() { - OuterClass outerClass = new OuterClass(); - assertEquals("B.n1;I.n;I.m;A.n;A.m;B.m;", outerClass.n1()); - assertEquals("B.n2;I.m;A.n;A.m;B.m;B.m;", outerClass.n2()); - } - - class EmptyA { } - interface EmptyI { } - interface EmptyJ { } - class EmptyB extends EmptyA implements EmptyI { } - class EmptyC extends EmptyA implements EmptyI, EmptyJ { } - public void testBaseIntersectionCast() { - EmptyA localB = new EmptyB(); - EmptyA localC = new EmptyC(); - EmptyB b2BI = (EmptyB & EmptyI) localB; - EmptyC c2CIJ = (EmptyC & EmptyI & EmptyJ) localC; - EmptyI ii1 = (EmptyB & EmptyI) localB; - EmptyI ii2 = (EmptyC & EmptyI) localC; - EmptyI ii3 = (EmptyC & EmptyJ) localC; - EmptyI ii4 = (EmptyC & EmptyI & EmptyJ) localC; - EmptyJ jj1 = (EmptyC & EmptyI & EmptyJ) localC; - EmptyJ jj2 = (EmptyC & EmptyI) localC; - EmptyJ jj3 = (EmptyC & EmptyJ) localC; - EmptyJ jj4 = (EmptyI & EmptyJ) localC; - - try { - EmptyC b2CIJ = (EmptyC & EmptyI & EmptyJ) localB; - fail("Should have thrown a ClassCastException"); - } catch (ClassCastException e) { - // Expected. - } - try { - EmptyB c2BI = (EmptyB & EmptyI) localC; - fail("Should have thrown a ClassCastException"); - } catch (ClassCastException e) { - // Expected. - } - try { - EmptyJ jj = (EmptyB & EmptyJ) localB; - fail("Should have thrown a ClassCastException"); - } catch (ClassCastException e) { - // Expected. - } - } - - interface SimpleI { - int fun(); - } - interface SimpleK { - } - public void testIntersectionCastWithLambdaExpr() { - SimpleI simpleI1 = (SimpleI & EmptyI) () -> 11; - assertEquals(11, simpleI1.fun()); - SimpleI simpleI2 = (EmptyI & SimpleI) () -> 22; - assertEquals(22, simpleI2.fun()); - EmptyI emptyI = (EmptyI & SimpleI) () -> 33; - assertEquals(55, ((SimpleI & SimpleK) () -> 55).fun()); - } - - class SimpleA { - public int bar() { - return 11; - } - } - - class SimpleB extends SimpleA implements SimpleI { - public int fun() { - return 22; - } - } - - class SimpleC extends SimpleA implements SimpleI { - public int fun() { - return 33; - } - - public int bar() { - return 44; - } - } - - public void testIntersectionCastPolymorphism() { - SimpleA bb = new SimpleB(); - assertEquals(22, ((SimpleB & SimpleI) bb).fun()); - assertEquals(11, ((SimpleB & SimpleI) bb).bar()); - SimpleA cc = new SimpleC(); - assertEquals(33, ((SimpleC & SimpleI) cc).fun()); - assertEquals(44, ((SimpleC & SimpleI) cc).bar()); - assertEquals(33, ((SimpleA & SimpleI) cc).fun()); - SimpleI ii = (SimpleC & SimpleI) cc; - assertEquals(33, ii.fun()); - } - - interface ClickHandler { - int onClick(int a); - } - private int addClickHandler(ClickHandler clickHandler) { - return clickHandler.onClick(1); - } - private int addClickHandler(int a) { - return addClickHandler(x -> { int temp = a; return temp; }); - } - public void testLambdaCaptureParameter() { - assertEquals(2, addClickHandler(2)); - } - - interface TestLambda_Inner { - void f(); - } - interface TestLambda_Outer { - void accept(TestLambda_Inner t); - } - public void testLambda_call(TestLambda_Outer a) { - a.accept(() -> { }); - } - public void testLambdaNestingCaptureLocal() { - int[] success = new int[] {0}; - testLambda_call(sam1 -> { testLambda_call(sam2 -> { success[0] = 10; }); }); - assertEquals(10, success[0]); - } - - public void testLambdaNestingInAnonymousCaptureLocal() { - int[] x = new int[] {42}; - new Runnable() { - public void run() { - Lambda l = (a, b) -> x[0] = x[0] + a + b; - l.run(1, 2); - } - }.run(); - assertEquals(45, x[0]); - } - - public void testLambdaNestingInMultipleMixedAnonymousCaptureLocal() { - // checks that lambda has access to local variable and arguments when placed in mixed scopes - // Local Class -> Local Class -> Local Anonymous -> lambda -> Local Anonymous - class A { - int a() { - int[] x = new int[] {42}; - class B { - void b() { - I i = new I() { - public int foo(Integer arg) { - Runnable r = () -> { - new Runnable() { - public void run() { - Lambda l = (a, b) -> x[0] = x[0] + a + b + arg; - l.run(1, 2); - } - }.run(); - }; - r.run(); - return x[0]; - } - }; - i.foo(1); - } - } - B b = new B(); - b.b(); - return x[0]; - } - } - A a = new A(); - assertEquals(46, a.a()); - } - - public void testLambdaNestingInMultipleMixedAnonymousCaptureLocal_withInterference() { - // checks that lambda has access to NEAREST local variable and arguments when placed in mixed - // scopes Local Class -> Local Class -> Local Anonymous -> lambda -> Local Anonymous - class A { - int a() { - int[] x = new int[] {42}; - class B { - int b() { - int[] x = new int[] {22}; - I i = new I() { - public int foo(Integer arg) { - Runnable r = () -> { - new Runnable() { - public void run() { - Lambda l = (a, b) -> x[0] = x[0] + a + b + arg; - l.run(1, 2); - } - }.run(); - }; - r.run(); - return x[0]; - } - }; - return i.foo(1); - } - } - B b = new B(); - return b.b(); - } - } - A a = new A(); - assertEquals(26, a.a()); - } - - public void testLambdaNestingInMultipleMixedAnonymousCaptureLocalAndField() { - // checks that lambda has access to local variable, field and arguments when placed in mixed - // scopes - Local Class -> Local Class -> Local Anonymous -> lambda -> Local Anonymous - class A { - int fA = 1; - - int a() { - int[] x = new int[] {42}; - class B { - int fB = 2; - - int b() { - I i = new I() { - int fI = 3; - - public int foo(Integer arg) { - Runnable r = () -> { - new Runnable() { - public void run() { - Lambda l = (a, b) -> x[0] = x[0] + a + b + arg + fA + fB + fI; - l.run(1, 2); - } - }.run(); - }; - r.run(); - return x[0]; - } - }; - return i.foo(1); - } - } - B b = new B(); - return b.b(); - } - } - A a = new A(); - assertEquals(52, a.a()); - } - - public void testLambdaNestingInMultipleAnonymousCaptureLocal() { - // checks that lambda has access to local variable and arguments when placed in local anonymous - // class with multile nesting - int[] x = new int[] {42}; - int result = new I() { - public int foo(Integer i1) { - return new I() { - public int foo(Integer i2) { - return new I() { - public int foo(Integer i3) { - Lambda l = (a, b) -> x[0] = x[0] + a + b + i1 + i2 + i3; - return l.run(1, 2); - } - }.foo(3); - } - }.foo(2); - } - }.foo(1); - assertEquals(51, x[0]); - } - - static class TestLambda_ClassA { - int[] f = new int[] {42}; - - class B { - void m() { - Runnable r = () -> f[0] = f[0] + 1; - r.run(); - } - } - - int a() { - B b = new B(); - b.m(); - return f[0]; - } - } - - public void testLambdaNestingCaptureField_InnerClassCapturingOuterClassVariable() { - TestLambda_ClassA a = new TestLambda_ClassA(); - assertEquals(43, a.a()); - } - - public void testInnerClassCaptureLocalFromOuterLambda() { - int[] x = new int[] {42}; - Lambda l = (a, b) -> { - int[] x1 = new int[] {32}; - Lambda r = (rA, rB) -> { - int[] x2 = new int[] {22}; - I i = new I() { - public int foo(Integer arg) { - x1[0] = x1[0] + 1; - x[0] = x[0] + 1; - return x2[0] = x2[0] + rA + rB + a + b; - } - }; - return i.foo(1); - }; - return r.run(3, 4) + x1[0]; - }; - - // x1[0](32) + 1 + x2[0](22) + rA(3) + rB(4) + a(1) + b(2) - assertEquals(65, l.run(1, 2).intValue()); - assertEquals(43, x[0]); - } - - static class TestLambda_Class { - public int[] s = new int[] {0}; - public void call(TestLambda_Outer a) { - a.accept(() -> { }); - } - class TestLambda_InnerClass { - public int[] s = new int[] {0}; - public int test() { - int[] s = new int[] {0}; - TestLambda_Class.this.call( - sam0 -> TestLambda_Class.this.call( - sam1 -> { - TestLambda_Class.this.call( - sam2 -> { - TestLambda_Class.this.s[0] = 10; - this.s[0] = 20; - s[0] = 30; - }); - })); - return s[0]; - } - } - } - - public void testLambdaNestingCaptureField() { - TestLambda_Class a = new TestLambda_Class(); - a.call(sam1 -> { a.call(sam2 -> { a.s[0] = 20; }); }); - assertEquals(20, a.s[0]); - } - - public void testLambdaMultipleNestingCaptureFieldAndLocal() { - TestLambda_Class a = new TestLambda_Class(); - TestLambda_Class b = new TestLambda_Class(); - int [] s = new int [] {0}; - b.call(sam0 -> a.call(sam1 -> { a.call(sam2 -> { a.s[0] = 20; b.s[0] = 30; s[0] = 40; }); })); - assertEquals(20, a.s[0]); - assertEquals(30, b.s[0]); - assertEquals(40, s[0]); - } - - public void testLambdaMultipleNestingCaptureFieldAndLocalInnerClass() { - TestLambda_Class a = new TestLambda_Class(); - TestLambda_Class.TestLambda_InnerClass b = a.new TestLambda_InnerClass(); - int result = b.test(); - assertEquals(10, a.s[0]); - assertEquals(20, b.s[0]); - assertEquals(30, result); - } - - static class TestMF_A { - public static String getId() { - return "A"; - } - public int getIdx() { - return 1; - } - } - static class TestMF_B { - public static String getId() { - return "B"; - } - public int getIdx() { - return 2; - } - } - interface Function { - T apply(); - } - private String f(Function arg) { - return arg.apply(); - } - private int g(Function arg) { - return arg.apply().intValue(); - } - - public void testMethodRefWithSameName() { - assertEquals("A", f(TestMF_A::getId)); - assertEquals("B", f(TestMF_B::getId)); - TestMF_A a = new TestMF_A(); - TestMF_B b = new TestMF_B(); - assertEquals(1, g(a::getIdx)); - assertEquals(2, g(b::getIdx)); - } - - // Test particular scenarios involving multiple path to inherit defaults. - interface ITop { - default String m() { - return "ITop.m()"; - } - } - - interface IRight extends ITop { - default String m() { - return "IRight.m()"; - } - } - - interface ILeft extends ITop { } - - public void testMultipleDefaults_fromInterfaces_left() { - class A implements ILeft, IRight { } - - assertEquals("IRight.m()", new A().m()); - } - - public void testMultipleDefaults_fromInterfaces_right() { - class A implements IRight, ILeft { } - - assertEquals("IRight.m()", new A().m()); - } - - public void testMultipleDefaults_superclass_left() { - class A implements ITop { } - class B extends A implements ILeft, IRight { } - - assertEquals("IRight.m()", new B().m()); - } - - public void testMultipleDefaults_superclass_right() { - class A implements ITop { } - class B extends A implements IRight, ILeft { } - - assertEquals("IRight.m()", new B().m()); - } - - static class DefaultTrumpsOverSyntheticAbstractStub { - interface SuperInterface { - String m(); - } - - interface SubInterface extends SuperInterface { - default String m() { - return "SubInterface.m()"; - } - } - } - - public void testMultipleDefaults_defaultShadowsOverSyntheticAbstractStub() { - abstract class A implements DefaultTrumpsOverSyntheticAbstractStub.SuperInterface { } - class B extends A implements DefaultTrumpsOverSyntheticAbstractStub.SubInterface { } - - assertEquals("SubInterface.m()", new B().m()); - } - - static class DefaultTrumpsOverDefaultOnSuperAbstract { - interface SuperInterface { - default String m() { - return "SuperInterface.m()"; - } - } - - interface SubInterface extends SuperInterface { - default String m() { - return "SubInterface.m()"; - } - } - } - - public void testMultipleDefaults_defaultShadowsOverDefaultOnSuperAbstract() { - abstract class A implements DefaultTrumpsOverDefaultOnSuperAbstract.SuperInterface { } - class B extends A implements DefaultTrumpsOverDefaultOnSuperAbstract.SubInterface { } - - assertEquals("SubInterface.m()", new B().m()); - } - - interface InterfaceWithThisReference { - default String n() { - return "default n"; - } - default String callNUnqualified() { - class Super implements InterfaceWithThisReference { - public String n() { - return "super n"; - } - } - return new Super() { - public String callNUnqualified() { - return "Object " + n(); - } - }.callNUnqualified(); - } - default String callNWithThis() { - class Super implements InterfaceWithThisReference { - public String n() { - return "super n"; - } - } - return new Super() { - public String callNWithThis() { - return "Object " + this.n(); - } - }.callNWithThis(); - } - default String callNWithInterfaceThis() { - class Super implements InterfaceWithThisReference { - public String n() { - return "super n"; - } - } - return new Super() { - public String callNWithInterfaceThis() { - // In this method this has interface Test as its type, but it refers to outer n(); - return "Object " + InterfaceWithThisReference.this.n(); - } - }.callNWithInterfaceThis(); - } - default String callNWithSuper() { - class Super implements InterfaceWithThisReference { - public String n() { - return "super n"; - } - } - return new Super() { - public String callNWithSuper() { - // In this method this has interface Test as its type. - return "Object " + super.n(); - } - }.callNWithSuper(); - } - default String callNWithInterfaceSuper() { - return new InterfaceWithThisReference() { - public String n() { - return "this n"; - } - public String callNWithInterfaceSuper() { - // In this method this has interface Test as its type and refers to default n(); - return "Object " + InterfaceWithThisReference.super.n(); - } - }.callNWithInterfaceSuper(); - } - } - - public void testInterfaceThis() { - class A implements InterfaceWithThisReference { - public String n() { - return "n"; - } - } - assertEquals("Object super n", new A().callNUnqualified()); - assertEquals("Object super n", new A().callNWithThis()); - assertEquals("Object n", new A().callNWithInterfaceThis()); - assertEquals("Object super n", new A().callNWithSuper()); - assertEquals("Object default n", new A().callNWithInterfaceSuper()); - } - - private static List initializationOrder; - - private static int get(String s) { - initializationOrder.add(s); - return 1; - } - - interface A1 { - int fa1 = get("A1"); - - default void a1() { } - } - - interface A2 { - int fa2 = get("A2"); - - default void a2() { } - } - - interface A3 { - int fa3 = get("A3"); - - default void a3() { } - } - - interface B1 extends A1 { - int fb1 = get("B1"); - - default void b1() { } - } - - interface B2 extends A2 { - int fb2 = get("B2"); - - default void b2() { } - } - - interface B3 extends A3 { - int fb3 = get("B3"); - } - - static class C implements B1, A2 { - static { - get("C"); - } - } - - static class D extends C implements B2, B3 { - static { - get("D"); - } - } - - public void testInterfaceWithDefaultMethodsInitialization() { - initializationOrder = new ArrayList(); - new D(); - assertContentsInOrder(initializationOrder, "A1", "B1", "A2", "C", "B2", "A3", "D"); - } - - /** - * Regression test for issue 9214. - */ - interface P { - boolean apply(T obj); - } - - static class B { - public boolean getTrue() { - return true; - } - } - private static String getClassName(T obj) { - return obj.getClass().getSimpleName(); - } - - public void testMethodReference_generics() { - P p = B::getTrue; - assertTrue(p.apply(new B())); - // The next two method references must result in two different lambda implementations due - // to generics, see bug # 9333. - MyFunction1 f1 = Java8Test::getClassName; - MyFunction1 f2 = Java8Test::getClassName; - - assertEquals(B.class.getSimpleName(), f1.apply(new B())); - assertEquals(Double.class.getSimpleName(), f2.apply(new Double(2))); - } - - public void testDefaultMethod_staticInitializer() { - SomeClass.initializationOrder = new ArrayList(); - Object object = ImplementsWithDefaultMethodAndStaticInitializer.someClass; - assertContentsInOrder(SomeClass.initializationOrder, "1", "2", "3", "4"); - } - - private void assertContentsInOrder(Iterable contents, String... elements) { - assertEquals(Arrays.asList(elements).toString(), contents.toString()); - } - - @JsType(isNative = true) - interface NativeJsTypeInterfaceWithStaticInitializationAndFieldAccess { - @JsOverlay - Object object = new Integer(3); - } - - @JsType(isNative = true) - interface NativeJsTypeInterfaceWithStaticInitializationAndStaticOverlayMethod { - @JsOverlay - Object object = new Integer(4); - - @JsOverlay - static Object getObject() { - return object; - } - } - - @JsType(isNative = true) - interface NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod { - @JsOverlay - Object object = new Integer(5); - - int getA(); - - @JsOverlay - default Object getObject() { - return ((int) object) + this.getA(); - } - } - - private native NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod - createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() /*-{ - return { getA: function() { return 1; } }; - }-*/; - - @JsType(isNative = true) - interface NativeJsTypeInterfaceWithStaticInitialization { - @JsOverlay - Object object = new Integer(6); - } - - @JsType(isNative = true) - interface NativeJsTypeInterfaceWithComplexStaticInitialization { - @JsOverlay - Object object = (Integer) (((int) NativeJsTypeInterfaceWithStaticInitialization.object) + 1); - } - - static class JavaTypeImplementingNativeJsTypeInterceWithDefaultMethod implements - NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod { - public int getA() { - return 4; - } - } - - public void testNativeJsTypeWithStaticInitializer() { - assertEquals(3, NativeJsTypeInterfaceWithStaticInitializationAndFieldAccess.object); - assertEquals( - 4, NativeJsTypeInterfaceWithStaticInitializationAndStaticOverlayMethod.getObject()); - assertEquals(6, - createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() - .getObject()); - assertEquals(7, NativeJsTypeInterfaceWithComplexStaticInitialization.object); - assertEquals(9, new JavaTypeImplementingNativeJsTypeInterceWithDefaultMethod().getObject()); - } - - @JsFunction - interface VarargsFunction { - String f(int i, String... args); - } - - private static native String callFromJSNI(VarargsFunction f) /*-{ - return f(2, "a", "b", "c"); - }-*/; - - public void testJsVarargsLambda() { - VarargsFunction function = (i, args) -> args[i]; - assertSame("b", function.f(1, "a", "b", "c")); - assertSame("c", callFromJSNI(function)); - String[] pars = new String[] {"a", "b", "c"}; - assertSame("a", function.f(0, pars)); - } - - private static T m(T s) { - return s; - } - - static class Some { - T s; - MyFunction2 combine; - Some(T s, MyFunction2 combine) { - this.s = s; - this.combine = combine; - } - public T m(T s2) { - return combine.apply(s, s2); - } - public T m1() { - return s; - } - } - - @FunctionalInterface - interface MyFunction1 { - U apply(T t); - } - - @FunctionalInterface - interface MyFunction2 { - V apply(T t, U u); - } - - @FunctionalInterface - interface MyFunction3 { - W apply(T t, U u, V v); - } - - @FunctionalInterface - interface IntFunction1 { - U apply(int t); - } - - @FunctionalInterface - interface IntFunction2 { - V apply(int t, int u); - } - - @FunctionalInterface - interface IntFunction3 { - W apply(int t, int u, int v); - } - - public void testMethodReference_implementedInSuperclass() { - MyFunction1 toString = StringBuilder::toString; - assertEquals("Hello", toString.apply(new StringBuilder("Hello"))); - } - - static MyFunction2 concat = (s,t) -> s + t; - - public void testMethodReference_genericTypeParameters() { - testMethodReference_genericTypeParameters( - new Some("Hell", concat), "Hell", "o", concat); - } - - static String concat(String... strs) { - String result = ""; - for (String s : strs) { - result += s; - } - return result; - } - - static String anotherConcat(String s1, String s2, String... strs) { - String result = s1 + s2; - for (String s : strs) { - result += s; - } - return result; - } - - public String instanceConcat(String... strs) { - String result = ""; - for (String s : strs) { - result += s; - } - return result; - } - - public String anotherInstanceConcat(String s1, String... strs) { - String result = s1; - for (String s : strs) { - result += s; - } - return result; - } - - private static class ClassWithVarArgsConstructor { - private class Inner { - private int sum; - Inner(int i, Integer... nums) { - this.sum = ClassWithVarArgsConstructor.this.sum + i; - for (Integer n: nums) { - sum += n; - } - } - } - - private int sum; - ClassWithVarArgsConstructor(int i, Integer... nums) { - sum = i; - for (Integer n: nums) { - sum += n; - } - } - - private MyFunction1 createInner1Param() { - return (MyFunction1) Inner::new; - } - - private MyFunction2 createInner2Param() { - return (MyFunction2) Inner::new; - } - - private MyFunction3 createInner3Param() { - return (MyFunction3) Inner::new; - } - - private MyFunction2 createInner2ParamArray() { - return (MyFunction2) Inner::new; - } - - private IntFunction1 createInner1IntParam() { - return (IntFunction1) Inner::new; - } - - private IntFunction2 createInner2IntParam() { - return (IntFunction2) Inner::new; - } - - private IntFunction3 createInner3IntParam() { - return (IntFunction3) Inner::new; - } - } - - public void testMethodReference_varargs() { - // More functional arguments than varargs - MyFunction2 concat = Java8Test::concat; - assertEquals("ab", concat.apply("a", "b")); - - // Less functional arguments than varargs - MyFunction2 anotherConcat = Java8Test::anotherConcat; - assertEquals("ab", anotherConcat.apply("a", "b")); - - MyFunction2 instanceConcat = Java8Test::instanceConcat; - assertEquals("a", instanceConcat.apply(this, "a")); - - MyFunction2 anotherInstanceConcat = Java8Test::anotherInstanceConcat; - assertEquals("a", anotherInstanceConcat.apply(this, "a")); - - // constructor varargs - MyFunction1 constructor1Param = - ClassWithVarArgsConstructor::new; - assertEquals(1, constructor1Param.apply(1).sum); - - MyFunction2 constructor2Param = - ClassWithVarArgsConstructor::new; - assertEquals(3, constructor2Param.apply(1, 2).sum); - - MyFunction3 constructor3Param = - ClassWithVarArgsConstructor::new; - assertEquals(6, constructor3Param.apply(1, 2, 3).sum); - - MyFunction2 constructor2ParamArray = - ClassWithVarArgsConstructor::new; - assertEquals(6, constructor2ParamArray.apply(1, new Integer[] {2, 3}).sum); - - // constructor varargs + autoboxing - IntFunction1 constructor1IntParam = - ClassWithVarArgsConstructor::new; - assertEquals(1, constructor1IntParam.apply(1).sum); - - IntFunction2 constructor2IntParam = - ClassWithVarArgsConstructor::new; - assertEquals(3, constructor2IntParam.apply(1, 2).sum); - - IntFunction3 constructor3IntParam = - ClassWithVarArgsConstructor::new; - assertEquals(6, constructor3IntParam.apply(1, 2, 3).sum); - - ClassWithVarArgsConstructor outer = new ClassWithVarArgsConstructor(1); - - // inner class constructor varargs - assertEquals(2, outer.createInner1Param().apply(1).sum); - assertEquals(4, outer.createInner2Param().apply(1, 2).sum); - assertEquals(7, outer.createInner3Param().apply(1, 2, 3).sum); - assertEquals(7, outer.createInner2ParamArray().apply(1, new Integer[] {2, 3}).sum); - - // inner class constructor varargs + autoboxing - assertEquals(2, outer.createInner1IntParam().apply(1).sum); - assertEquals(4, outer.createInner2IntParam().apply(1, 2).sum); - assertEquals(7, outer.createInner3IntParam().apply(1, 2, 3).sum); - } - - private static void testMethodReference_genericTypeParameters( - Some some, T t1, T t2, MyFunction2 combine) { - T t1t2 = combine.apply(t1, t2); - - // Test all 4 flavours of methodReference - // 1. Static method - assertEquals(t1t2, ((MyFunction1) Java8Test::m).apply(t1t2)); - // 2. Qualified instance method - assertEquals(t1t2, ((MyFunction1) some::m).apply(t2)); - // 3. Unqualified instance method - assertEquals(t1, ((MyFunction1, T>) Some::m1).apply(some)); - assertEquals("Hello", - ((MyFunction1, String>) - Some::m1).apply(new Some<>("Hello", concat))); - // 4. Constructor reference. - assertEquals(t1t2, - ((MyFunction2, Some>) Some::new).apply(t1t2, combine).m1()); - } - - static MyFunction2 addInteger = (s,t) -> s + t; - - @FunctionalInterface - interface MyIntFunction1 { - int apply(int t); - } - - @FunctionalInterface - interface MyIntFunction2 { - int apply(int t, int u); - } - - @FunctionalInterface - interface MyIntFuncToSomeIntegeFunction2 { - SomeInteger apply(int t, MyFunction2 u); - } - - @FunctionalInterface - interface MySomeIntegerFunction1 { - int apply(SomeInteger t); - } - - @FunctionalInterface - interface MySomeIntegerIntFunction2 { - int apply(SomeInteger t, int u); - } - - static MyIntFunction2 addint = (s,t) -> s + t; - - static class SomeInteger { - int s; - MyFunction2 combine; - SomeInteger(int s, MyFunction2 combine) { - this.s = s; - this.combine = combine; - } - public int m(int s2) { - return combine.apply(s, s2); - } - public int m1() { - return s; - } - } - - public void testMethodReference_autoboxing() { - SomeInteger some = new SomeInteger(3, addInteger); - - // Test all 4 flavours of methodReference autoboxing parameters. - // 1. Static method - assertEquals((Integer) 5, ((MyFunction1) Java8Test::m).apply(5)); - // 2. Qualified instance method - assertEquals((Integer) 5, ((MyFunction1) some::m).apply(2)); - // 3. Unqualified instance method - assertEquals((Integer) 3, ((MyFunction1) SomeInteger::m1).apply(some)); - assertEquals((Integer) 5, ((MyFunction2) - SomeInteger::m).apply(some, 2)); - assertEquals((Integer) 5, - ((MyFunction1) - SomeInteger::m1).apply(new SomeInteger(5, addInteger))); - // 4. Constructor reference. - assertEquals(5, - ((MyFunction2, SomeInteger>) - SomeInteger::new).apply(5, addInteger).m1()); - - // Test all 4 flavours of methodReference (interface unboxed) - // 1. Static method - assertEquals(5, ((MyIntFunction1) Java8Test::m).apply(5)); - // 2. Qualified instance method - assertEquals(5, ((MyIntFunction1) some::m).apply(2)); - // 3. Unqualified instance method - assertEquals(3, ((MySomeIntegerFunction1) SomeInteger::m1).apply(some)); - // The next expression was the one that triggered bug #9346 where decisions on whether to - // box/unbox were decided incorrectly due to differring number of parameters in the method - // reference and the functional interface method. - assertEquals(5, ((MySomeIntegerIntFunction2) SomeInteger::m).apply(some, 2)); - assertEquals(5, - ((MySomeIntegerFunction1) - SomeInteger::m1).apply(new SomeInteger(5, addInteger))); - // 4. Constructor reference. - assertEquals(5, - ((MyIntFuncToSomeIntegeFunction2) SomeInteger::new).apply(5, addInteger).m1()); - } - - @JsType(isNative = true) - private static class NativeClassWithJsOverlay { - @JsOverlay - public static String m(String s) { - MyFunction1 id = (a) -> a; - return id.apply(s); - } - } - public void testNativeJsOverlay_lambda() { - assertSame("Hello", NativeClassWithJsOverlay.m("Hello")); - } - - interface IntefaceWithDefaultMethodAndLambda { - boolean f(); - - default BooleanPredicate fAsPredicate() { - // This lambda will be defined as an instance method in the enclosing class, which is an - // interface. In this case the methdod will be devirtualized. - return () -> this.f(); - } - } - - interface BooleanPredicate { - boolean apply(); - } - - public void testLambdaCapturingThis_onDefaultMethod() { - assertTrue( - new IntefaceWithDefaultMethodAndLambda() { - @Override - public boolean f() { - return true; - } - }.fAsPredicate().apply()); - } - - @JsFunction - interface MyJsFunctionInterface { - int foo(int a); - } - - public void testJsFunction_lambda() { - MyJsFunctionInterface jsFunctionInterface = a -> a + 2; - assertEquals(12, callAsFunction(jsFunctionInterface, 10)); - assertEquals(12, jsFunctionInterface.foo(10)); - } - - private static native int callAsFunction(Object fn, int arg) /*-{ - return fn(arg); - }-*/; - - @JsFunction - interface MyJsFunctionInterfaceWithOverlay { - Double m(); - @JsOverlay - default Double callM() { - return this.m(); - } - } - - private static native MyJsFunctionInterfaceWithOverlay createNative() /*-{ - return function () { return 5; }; - }-*/; - - public void testJsFunction_withOverlay() { - MyJsFunctionInterfaceWithOverlay f = new MyJsFunctionInterfaceWithOverlay() { - @Override - public Double m() { - return new Double(2.0); - } - }; - assertEquals(2, f.callM().intValue()); - assertEquals(5, createNative().callM().intValue()); - } - - interface FunctionalExpressionBridges_I { - T apply(T t); - // TODO(rluble): uncomment the line below to when bridges for default methods are created - // in functional expressions - FunctionalExpressionBridges_I m(T t); - } - - @FunctionalInterface - interface FunctionalExpressionBridges_J - extends FunctionalExpressionBridges_I { - T apply(T t); - - // Overrides I.m() and specializes return type - default FunctionalExpressionBridges_J m(T t) { - return this; - } - } - - public static String identity(String s) { - return s; - } - - public void testFunctionalExpressionBridges() { - FunctionalExpressionBridges_J ann = new FunctionalExpressionBridges_J() { - @Override - public String apply(String string) { - return string; - } - }; - - assertBrigdeDispatchIsCorrect(ann); - assertBrigdeDispatchIsCorrect((String s) -> s + ""); - assertBrigdeDispatchIsCorrect(Java8Test::identity); - } - - private void assertBrigdeDispatchIsCorrect( - FunctionalExpressionBridges_J functionalExpression) { - assertEquals("Hello", functionalExpression.m(null).apply("Hello")); - assertEquals("Hello", functionalExpression.apply("Hello")); - assertEquals("Hello", - ((FunctionalExpressionBridges_I) functionalExpression).apply("Hello")); - } - - static class ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName { - public static String m() { - return null; - } - } - - // Regression test for bug: #9426. - public void testCorrectNaming() { - Function f = ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName::m; - assertNotNull(f); - } - - @JsType(isNative = true) - interface InterfaceWithOverlay { - - @JsProperty - int getLength(); - - @JsOverlay - default int len() { - return this.getLength(); - } - } - - @JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL) - static abstract class SubclassImplementingInterfaceWithOverlay implements InterfaceWithOverlay { - } - - // Regression test for bug: #9440 - public void testInterfaceWithOverlayAndNativeSubclass() { - SubclassImplementingInterfaceWithOverlay object = - (SubclassImplementingInterfaceWithOverlay) (Object) new int[]{1, 2, 3}; - assertEquals(3, object.len()); - } - - interface Producer { - T get(); - } - - private static Producer createInnerClassProducer() { - class InnerClass { - } - return (Producer) InnerClass::new; - } - - public void testLocalClassConstructorReferenceInStaticMethod() { - assertTrue(createInnerClassProducer().get() != null); - } - - // NOTE: DO NOT reorder the following classes, bug #9453 is only reproducible in certain - // orderings. - interface SubSub_SuperDefaultMethodDevirtualizationOrder - extends Sub_SuperDefaultMethodDevirtualizationOrder { - default String m() { - return Sub_SuperDefaultMethodDevirtualizationOrder.super.m(); - } - } - - interface Sub_SuperDefaultMethodDevirtualizationOrder - extends Super_SuperDefaultMethodDevirtualizationOrder { - @Override - default String m() { - return Super_SuperDefaultMethodDevirtualizationOrder.super.m(); - } - } - - interface Super_SuperDefaultMethodDevirtualizationOrder { - default String m() { - return "Hi"; - } - } - - // Regression test for bug #9453. - public void testDefaultMethodDevirtualizationOrder() { - assertEquals("Hi", new SubSub_SuperDefaultMethodDevirtualizationOrder() { - }.m()); - } - - private static String first(String... strings) { - return strings[0]; - } - - // Regresion test for https://github.com/gwtproject/gwt/issues/9497 - public void testVarargsFunctionalConversion() { - java.util.function.Function function = Java8Test::first; - assertEquals("Hello", function.apply(new String[] {"Hello", "GoodBye"})); - } - - interface SingleJsoImplA { - String getAData(); - - List getListOfB(); - } - - interface SingleJsoImplB { - String getBData(); - } - - private static final class AOverlay extends JavaScriptObject implements SingleJsoImplA { - protected AOverlay() { } - - @Override - public native String getAData() /*-{ - return this.data; - }-*/; - - @Override - public native List getListOfB() /*-{ - return @java.util.Arrays::asList(*)(this.listOfb); - }-*/; - } - - private static final class BOverlay extends JavaScriptObject implements SingleJsoImplB { - protected BOverlay() { } - - @Override - public native String getBData() /*-{ - return this.data; - }-*/; - } - - private static SingleJsoImplA createA() { - return JsonUtils.safeEval( - "{\"data\":\"a value\",\"listOfb\":[{\"data\":\"b1\"},{\"data\":\"b2\"}]}"); - } - - // Regression for issue #9558 - public void testJSOLivenessSingleImplErasure() { - SingleJsoImplA a = createA(); - String result = a.getListOfB().stream() - .map(SingleJsoImplB::getBData).collect(Collectors.joining(",")); - assertEquals("b1,b2", result); - result = a.getListOfB().stream() - .map(b -> b.getBData()).collect(Collectors.joining(",")); - assertEquals("b1,b2", result); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public void testLambdaErasureCasts() { - List list = new ArrayList(); - list.add("2"); - try { - ((List) list).stream().map(n -> n.intValue() == 2).findAny(); - fail("Should have thrown."); - } catch (ClassCastException expected) { - } - } - - public void testLambdaBoxing() { - BiFunction equals = (i, j) -> i + 0 == j; - assertTrue(equals.apply(1,1)); - assertTrue(equals.apply(new Integer(2),2)); - assertTrue(equals.apply(new Integer(3), new Integer(3))); - - IntFunction unboxBox = i -> i; - assertEquals(2, (int) unboxBox.apply(2)); - assertEquals(2, (int) unboxBox.apply(new Integer(2))); - } - - // Regression tests for #9598 - public void testImproperMethodResolution() { - Predicate p = o -> true; - assertTrue(p.test(null)); - } - - interface I2 { public T foo(T arg); } - - interface I1 extends I2 { public String foo(String arg0); } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public void testIntersectionCastLambda() { - - Object instance = (I1 & I2) val -> "#" + val; - - assertTrue(instance instanceof I1); - assertTrue(instance instanceof I2); - - I1 lambda = (I1) instance; - I2 raw = lambda; - assertEquals("#1", raw.foo("1")); // tests that the bridge exists and is correct - assertEquals("#2", lambda.foo("2")); - } - - static class C2 { public static String append(String str) { return "#" + str; } } - @SuppressWarnings({"rawtypes", "unchecked"}) - public void testIntersectionCastMethodReference() { - - Object instance = (I1 & I2) C2::append; - - assertTrue(instance instanceof I1); - assertTrue(instance instanceof I2); - - I1 lambda = (I1) instance; - I2 raw = lambda; - assertEquals("#1", raw.foo("1")); // tests that the bridge exists and is correct - assertEquals("#2", lambda.foo("2")); - } -} diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java9Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java9Test.java deleted file mode 100644 index e6ff6d29d3f..00000000000 --- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java9Test.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2023 GwtProject contributors - * - * 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.test; - -import com.google.gwt.core.client.GwtScriptOnly; -import com.google.gwt.junit.client.GWTTestCase; - -import java.util.function.Predicate; -import java.util.function.Supplier; - -@GwtScriptOnly -public class Java9Test extends GWTTestCase { - - @Override - public String getModuleName() { - return "com.google.gwt.dev.jjs.Java9Test"; - } - - class Resource implements AutoCloseable { - boolean isOpen = true; - - public void close() { - this.isOpen = false; - } - } - - public void testTryWithResourcesJava9() { - Resource r1 = new Resource(); - assertTrue(r1.isOpen); - Resource r2Copy; - try (r1; Resource r2 = new Resource()) { - assertTrue(r1.isOpen); - assertTrue(r2.isOpen); - r2Copy = r2; - } - assertFalse(r1.isOpen); - assertFalse(r2Copy.isOpen); - } - - interface Selector extends Predicate { - @Override - boolean test(String object); - - default Selector trueSelector() { - // Unused variable that creates a lambda with a bridge for the method test. The bug #9598 - // was caused by GwtAstBuilder associating the bridge method Lambda.test(Object) on the - // lambda below to the method Predicate.test(Object), causing the method resolution in the - // code that refers to the Predicate.test(Object) in the test below to refer to - // Lambda.test(Object) which is the wrong method. - return receiver -> true; - } - } - - private interface InterfaceWithPrivateMethods { - int implementedMethod(); - - default int defaultMethod() { - return privateMethod(); - } - - private int privateMethod() { - return implementedMethod(); - } - - private int staticPrivateMethod() { - return 42; - } - } - - public void testInterfacePrivateMethodsJava9() { - InterfaceWithPrivateMethods implementor = () -> 50; - assertEquals(50, implementor.implementedMethod()); - assertEquals(50, implementor.defaultMethod()); - assertEquals(42, implementor.staticPrivateMethod()); - } - - public void testAnonymousDiamondJava9() { - Supplier helloSupplier = new Supplier<>() { - @Override - public String get() { - return "hello"; - } - }; - assertEquals("hello", helloSupplier.get()); - } -} \ No newline at end of file diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java index b15ce7563b8..6a3822ac069 100644 --- a/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java +++ b/user/test/com/google/gwt/core/client/impl/StackTraceEmulTest.java @@ -67,7 +67,7 @@ public void testJavaLineNumbers() { String[] methodNames = getTraceJava(); StackTraceElement[] expectedTrace = new StackTraceElement[] { - createSTE(methodNames[0], "Throwable.java", 68), + createSTE(methodNames[0], "Throwable.java", 66), createSTE(methodNames[1], "Exception.java", 29), createSTE(methodNames[2], "StackTraceExamples.java", 57), createSTE(methodNames[3], "StackTraceExamples.java", 52), diff --git a/user/test/com/google/gwt/core/interop/ElementLikeNativeInterface.java b/user/test/com/google/gwt/core/interop/ElementLikeNativeInterface.java index 6d6ac091085..f50d78cc45b 100644 --- a/user/test/com/google/gwt/core/interop/ElementLikeNativeInterface.java +++ b/user/test/com/google/gwt/core/interop/ElementLikeNativeInterface.java @@ -15,7 +15,6 @@ */ package com.google.gwt.core.interop; - import jsinterop.annotations.JsProperty; import jsinterop.annotations.JsType; diff --git a/user/test/com/google/gwt/core/interop/JsTypeTest.java b/user/test/com/google/gwt/core/interop/JsTypeTest.java index 8fd9ddd56b1..9b42fa0c28a 100644 --- a/user/test/com/google/gwt/core/interop/JsTypeTest.java +++ b/user/test/com/google/gwt/core/interop/JsTypeTest.java @@ -21,7 +21,6 @@ import com.google.gwt.junit.client.GWTTestCase; import java.util.Iterator; - import jsinterop.annotations.JsFunction; import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsPackage; diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java index 56e49ff62ae..28076f94838 100644 --- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java +++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java @@ -29,6 +29,7 @@ import com.google.gwt.dev.jjs.test.InnerOuterSuperTest; import com.google.gwt.dev.jjs.test.Java10Test; import com.google.gwt.dev.jjs.test.Java11Test; +import com.google.gwt.dev.jjs.test.Java17Test; import com.google.gwt.dev.jjs.test.Java7Test; import com.google.gwt.dev.jjs.test.Java8Test; import com.google.gwt.dev.jjs.test.Java9Test; @@ -71,12 +72,13 @@ public static Test suite() { suite.addTestSuite(InnerClassTest.class); suite.addTestSuite(InnerOuterSuperTest.class); suite.addTestSuite(Java7Test.class); - // Java8Test cannot be the first one in a suite. It uses a hack - // to avoid executing if not in a Java 8+ environment. suite.addTestSuite(Java8Test.class); suite.addTestSuite(Java9Test.class); suite.addTestSuite(Java10Test.class); suite.addTestSuite(Java11Test.class); + // Java17Test cannot be the first one in a suite. It uses a hack + // to avoid executing if not in a Java 17+ environment. + suite.addTestSuite(Java17Test.class); suite.addTestSuite(JavaAccessFromJavaScriptTest.class); suite.addTestSuite(JsniConstructorTest.class); suite.addTestSuite(JsniDispatchTest.class); diff --git a/user/test/com/google/gwt/dev/jjs/Java10Test.gwt.xml b/user/test/com/google/gwt/dev/jjs/Java10Test.gwt.xml index f16a361df4b..282caab62fb 100644 --- a/user/test/com/google/gwt/dev/jjs/Java10Test.gwt.xml +++ b/user/test/com/google/gwt/dev/jjs/Java10Test.gwt.xml @@ -15,5 +15,5 @@ - + \ No newline at end of file diff --git a/user/test/com/google/gwt/dev/jjs/Java11Test.gwt.xml b/user/test/com/google/gwt/dev/jjs/Java11Test.gwt.xml index a73ecb58ee3..6b07de06936 100644 --- a/user/test/com/google/gwt/dev/jjs/Java11Test.gwt.xml +++ b/user/test/com/google/gwt/dev/jjs/Java11Test.gwt.xml @@ -15,5 +15,5 @@ - + \ No newline at end of file diff --git a/user/test/com/google/gwt/dev/jjs/Java17Test.gwt.xml b/user/test/com/google/gwt/dev/jjs/Java17Test.gwt.xml new file mode 100644 index 00000000000..a73ecb58ee3 --- /dev/null +++ b/user/test/com/google/gwt/dev/jjs/Java17Test.gwt.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/user/test/com/google/gwt/dev/jjs/Java8Test.gwt.xml b/user/test/com/google/gwt/dev/jjs/Java8Test.gwt.xml index ff61d0dc3c7..426982b9e3c 100644 --- a/user/test/com/google/gwt/dev/jjs/Java8Test.gwt.xml +++ b/user/test/com/google/gwt/dev/jjs/Java8Test.gwt.xml @@ -15,5 +15,5 @@ - + \ No newline at end of file diff --git a/user/test/com/google/gwt/dev/jjs/Java9Test.gwt.xml b/user/test/com/google/gwt/dev/jjs/Java9Test.gwt.xml index ff61d0dc3c7..426982b9e3c 100644 --- a/user/test/com/google/gwt/dev/jjs/Java9Test.gwt.xml +++ b/user/test/com/google/gwt/dev/jjs/Java9Test.gwt.xml @@ -15,5 +15,5 @@ - + \ No newline at end of file diff --git a/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java b/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java index 5d27b57a4aa..cdf343486d7 100644 --- a/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java +++ b/user/test/com/google/gwt/dev/jjs/optimized/CastOptimizationTest.java @@ -20,7 +20,6 @@ import com.google.gwt.junit.Platform; import java.util.Random; - import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; diff --git a/user/test/com/google/gwt/dev/jjs/optimized/UncheckedCastOptimizationTest.java b/user/test/com/google/gwt/dev/jjs/optimized/UncheckedCastOptimizationTest.java index 021beed1027..efc39acbfae 100644 --- a/user/test/com/google/gwt/dev/jjs/optimized/UncheckedCastOptimizationTest.java +++ b/user/test/com/google/gwt/dev/jjs/optimized/UncheckedCastOptimizationTest.java @@ -19,7 +19,6 @@ import com.google.gwt.junit.Platform; import javaemul.internal.annotations.UncheckedCast; - import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; diff --git a/user/test/com/google/gwt/dev/jjs/test/AnnotationsTest.java b/user/test/com/google/gwt/dev/jjs/test/AnnotationsTest.java index af856a41ee3..97aec8316d0 100644 --- a/user/test/com/google/gwt/dev/jjs/test/AnnotationsTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/AnnotationsTest.java @@ -24,6 +24,7 @@ */ public class AnnotationsTest extends GWTTestCase { + @SuppressWarnings("BadAnnotationImplementation") private static class Foo implements IFoo { @Override public Class annotationType() { diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java index 4ec71bcec9a..0864c717ead 100644 --- a/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java @@ -34,7 +34,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - import javaemul.internal.annotations.DoNotInline; import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsOverlay; diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java index ad1f54285e1..cad90f39779 100644 --- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java @@ -36,6 +36,7 @@ interface MyMap { interface Silly { } + @SuppressWarnings("ComparableType") interface SillyComparable extends Comparable { @Override int compareTo(T obj); @@ -418,6 +419,7 @@ public int compareTo(AbstractFoo o) { } } + @SuppressWarnings("ComparableType") class MyFoo extends AbstractFoo implements Comparable { } @@ -752,6 +754,7 @@ void blah() { }; } + @SuppressWarnings({"ReturnValueIgnored", "IdentityBinaryExpression"}) public void testDeadTypes() { if (false) { new Object() { @@ -771,7 +774,7 @@ void a() { * Development Mode or Production Mode, but the important thing is that the * compiler does not crash. */ - @SuppressWarnings({"divzero", "ConstantOverflow"}) + @SuppressWarnings({"divzero", "ConstantOverflow", "IdentityBinaryExpression"}) public void testDivByZero() { assertTrue(Double.isNaN(0.0 / 0.0)); @@ -806,6 +809,7 @@ public void testDivByZero() { } } + @SuppressWarnings({"IdentityBinaryExpression", "LoopConditionChecker"}) public void testEmptyBlockStatements() { boolean b = false; while (b) { @@ -864,7 +868,7 @@ public native void testEmptyBlockStatementsNative() /*-{ // CHECKSTYLE_OFF - @SuppressWarnings("empty") + @SuppressWarnings({"empty", "LoopConditionChecker"}) public void testEmptyStatements() { boolean b = false; diff --git a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java index 88410ff159b..c29439f2c8d 100644 --- a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java @@ -333,7 +333,7 @@ private void testCaseSwitchStatement() { assertEquals(15, i); } - @SuppressWarnings("cast") + @SuppressWarnings({"cast", "SelfAssignment"}) private void testCastExpression() { // CastExpression o = (Super) o; diff --git a/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java b/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java index d011912f347..e0ec236088c 100644 --- a/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java @@ -26,6 +26,7 @@ public class InnerClassTest extends GWTTestCase { static class OuterRefFromSuperCtorBase { + @SuppressWarnings("ReturnValueIgnored") OuterRefFromSuperCtorBase(Object o) { o.toString(); } diff --git a/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java b/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java index 97c956a255a..86aad803ef9 100644 --- a/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java @@ -77,6 +77,7 @@ public void testConditionalExpressions() { * Test "true == booleanField" and permutations, as well as "true == false" * and permutations. */ + @SuppressWarnings("IdentityBinaryExpression") public void testEqualsBool() { assertTrue(fieldTrue == returnTrue()); assertTrue(returnTrue() == fieldTrue); @@ -127,6 +128,7 @@ public void testFlippedIf() { /** * Tests constant folding. */ + @SuppressWarnings("IdentityBinaryExpression") public void testOpsOnLiterals() { assertEquals(10, returnIntFive() + returnIntFive()); assertEquals(0, returnIntFive() - returnIntFive()); diff --git a/user/test/com/google/gwt/dev/jjs/test/Java10Test.java b/user/test/com/google/gwt/dev/jjs/test/Java10Test.java index 07b6bd72ca8..375313e86c4 100644 --- a/user/test/com/google/gwt/dev/jjs/test/Java10Test.java +++ b/user/test/com/google/gwt/dev/jjs/test/Java10Test.java @@ -15,74 +15,143 @@ */ package com.google.gwt.dev.jjs.test; -import com.google.gwt.dev.util.arg.SourceLevel; import com.google.gwt.junit.DoNotRunWith; -import com.google.gwt.junit.JUnitShell; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.function.Supplier; + /** - * Dummy test case. Java10Test is super sourced so that GWT can be compiled by Java 8. - * - * NOTE: Make sure this class has the same test methods of its supersourced variant. + * Tests Java 10 features. */ @DoNotRunWith(Platform.Devel) public class Java10Test extends GWTTestCase { - @Override - public String getModuleName() { - return "com.google.gwt.dev.jjs.Java10Test"; + interface VarArgsFunction { + R apply(T... args); } @Override - public void runTest() throws Throwable { - // Only run these tests if -sourceLevel 10 (or greater) is enabled. - if (isGwtSourceLevel10()) { - super.runTest(); - } + public String getModuleName() { + return "com.google.gwt.dev.jjs.Java10Test"; } public void testLocalVarType_DenotableTypes() { - assertFalse(isGwtSourceLevel10()); + var i = 42; + assertEquals(42, i); + var s = "42"; + assertEquals("42", s); + + Supplier initializer = () -> "37"; + var s2 = initializer.get(); + // to be sure that s2 was inferred as a string and not an Object + String s3 = s2; + assertEquals("37", s3); } public void testLocalVarType_Anonymous() { - assertFalse(isGwtSourceLevel10()); + var o = new Object() { + int i; + String s; + }; + o.i = 42; + o.s = "42"; + assertEquals(42, o.i); + assertEquals("42", o.s); } public void testLocalVarType_Ternary() { - assertFalse(isGwtSourceLevel10()); + var value = true ? "a" : 'c'; + checkSerializableDispatch(value); + checkComparableDispatch(value); + assertEquals("a", value.toString()); + } + + private void checkSerializableDispatch(Object fail) { + fail("should not be treated as object"); + } + + private void checkSerializableDispatch(Serializable pass) { + // pass + } + + private void checkComparableDispatch(Object fail) { + fail("should not be treated as object"); + } + + private void checkComparableDispatch(Comparable pass) { + // pass } public void testLocalVarType_LambdaCapture() { - assertFalse(isGwtSourceLevel10()); + var s = "42"; + Supplier supplier = () -> s; + assertEquals("42", supplier.get()); } public void testLocalVarType_VarArg() { - assertFalse(isGwtSourceLevel10()); + var args = new String[] {"4", "2"}; + VarArgsFunction f = arr -> arr[0] + arr[1]; + assertEquals("42", f.apply(args)); } public void testLocalVarType_LocalClass() { - assertFalse(isGwtSourceLevel10()); + var i = 37; + class Local { + int m() { + var i = 40; + return i + 2; + } + + int fromOuterScope() { + return i; + } + } + + var l = new Local(); + assertEquals(37, l.fromOuterScope()); + assertEquals(42, l.m()); } public void testLocalVarType_ForLoop() { - assertFalse(isGwtSourceLevel10()); + var a = new String[] {"4", "2"}; + var s = ""; + for (var i = 0; i < a.length; i++) { + s += a[i]; + } + assertEquals("42", s); } public void testLocalVarType_EnhancedForLoopArray() { - assertFalse(isGwtSourceLevel10()); + var a = new String[] {"4", "2"}; + var str = ""; + for (var s : a) { + str += s; + } + assertEquals("42", str); } public void testLocalVarType_EnhancedNestedForLoopArray() { - assertFalse(isGwtSourceLevel10()); + var m = new int[][] {{1, 2}, {3, 4}}; + var summ = 0; + for (var row : m) { + for (var cell : row) { + summ += cell; + } + } + assertEquals(10, summ); } public void testLocalVarType_EnhancedForLoopIterable() { - assertFalse(isGwtSourceLevel10()); - } - - private boolean isGwtSourceLevel10() { - return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA10) >= 0; + var list = new ArrayList(); + list.add("4"); + list.add("2"); + var str = ""; + for (var s : list) { + str += s; + } + assertEquals("42", str); } } diff --git a/user/test/com/google/gwt/dev/jjs/test/Java11Test.java b/user/test/com/google/gwt/dev/jjs/test/Java11Test.java index 446c487f752..eed3c587951 100644 --- a/user/test/com/google/gwt/dev/jjs/test/Java11Test.java +++ b/user/test/com/google/gwt/dev/jjs/test/Java11Test.java @@ -15,42 +15,41 @@ */ package com.google.gwt.dev.jjs.test; -import com.google.gwt.dev.util.arg.SourceLevel; import com.google.gwt.junit.DoNotRunWith; -import com.google.gwt.junit.JUnitShell; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + /** - * Dummy test case. Java11Test is super sourced so that GWT can be compiled by Java 8. - * - * NOTE: Make sure this class has the same test methods of its supersourced variant. + * Tests Java 11 features. */ @DoNotRunWith(Platform.Devel) public class Java11Test extends GWTTestCase { - @Override - public String getModuleName() { - return "com.google.gwt.dev.jjs.Java11Test"; + @interface NotNull { + } + + interface Lambda { + T run(T a, T b); } @Override - public void runTest() throws Throwable { - // Only run these tests if -sourceLevel 11 (or greater) is enabled. - if (isGwtSourceLevel11()) { - super.runTest(); - } + public String getModuleName() { + return "com.google.gwt.dev.jjs.Java11Test"; } public void testLambdaParametersVarType() { - assertFalse(isGwtSourceLevel11()); + Lambda l = (@NotNull var x, var y) -> x + y; + assertEquals("12", l.run("1", "2")); } public void testLambdaParametersVarType_function() { - assertFalse(isGwtSourceLevel11()); - } - - private boolean isGwtSourceLevel11() { - return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA11) >= 0; + List l = Arrays.asList("a", "b"); + l = l.stream().map((var s) -> s.toUpperCase()).collect(Collectors.toList()); + assertEquals("A", l.get(0)); + assertEquals("B", l.get(1)); } } diff --git a/user/test/com/google/gwt/dev/jjs/test/Java17Test.java b/user/test/com/google/gwt/dev/jjs/test/Java17Test.java new file mode 100644 index 00000000000..4413e90efa8 --- /dev/null +++ b/user/test/com/google/gwt/dev/jjs/test/Java17Test.java @@ -0,0 +1,56 @@ +/* + * Copyright 2019 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.test; + +import com.google.gwt.dev.util.arg.SourceLevel; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.JUnitShell; +import com.google.gwt.junit.Platform; +import com.google.gwt.junit.client.GWTTestCase; + +/** + * Dummy test case. Java17Test is super sourced so that GWT can be compiled by Java 8. + * + * NOTE: Make sure this class has the same test methods of its supersourced variant. + */ +@DoNotRunWith(Platform.Devel) +public class Java17Test extends GWTTestCase { + + @Override + public String getModuleName() { + return "com.google.gwt.dev.jjs.Java17Test"; + } + + @Override + public void runTest() throws Throwable { + // Only run these tests if -sourceLevel 17 (or greater) is enabled. + if (isGwtSourceLevel17()) { + super.runTest(); + } + } + + public void testTextBlocks() { + assertFalse(isGwtSourceLevel17()); + } + + public void testSealedClassesPermitted() { + assertFalse(isGwtSourceLevel17()); + } + + private boolean isGwtSourceLevel17() { + return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA17) >= 0; + } +} diff --git a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java index ed2e5d20d27..81ac455d8bb 100644 --- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java +++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java @@ -15,348 +15,2051 @@ */ package com.google.gwt.dev.jjs.test; -import com.google.gwt.dev.util.arg.SourceLevel; +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsonUtils; +import com.google.gwt.dev.jjs.test.defaultmethods.ImplementsWithDefaultMethodAndStaticInitializer; +import com.google.gwt.dev.jjs.test.defaultmethods.SomeClass; import com.google.gwt.junit.DoNotRunWith; -import com.google.gwt.junit.JUnitShell; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import jsinterop.annotations.JsFunction; +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + /** - * Dummy test case. Java8Test was historically super sourced so that GWT can be compiled by Java 6. - * - * NOTE: Make sure this class has the same test methods of its supersourced variant. + * Tests Java 8 features. */ @DoNotRunWith(Platform.Devel) public class Java8Test extends GWTTestCase { + int local = 42; - @Override - public String getModuleName() { - return "com.google.gwt.dev.jjs.Java8Test"; + static abstract class SameClass { + public int method1() { + return 10; + } + public abstract int method2(); } - @Override - public void runTest() throws Throwable { - // Only run these tests if -sourceLevel 8 (or greater) is enabled. - if (isGwtSourceLevel8()) { - super.runTest(); + interface Lambda { + T run(int a, int b); + } + + interface Lambda2 { + boolean run(String a, String b); + } + + interface Lambda3 { + boolean run(String a); + } + + class AcceptsLambda { + public T accept(Lambda foo) { + return foo.run(10, 20); + } + public boolean accept2(Lambda2 foo) { + return foo.run("a", "b"); + } + public boolean accept3(Lambda3 foo) { + return foo.run("hello"); } } + class Pojo { + private final int x; + private final int y; + + Pojo(int x, int y) { + this.x = x; + this.y = y; + } + + public int fooInstance(int a, int b) { + return a + b + x + y; + } + } + + interface DefaultInterface { + void method1(); + // CHECKSTYLE_OFF + default int method2() { return 42; } + default int redeclaredAsAbstract() { + return 88; + } + default Integer addInts(int x, int y) { return x + y; } + default String print() { return "DefaultInterface"; } + // CHECKSTYLE_ON + } + + interface DefaultInterface2 { + void method3(); + // CHECKSTYLE_OFF + default int method4() { return 23; } + default int redeclaredAsAbstract() { + return 77; + } + // CHECKSTYLE_ON + } + + interface DefaultInterfaceSubType extends DefaultInterface { + // CHECKSTYLE_OFF + default int method2() { return 43; } + default String print() { + return "DefaultInterfaceSubType " + DefaultInterface.super.print(); + } + // CHECKSTYLE_ON + } + + static abstract class DualImplementorSuper implements DefaultInterface { + public void method1() { + } + + public abstract int redeclaredAsAbstract(); + } + + static class DualImplementorBoth extends VirtualUpRef implements DefaultInterface, + DefaultInterface2 { + public void method1() { + } + public void method3() { + } + } + + static class DualImplementor extends DualImplementorSuper implements DefaultInterface2 { + public void method3() { + } + + public int redeclaredAsAbstract() { + return DefaultInterface2.super.redeclaredAsAbstract(); + } + } + + // this doesn't implement DefaultInterface, but will provide implementation in subclasses + static class VirtualUpRef { + public int method2() { + return 99; + } + public int redeclaredAsAbstract() { + return 44; + } + } + + class Inner { + int local = 22; + public void run() { + assertEquals(94, new AcceptsLambda().accept((a,b) -> Java8Test.this.local + local + a + b).intValue()); + } + } + + static class Static { + static int staticField; + static { + staticField = 99; + } + static Integer staticMethod(int x, int y) { + return x + y + staticField; + } + } + + private static void throwInClinit() { + throw new RuntimeException("clinit() shouldn't run from just taking a reference to a method"); + } + static class StaticFailIfClinitRuns { + static { + throwInClinit(); + } + + public static Integer staticMethod(int x, int y) { + return null; + } + } + + static class DefaultInterfaceImpl implements DefaultInterface { + public void method1() { + } + } + + static class DefaultInterfaceImpl2 implements DefaultInterface { + public void method1() { + } + public int method2() { + return 100; + } + } + + static class DefaultInterfaceImplVirtualUpRef extends VirtualUpRef implements DefaultInterface { + public void method1() { + } + } + + static class DefaultInterfaceImplVirtualUpRefTwoInterfaces extends VirtualUpRef + implements DefaultInterfaceSubType { + public void method1() { + } + // CHECKSTYLE_OFF + public String print() { return "DefaultInterfaceImplVirtualUpRefTwoInterfaces"; } + // CHECKSTYLE_ON + } + + @Override + public String getModuleName() { + return "com.google.gwt.dev.jjs.Java8Test"; + } + public void testLambdaNoCapture() { - // Make sure we are using the right Java8Test if the source compatibility level is set to Java 8 - // or above. - assertFalse(isGwtSourceLevel8()); + assertEquals(30, new AcceptsLambda().accept((a, b) -> a + b).intValue()); } public void testLambdaCaptureLocal() { - assertFalse(isGwtSourceLevel8()); + int x = 10; + assertEquals(40, new AcceptsLambda().accept((a,b) -> x + a + b).intValue()); } public void testLambdaCaptureLocalWithInnerClass() { - assertFalse(isGwtSourceLevel8()); + int x = 10; + Lambda l = (a,b) -> new Lambda() { + @Override public Integer run(int a, int b) { + int t = x; + return t + a + b; + } + }.run(a,b); + assertEquals(40, new AcceptsLambda().accept(l).intValue()); } public void testLambdaCaptureLocalAndField() { - assertFalse(isGwtSourceLevel8()); + int x = 10; + assertEquals(82, new AcceptsLambda().accept((a,b) -> x + local + a + b).intValue()); } public void testLambdaCaptureLocalAndFieldWithInnerClass() { - assertFalse(isGwtSourceLevel8()); + int x = 10; + Lambda l = (a,b) -> new Lambda() { + @Override public Integer run(int j, int k) { + int t = x; + int s = local; + return t + s + a + b; + } + }.run(a,b); + assertEquals(82, new AcceptsLambda().accept(l).intValue()); } public void testCompileLambdaCaptureOuterInnerField() throws Exception { - assertFalse(isGwtSourceLevel8()); + new Inner().run(); } public void testStaticReferenceBinding() throws Exception { - assertFalse(isGwtSourceLevel8()); + assertEquals(129, new AcceptsLambda().accept(Static::staticMethod).intValue()); + // if this next line runs a clinit, it fails + Lambda l = dummyMethodToMakeCheckStyleHappy(StaticFailIfClinitRuns::staticMethod); + try { + // but now it should fail + l.run(1,2); + fail("Clinit should have run for the first time"); + } catch (RuntimeException ignored) { + // success, it was supposed to throw! + } + } + + private static Lambda dummyMethodToMakeCheckStyleHappy(Lambda l) { + return l; } public void testInstanceReferenceBinding() throws Exception { - assertFalse(isGwtSourceLevel8()); + Pojo instance1 = new Pojo(1, 2); + Pojo instance2 = new Pojo(3, 4); + assertEquals(33, new AcceptsLambda().accept(instance1::fooInstance).intValue()); + assertEquals(37, new AcceptsLambda().accept(instance2::fooInstance).intValue()); } public void testImplicitQualifierReferenceBinding() throws Exception { - assertFalse(isGwtSourceLevel8()); + assertFalse(new AcceptsLambda().accept2(String::equalsIgnoreCase)); + assertTrue(new AcceptsLambda().accept3("hello world"::contains)); } public void testConstructorReferenceBinding() { - assertFalse(isGwtSourceLevel8()); + assertEquals(30, new AcceptsLambda().accept(Pojo::new).fooInstance(0, 0)); } public void testStaticInterfaceMethod() { - assertFalse(isGwtSourceLevel8()); + assertEquals(99, (int) Static.staticMethod(0, 0)); + } + + interface ArrayCtor { + ArrayElem [][][] copy(int i); + } + + interface ArrayCtorBoxed { + ArrayElem [][][] copy(Integer i); + } + + static class ArrayElem { } public void testArrayConstructorReference() { - assertFalse(isGwtSourceLevel8()); + ArrayCtor ctor = ArrayElem[][][]::new; + ArrayElem[][][] array = ctor.copy(100); + assertEquals(100, array.length); } public void testArrayConstructorReferenceBoxed() { - assertFalse(isGwtSourceLevel8()); + ArrayCtorBoxed ctor = ArrayElem[][][]::new; + ArrayElem[][][] array = ctor.copy(100); + assertEquals(100, array.length); + } + + interface ThreeArgs { + int foo(int x, int y, int z); + } + + interface ThreeVarArgs { + int foo(int x, int y, int... z); + } + + public static int addMany(int x, int y, int... nums) { + int sum = x + y; + for (int num : nums) { + sum += num; + } + return sum; } public void testVarArgsReferenceBinding() { - assertFalse(isGwtSourceLevel8()); + ThreeArgs t = Java8Test::addMany; + assertEquals(6, t.foo(1,2,3)); } public void testVarArgsPassthroughReferenceBinding() { - assertFalse(isGwtSourceLevel8()); + ThreeVarArgs t = Java8Test::addMany; + assertEquals(6, t.foo(1,2,3)); } public void testVarArgsPassthroughReferenceBindingProvidedArray() { - assertFalse(isGwtSourceLevel8()); + ThreeVarArgs t = Java8Test::addMany; + assertEquals(6, t.foo(1,2, new int[] {3})); + } + + interface I { + int foo(Integer i); } public void testSuperReferenceExpression() { - assertFalse(isGwtSourceLevel8()); + class Y { + int foo(Integer i) { + return 42; + } + } + + class X extends Y { + int foo(Integer i) { + return 23; + } + + int goo() { + I i = super::foo; + return i.foo(0); + } + } + + assertEquals(42, new X().goo()); } public void testQualifiedSuperReferenceExpression() { - assertFalse(isGwtSourceLevel8()); + class Y { + int foo(Integer i) { + return 42; + } + } + + class X extends Y { + int foo(Integer i) { + return 23; + } + + int goo() { + I i = X.super::foo; + return i.foo(0); + } + } + + assertEquals(42, new X().goo()); + } + + static class X2 { + protected int field; + void foo() { + int local; + class Y extends X2 { + class Z extends X2 { + void f() { + Ctor c = X2::new; + X2 x = c.makeX(123456); + assertEquals(123456, x.field); + c = Y::new; + x = c.makeX(987654); + x = new Y(987654); + assertEquals(987655, x.field); + c = Z::new; + x = c.makeX(456789); + x = new Z(456789); + assertEquals(456791, x.field); + } + private Z(int z) { + super(z + 2); + } + Z() { + } + } + + private Y(int y) { + super(y + 1); + } + + private Y() { + } + } + new Y().new Z().f(); + } + + private X2(int x) { + this.field = x; + } + X2() { + } } public void testSuperReferenceExpressionWithVarArgs() { - assertFalse(isGwtSourceLevel8()); + class Base { + int foo(Object... objects) { + return 0; + } + } + + class X extends Base { + int foo(Object... objects) { + throw new AssertionError(); + } + + void goo() { + I i = super::foo; + i.foo(10); + } + } + new X().goo(); + } + + interface Ctor { + X2 makeX(int x); } public void testPrivateConstructorReference() { - assertFalse(isGwtSourceLevel8()); + new X2().foo(); } public void testDefaultInterfaceMethod() { - assertFalse(isGwtSourceLevel8()); + assertEquals(42, new DefaultInterfaceImpl().method2()); } public void testDefaultInterfaceMethodVirtualUpRef() { - assertFalse(isGwtSourceLevel8()); + assertEquals(99, new DefaultInterfaceImplVirtualUpRef().method2()); + assertEquals(99, new DefaultInterfaceImplVirtualUpRefTwoInterfaces().method2()); + assertEquals("SimpleB", new com.google.gwt.dev.jjs.test.package3.SimpleC().m()); + assertEquals("SimpleASimpleB", new com.google.gwt.dev.jjs.test.package1.SimpleD().m()); } - public void testInterfaceWithDefaultMethodsInitialization() { - assertFalse(isGwtSourceLevel8()); + public void testDefaultInterfaceMethodMultiple() { + assertEquals(42, new DualImplementor().method2()); + assertEquals(23, new DualImplementor().method4()); + assertEquals(77, new DualImplementor().redeclaredAsAbstract()); + assertEquals(44, new DualImplementorBoth().redeclaredAsAbstract()); + DefaultInterfaceImplVirtualUpRefTwoInterfaces instanceImplementInterfaceSubType = + new DefaultInterfaceImplVirtualUpRefTwoInterfaces(); + DefaultInterfaceSubType interfaceSubType1 = instanceImplementInterfaceSubType; + assertEquals("DefaultInterfaceImplVirtualUpRefTwoInterfaces", + instanceImplementInterfaceSubType.print()); + assertEquals("DefaultInterfaceImplVirtualUpRefTwoInterfaces", interfaceSubType1.print()); + DefaultInterfaceSubType interfaceSubType2 = new DefaultInterfaceSubType() { + @Override + public void method1() { } + }; + assertEquals("DefaultInterfaceSubType DefaultInterface", + interfaceSubType2.print()); + DefaultInterfaceSubType interfaceSubType3 = () -> { }; + assertEquals("DefaultInterfaceSubType DefaultInterface", + interfaceSubType3.print()); } - public void testDefaultInterfaceMethodMultiple() { - assertFalse(isGwtSourceLevel8()); + public void testDefenderMethodByInterfaceInstance() { + DefaultInterfaceImpl2 interfaceImpl2 = new DefaultInterfaceImpl2(); + DefaultInterface interface1 = interfaceImpl2; + assertEquals(100, interfaceImpl2.method2()); + assertEquals(100, interface1.method2()); } public void testDefaultMethodReference() { - assertFalse(isGwtSourceLevel8()); + DefaultInterfaceImplVirtualUpRef x = new DefaultInterfaceImplVirtualUpRef(); + assertEquals(30, (int) new AcceptsLambda().accept(x::addInts)); } - public void testDefenderMethodByInterfaceInstance() { - assertFalse(isGwtSourceLevel8()); + interface InterfaceWithTwoDefenderMethods { + // CHECKSTYLE_OFF + default String foo() { return "interface.foo"; } + default String bar() { return this.foo() + " " + foo(); } + // CHECKSTYLE_ON } - public void testDefaultMethod_staticInitializer() { - assertFalse(isGwtSourceLevel8()); + class ClassImplementOneDefenderMethod implements InterfaceWithTwoDefenderMethods { + public String foo() { + return "class.foo"; + } } public void testThisRefInDefenderMethod() { - assertFalse(isGwtSourceLevel8()); + ClassImplementOneDefenderMethod c = new ClassImplementOneDefenderMethod(); + InterfaceWithTwoDefenderMethods i1 = c; + InterfaceWithTwoDefenderMethods i2 = new InterfaceWithTwoDefenderMethods() { }; + assertEquals("class.foo class.foo", c.bar()); + assertEquals("class.foo class.foo", i1.bar()); + assertEquals("interface.foo interface.foo", i2.bar()); + } + + interface InterfaceImplementOneDefenderMethod extends InterfaceWithTwoDefenderMethods { + // CHECKSTYLE_OFF + default String foo() { return "interface1.foo"; } + // CHECKSTYLE_ON + } + + interface InterfaceImplementZeroDefenderMethod extends InterfaceWithTwoDefenderMethods { + } + + class ClassImplementsTwoInterfaces implements InterfaceImplementOneDefenderMethod, + InterfaceImplementZeroDefenderMethod { } public void testClassImplementsTwoInterfacesWithSameDefenderMethod() { - assertFalse(isGwtSourceLevel8()); + ClassImplementsTwoInterfaces c = new ClassImplementsTwoInterfaces(); + assertEquals("interface1.foo", c.foo()); + } + + abstract class AbstractClass implements InterfaceWithTwoDefenderMethods { + } + + class Child1 extends AbstractClass { + public String foo() { + return super.foo() + " child1.foo"; + } + } + + class Child2 extends AbstractClass { } public void testAbstractClassImplementsInterface() { - assertFalse(isGwtSourceLevel8()); + Child1 child1 = new Child1(); + Child2 child2 = new Child2(); + assertEquals("interface.foo child1.foo", child1.foo()); + assertEquals("interface.foo", child2.foo()); + } + + interface InterfaceI { + // CHECKSTYLE_OFF + default String print() { return "interface1"; } + // CHECKSTYLE_ON + } + interface InterfaceII { + // CHECKSTYLE_OFF + default String print() { return "interface2"; } + // CHECKSTYLE_ON + } + class ClassI { + public String print() { + return "class1"; + } + } + class ClassII extends ClassI implements InterfaceI, InterfaceII { + public String print() { + return super.print() + " " + InterfaceI.super.print() + " " + InterfaceII.super.print(); + } } public void testSuperRefInDefenderMethod() { - assertFalse(isGwtSourceLevel8()); + ClassII c = new ClassII(); + assertEquals("class1 interface1 interface2", c.print()); } - public void testSuperThisRefsInDefenderMethod() { - assertFalse(isGwtSourceLevel8()); + interface II { + // CHECKSTYLE_OFF + default String fun() { return "fun() in i: " + this.foo(); }; + default String foo() { return "foo() in i.\n"; }; + // CHECKSTYLE_ON + } + interface JJ extends II { + // CHECKSTYLE_OFF + default String fun() { return "fun() in j: " + this.foo() + II.super.fun(); }; + default String foo() { return "foo() in j.\n"; } + // CHECKSTYLE_ON + } + class AA { + public String fun() { + return "fun() in a: " + this.foo(); + } + public String foo() { + return "foo() in a.\n"; + } + } + class BB extends AA implements JJ { + public String fun() { + return "fun() in b: " + this.foo() + super.fun() + JJ.super.fun(); + } + public String foo() { + return "foo() in b.\n"; + } + } + class CC extends BB implements JJ { + public String fun() { + return "fun() in c: " + super.fun(); + } } + public void testSuperThisRefsInDefenderMethod() { + CC c = new CC(); + II i1 = c; + JJ j1 = c; + BB b = new BB(); + II i2 = b; + JJ j2 = b; + JJ j3 = new JJ() { }; + II i3 = j3; + II i4 = new II() { }; + String c_fun = "fun() in c: fun() in b: foo() in b.\n" + + "fun() in a: foo() in b.\n" + + "fun() in j: foo() in b.\n" + + "fun() in i: foo() in b.\n"; + String b_fun = "fun() in b: foo() in b.\n" + + "fun() in a: foo() in b.\n" + + "fun() in j: foo() in b.\n" + + "fun() in i: foo() in b.\n"; + String j_fun = "fun() in j: foo() in j.\n" + + "fun() in i: foo() in j.\n"; + String i_fun = "fun() in i: foo() in i.\n"; + assertEquals(c_fun, c.fun()); + assertEquals(c_fun, i1.fun()); + assertEquals(c_fun, j1.fun()); + assertEquals(b_fun, b.fun()); + assertEquals(b_fun, i2.fun()); + assertEquals(b_fun, j2.fun()); + assertEquals(j_fun, j3.fun()); + assertEquals(j_fun, i3.fun()); + assertEquals(i_fun, i4.fun()); + } + + interface OuterInterface { + // CHECKSTYLE_OFF + default String m() { + return "I.m;" + new InnerClass().n(); + } + default String n() { + return "I.n;" + this.m(); + } + // CHECKSTYLE_ON + class InnerClass { + public String n() { + return "A.n;" + m(); + } + public String m() { + return "A.m;"; + } + } + } + class OuterClass { + public String m() { + return "B.m;"; + } + public String n1() { + OuterInterface i = new OuterInterface() { }; + return "B.n1;" + i.n() + OuterClass.this.m(); + } + public String n2() { + OuterInterface i = new OuterInterface() { + @Override + public String n() { + return this.m() + OuterClass.this.m(); + } + }; + return "B.n2;" + i.n() + OuterClass.this.m(); + } + } public void testNestedInterfaceClass() { - assertFalse(isGwtSourceLevel8()); + OuterClass outerClass = new OuterClass(); + assertEquals("B.n1;I.n;I.m;A.n;A.m;B.m;", outerClass.n1()); + assertEquals("B.n2;I.m;A.n;A.m;B.m;B.m;", outerClass.n2()); } + class EmptyA { } + interface EmptyI { } + interface EmptyJ { } + class EmptyB extends EmptyA implements EmptyI { } + class EmptyC extends EmptyA implements EmptyI, EmptyJ { } public void testBaseIntersectionCast() { - assertFalse(isGwtSourceLevel8()); + EmptyA localB = new EmptyB(); + EmptyA localC = new EmptyC(); + EmptyB b2BI = (EmptyB & EmptyI) localB; + EmptyC c2CIJ = (EmptyC & EmptyI & EmptyJ) localC; + EmptyI ii1 = (EmptyB & EmptyI) localB; + EmptyI ii2 = (EmptyC & EmptyI) localC; + EmptyI ii3 = (EmptyC & EmptyJ) localC; + EmptyI ii4 = (EmptyC & EmptyI & EmptyJ) localC; + EmptyJ jj1 = (EmptyC & EmptyI & EmptyJ) localC; + EmptyJ jj2 = (EmptyC & EmptyI) localC; + EmptyJ jj3 = (EmptyC & EmptyJ) localC; + EmptyJ jj4 = (EmptyI & EmptyJ) localC; + + try { + EmptyC b2CIJ = (EmptyC & EmptyI & EmptyJ) localB; + fail("Should have thrown a ClassCastException"); + } catch (ClassCastException e) { + // Expected. + } + try { + EmptyB c2BI = (EmptyB & EmptyI) localC; + fail("Should have thrown a ClassCastException"); + } catch (ClassCastException e) { + // Expected. + } + try { + EmptyJ jj = (EmptyB & EmptyJ) localB; + fail("Should have thrown a ClassCastException"); + } catch (ClassCastException e) { + // Expected. + } } + interface SimpleI { + int fun(); + } + interface SimpleK { + } public void testIntersectionCastWithLambdaExpr() { - assertFalse(isGwtSourceLevel8()); + SimpleI simpleI1 = (SimpleI & EmptyI) () -> 11; + assertEquals(11, simpleI1.fun()); + SimpleI simpleI2 = (EmptyI & SimpleI) () -> 22; + assertEquals(22, simpleI2.fun()); + EmptyI emptyI = (EmptyI & SimpleI) () -> 33; + assertEquals(55, ((SimpleI & SimpleK) () -> 55).fun()); + } + + class SimpleA { + public int bar() { + return 11; + } + } + + class SimpleB extends SimpleA implements SimpleI { + public int fun() { + return 22; + } + } + + class SimpleC extends SimpleA implements SimpleI { + public int fun() { + return 33; + } + + public int bar() { + return 44; + } } public void testIntersectionCastPolymorphism() { - assertFalse(isGwtSourceLevel8()); + SimpleA bb = new SimpleB(); + assertEquals(22, ((SimpleB & SimpleI) bb).fun()); + assertEquals(11, ((SimpleB & SimpleI) bb).bar()); + SimpleA cc = new SimpleC(); + assertEquals(33, ((SimpleC & SimpleI) cc).fun()); + assertEquals(44, ((SimpleC & SimpleI) cc).bar()); + assertEquals(33, ((SimpleA & SimpleI) cc).fun()); + SimpleI ii = (SimpleC & SimpleI) cc; + assertEquals(33, ii.fun()); } + interface ClickHandler { + int onClick(int a); + } + private int addClickHandler(ClickHandler clickHandler) { + return clickHandler.onClick(1); + } + private int addClickHandler(int a) { + return addClickHandler(x -> { + int temp = a; return temp; + }); + } public void testLambdaCaptureParameter() { - assertFalse(isGwtSourceLevel8()); + assertEquals(2, addClickHandler(2)); } + interface TestLambda_Inner { + void f(); + } + interface TestLambda_Outer { + void accept(TestLambda_Inner t); + } + public void testLambda_call(TestLambda_Outer a) { + a.accept(() -> { }); + } public void testLambdaNestingCaptureLocal() { - assertFalse(isGwtSourceLevel8()); + int[] success = new int[] {0}; + testLambda_call(sam1 -> { + testLambda_call(sam2 -> { + success[0] = 10; + }); + }); + assertEquals(10, success[0]); } public void testLambdaNestingInAnonymousCaptureLocal() { - assertFalse(isGwtSourceLevel8()); + int[] x = new int[] {42}; + new Runnable() { + public void run() { + Lambda l = (a, b) -> x[0] = x[0] + a + b; + l.run(1, 2); + } + }.run(); + assertEquals(45, x[0]); } public void testLambdaNestingInMultipleMixedAnonymousCaptureLocal() { - assertFalse(isGwtSourceLevel8()); + // checks that lambda has access to local variable and arguments when placed in mixed scopes + // Local Class -> Local Class -> Local Anonymous -> lambda -> Local Anonymous + class A { + int a() { + int[] x = new int[] {42}; + class B { + void b() { + I i = new I() { + public int foo(Integer arg) { + Runnable r = () -> { + new Runnable() { + public void run() { + Lambda l = (a, b) -> x[0] = x[0] + a + b + arg; + l.run(1, 2); + } + }.run(); + }; + r.run(); + return x[0]; + } + }; + i.foo(1); + } + } + B b = new B(); + b.b(); + return x[0]; + } + } + A a = new A(); + assertEquals(46, a.a()); } public void testLambdaNestingInMultipleMixedAnonymousCaptureLocal_withInterference() { - assertFalse(isGwtSourceLevel8()); + // checks that lambda has access to NEAREST local variable and arguments when placed in mixed + // scopes Local Class -> Local Class -> Local Anonymous -> lambda -> Local Anonymous + class A { + int a() { + int[] x = new int[] {42}; + class B { + int b() { + int[] x = new int[] {22}; + I i = new I() { + public int foo(Integer arg) { + Runnable r = () -> { + new Runnable() { + public void run() { + Lambda l = (a, b) -> x[0] = x[0] + a + b + arg; + l.run(1, 2); + } + }.run(); + }; + r.run(); + return x[0]; + } + }; + return i.foo(1); + } + } + B b = new B(); + return b.b(); + } + } + A a = new A(); + assertEquals(26, a.a()); } public void testLambdaNestingInMultipleMixedAnonymousCaptureLocalAndField() { - assertFalse(isGwtSourceLevel8()); + // checks that lambda has access to local variable, field and arguments when placed in mixed + // scopes - Local Class -> Local Class -> Local Anonymous -> lambda -> Local Anonymous + class A { + int fA = 1; + + int a() { + int[] x = new int[] {42}; + class B { + int fB = 2; + + int b() { + I i = new I() { + int fI = 3; + + public int foo(Integer arg) { + Runnable r = () -> { + new Runnable() { + public void run() { + Lambda l = (a, b) -> x[0] = x[0] + a + b + arg + fA + fB + fI; + l.run(1, 2); + } + }.run(); + }; + r.run(); + return x[0]; + } + }; + return i.foo(1); + } + } + B b = new B(); + return b.b(); + } + } + A a = new A(); + assertEquals(52, a.a()); } public void testLambdaNestingInMultipleAnonymousCaptureLocal() { - assertFalse(isGwtSourceLevel8()); + // checks that lambda has access to local variable and arguments when placed in local anonymous + // class with multile nesting + int[] x = new int[] {42}; + int result = new I() { + public int foo(Integer i1) { + return new I() { + public int foo(Integer i2) { + return new I() { + public int foo(Integer i3) { + Lambda l = (a, b) -> x[0] = x[0] + a + b + i1 + i2 + i3; + return l.run(1, 2); + } + }.foo(3); + } + }.foo(2); + } + }.foo(1); + assertEquals(51, x[0]); + } + + static class TestLambda_ClassA { + int[] f = new int[] {42}; + + class B { + void m() { + Runnable r = () -> f[0] = f[0] + 1; + r.run(); + } + } + + int a() { + B b = new B(); + b.m(); + return f[0]; + } } public void testLambdaNestingCaptureField_InnerClassCapturingOuterClassVariable() { - assertFalse(isGwtSourceLevel8()); + TestLambda_ClassA a = new TestLambda_ClassA(); + assertEquals(43, a.a()); } public void testInnerClassCaptureLocalFromOuterLambda() { - assertFalse(isGwtSourceLevel8()); + int[] x = new int[] {42}; + Lambda l = (a, b) -> { + int[] x1 = new int[] {32}; + Lambda r = (rA, rB) -> { + int[] x2 = new int[] {22}; + I i = new I() { + public int foo(Integer arg) { + x1[0] = x1[0] + 1; + x[0] = x[0] + 1; + return x2[0] = x2[0] + rA + rB + a + b; + } + }; + return i.foo(1); + }; + return r.run(3, 4) + x1[0]; + }; + + // x1[0](32) + 1 + x2[0](22) + rA(3) + rB(4) + a(1) + b(2) + assertEquals(65, l.run(1, 2).intValue()); + assertEquals(43, x[0]); + } + + static class TestLambda_Class { + public int[] s = new int[] {0}; + public void call(TestLambda_Outer a) { + a.accept(() -> { }); + } + class TestLambda_InnerClass { + public int[] s = new int[] {0}; + public int test() { + int[] s = new int[] {0}; + TestLambda_Class.this.call( + sam0 -> TestLambda_Class.this.call( + sam1 -> { + TestLambda_Class.this.call( + sam2 -> { + TestLambda_Class.this.s[0] = 10; + this.s[0] = 20; + s[0] = 30; + }); + })); + return s[0]; + } + } } public void testLambdaNestingCaptureField() { - assertFalse(isGwtSourceLevel8()); + TestLambda_Class a = new TestLambda_Class(); + a.call(sam1 -> { + a.call(sam2 -> { + a.s[0] = 20; + }); + }); + assertEquals(20, a.s[0]); } public void testLambdaMultipleNestingCaptureFieldAndLocal() { - assertFalse(isGwtSourceLevel8()); + TestLambda_Class a = new TestLambda_Class(); + TestLambda_Class b = new TestLambda_Class(); + int [] s = new int [] {0}; + b.call(sam0 -> a.call(sam1 -> { + a.call(sam2 -> { + a.s[0] = 20; + b.s[0] = 30; + s[0] = 40; + }); + })); + assertEquals(20, a.s[0]); + assertEquals(30, b.s[0]); + assertEquals(40, s[0]); } public void testLambdaMultipleNestingCaptureFieldAndLocalInnerClass() { - assertFalse(isGwtSourceLevel8()); + TestLambda_Class a = new TestLambda_Class(); + TestLambda_Class.TestLambda_InnerClass b = a.new TestLambda_InnerClass(); + int result = b.test(); + assertEquals(10, a.s[0]); + assertEquals(20, b.s[0]); + assertEquals(30, result); + } + + static class TestMF_A { + public static String getId() { + return "A"; + } + public int getIdx() { + return 1; + } + } + static class TestMF_B { + public static String getId() { + return "B"; + } + public int getIdx() { + return 2; + } + } + interface Function { + T apply(); + } + private String f(Function arg) { + return arg.apply(); + } + private int g(Function arg) { + return arg.apply().intValue(); } public void testMethodRefWithSameName() { - assertFalse(isGwtSourceLevel8()); + assertEquals("A", f(TestMF_A::getId)); + assertEquals("B", f(TestMF_B::getId)); + TestMF_A a = new TestMF_A(); + TestMF_B b = new TestMF_B(); + assertEquals(1, g(a::getIdx)); + assertEquals(2, g(b::getIdx)); + } + + // Test particular scenarios involving multiple path to inherit defaults. + interface ITop { + default String m() { + return "ITop.m()"; + } + } + + interface IRight extends ITop { + default String m() { + return "IRight.m()"; + } } + interface ILeft extends ITop { } + public void testMultipleDefaults_fromInterfaces_left() { - assertFalse(isGwtSourceLevel8()); + class A implements ILeft, IRight { } + + assertEquals("IRight.m()", new A().m()); } public void testMultipleDefaults_fromInterfaces_right() { - assertFalse(isGwtSourceLevel8()); + class A implements IRight, ILeft { } + + assertEquals("IRight.m()", new A().m()); } public void testMultipleDefaults_superclass_left() { - assertFalse(isGwtSourceLevel8()); + class A implements ITop { } + class B extends A implements ILeft, IRight { } + + assertEquals("IRight.m()", new B().m()); } public void testMultipleDefaults_superclass_right() { - assertFalse(isGwtSourceLevel8()); + class A implements ITop { } + class B extends A implements IRight, ILeft { } + + assertEquals("IRight.m()", new B().m()); + } + + static class DefaultTrumpsOverSyntheticAbstractStub { + interface SuperInterface { + String m(); + } + + interface SubInterface extends SuperInterface { + default String m() { + return "SubInterface.m()"; + } + } } public void testMultipleDefaults_defaultShadowsOverSyntheticAbstractStub() { - assertFalse(isGwtSourceLevel8()); + abstract class A implements DefaultTrumpsOverSyntheticAbstractStub.SuperInterface { } + class B extends A implements DefaultTrumpsOverSyntheticAbstractStub.SubInterface { } + + assertEquals("SubInterface.m()", new B().m()); + } + + static class DefaultTrumpsOverDefaultOnSuperAbstract { + interface SuperInterface { + default String m() { + return "SuperInterface.m()"; + } + } + + interface SubInterface extends SuperInterface { + default String m() { + return "SubInterface.m()"; + } + } } public void testMultipleDefaults_defaultShadowsOverDefaultOnSuperAbstract() { - assertFalse(isGwtSourceLevel8()); + abstract class A implements DefaultTrumpsOverDefaultOnSuperAbstract.SuperInterface { } + class B extends A implements DefaultTrumpsOverDefaultOnSuperAbstract.SubInterface { } + + assertEquals("SubInterface.m()", new B().m()); + } + + interface InterfaceWithThisReference { + default String n() { + return "default n"; + } + default String callNUnqualified() { + class Super implements InterfaceWithThisReference { + public String n() { + return "super n"; + } + } + return new Super() { + public String callNUnqualified() { + return "Object " + n(); + } + }.callNUnqualified(); + } + default String callNWithThis() { + class Super implements InterfaceWithThisReference { + public String n() { + return "super n"; + } + } + return new Super() { + public String callNWithThis() { + return "Object " + this.n(); + } + }.callNWithThis(); + } + default String callNWithInterfaceThis() { + class Super implements InterfaceWithThisReference { + public String n() { + return "super n"; + } + } + return new Super() { + public String callNWithInterfaceThis() { + // In this method this has interface Test as its type, but it refers to outer n(); + return "Object " + InterfaceWithThisReference.this.n(); + } + }.callNWithInterfaceThis(); + } + default String callNWithSuper() { + class Super implements InterfaceWithThisReference { + public String n() { + return "super n"; + } + } + return new Super() { + public String callNWithSuper() { + // In this method this has interface Test as its type. + return "Object " + super.n(); + } + }.callNWithSuper(); + } + default String callNWithInterfaceSuper() { + return new InterfaceWithThisReference() { + public String n() { + return "this n"; + } + public String callNWithInterfaceSuper() { + // In this method this has interface Test as its type and refers to default n(); + return "Object " + InterfaceWithThisReference.super.n(); + } + }.callNWithInterfaceSuper(); + } } public void testInterfaceThis() { - assertFalse(isGwtSourceLevel8()); + class A implements InterfaceWithThisReference { + public String n() { + return "n"; + } + } + assertEquals("Object super n", new A().callNUnqualified()); + assertEquals("Object super n", new A().callNWithThis()); + assertEquals("Object n", new A().callNWithInterfaceThis()); + assertEquals("Object super n", new A().callNWithSuper()); + assertEquals("Object default n", new A().callNWithInterfaceSuper()); + } + + private static List initializationOrder; + + private static int get(String s) { + initializationOrder.add(s); + return 1; + } + + interface A1 { + int fa1 = get("A1"); + + default void a1() { } + } + + interface A2 { + int fa2 = get("A2"); + + default void a2() { } + } + + interface A3 { + int fa3 = get("A3"); + + default void a3() { } + } + + interface B1 extends A1 { + int fb1 = get("B1"); + + default void b1() { } + } + + interface B2 extends A2 { + int fb2 = get("B2"); + + default void b2() { } + } + + interface B3 extends A3 { + int fb3 = get("B3"); + } + + static class C implements B1, A2 { + static { + get("C"); + } + } + + static class D extends C implements B2, B3 { + static { + get("D"); + } + } + + public void testInterfaceWithDefaultMethodsInitialization() { + initializationOrder = new ArrayList(); + new D(); + assertContentsInOrder(initializationOrder, "A1", "B1", "A2", "C", "B2", "A3", "D"); + } + + /** + * Regression test for issue 9214. + */ + interface P { + boolean apply(T obj); + } + + static class B { + public boolean getTrue() { + return true; + } + } + private static String getClassName(T obj) { + return obj.getClass().getSimpleName(); } public void testMethodReference_generics() { - assertFalse(isGwtSourceLevel8()); + P p = B::getTrue; + assertTrue(p.apply(new B())); + // The next two method references must result in two different lambda implementations due + // to generics, see bug # 9333. + MyFunction1 f1 = Java8Test::getClassName; + MyFunction1 f2 = Java8Test::getClassName; + + assertEquals(B.class.getSimpleName(), f1.apply(new B())); + assertEquals(Double.class.getSimpleName(), f2.apply(new Double(2))); + } + + public void testDefaultMethod_staticInitializer() { + SomeClass.initializationOrder = new ArrayList(); + Object object = ImplementsWithDefaultMethodAndStaticInitializer.someClass; + assertContentsInOrder(SomeClass.initializationOrder, "1", "2", "3", "4"); + } + + private void assertContentsInOrder(Iterable contents, String... elements) { + assertEquals(Arrays.asList(elements).toString(), contents.toString()); + } + + @JsType(isNative = true) + interface NativeJsTypeInterfaceWithStaticInitializationAndFieldAccess { + @JsOverlay + Object object = new Integer(3); + } + + @JsType(isNative = true) + interface NativeJsTypeInterfaceWithStaticInitializationAndStaticOverlayMethod { + @JsOverlay + Object object = new Integer(4); + + @JsOverlay + static Object getObject() { + return object; + } + } + + @JsType(isNative = true) + interface NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod { + @JsOverlay + Object object = new Integer(5); + + int getA(); + + @JsOverlay + default Object getObject() { + return ((int) object) + this.getA(); + } + } + + private native NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod + createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() /*-{ + return { getA: function() { return 1; } }; + }-*/; + + @JsType(isNative = true) + interface NativeJsTypeInterfaceWithStaticInitialization { + @JsOverlay + Object object = new Integer(6); + } + + @JsType(isNative = true) + interface NativeJsTypeInterfaceWithComplexStaticInitialization { + @JsOverlay + Object object = (Integer) (((int) NativeJsTypeInterfaceWithStaticInitialization.object) + 1); + } + + static class JavaTypeImplementingNativeJsTypeInterceWithDefaultMethod implements + NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod { + public int getA() { + return 4; + } } public void testNativeJsTypeWithStaticInitializer() { - assertFalse(isGwtSourceLevel8()); + assertEquals(3, NativeJsTypeInterfaceWithStaticInitializationAndFieldAccess.object); + assertEquals( + 4, NativeJsTypeInterfaceWithStaticInitializationAndStaticOverlayMethod.getObject()); + assertEquals(6, + createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() + .getObject()); + assertEquals(7, NativeJsTypeInterfaceWithComplexStaticInitialization.object); + assertEquals(9, new JavaTypeImplementingNativeJsTypeInterceWithDefaultMethod().getObject()); + } + + @JsFunction + interface VarargsFunction { + String f(int i, String... args); } + private static native String callFromJSNI(VarargsFunction f) /*-{ + return f(2, "a", "b", "c"); + }-*/; + public void testJsVarargsLambda() { - assertFalse(isGwtSourceLevel8()); + VarargsFunction function = (i, args) -> args[i]; + assertSame("b", function.f(1, "a", "b", "c")); + assertSame("c", callFromJSNI(function)); + String[] pars = new String[] {"a", "b", "c"}; + assertSame("a", function.f(0, pars)); + } + + private static T m(T s) { + return s; + } + + static class Some { + T s; + MyFunction2 combine; + Some(T s, MyFunction2 combine) { + this.s = s; + this.combine = combine; + } + public T m(T s2) { + return combine.apply(s, s2); + } + public T m1() { + return s; + } + } + + @FunctionalInterface + interface MyFunction1 { + U apply(T t); + } + + @FunctionalInterface + interface MyFunction2 { + V apply(T t, U u); + } + + @FunctionalInterface + interface MyFunction3 { + W apply(T t, U u, V v); + } + + @FunctionalInterface + interface IntFunction1 { + U apply(int t); + } + + @FunctionalInterface + interface IntFunction2 { + V apply(int t, int u); + } + + @FunctionalInterface + interface IntFunction3 { + W apply(int t, int u, int v); } public void testMethodReference_implementedInSuperclass() { - assertFalse(isGwtSourceLevel8()); + MyFunction1 toString = StringBuilder::toString; + assertEquals("Hello", toString.apply(new StringBuilder("Hello"))); } + static MyFunction2 concat = (s,t) -> s + t; + public void testMethodReference_genericTypeParameters() { - assertFalse(isGwtSourceLevel8()); + testMethodReference_genericTypeParameters( + new Some("Hell", concat), "Hell", "o", concat); } - public void testMethodReference_autoboxing() { - assertFalse(isGwtSourceLevel8()); + static String concat(String... strs) { + String result = ""; + for (String s : strs) { + result += s; + } + return result; + } + + static String anotherConcat(String s1, String s2, String... strs) { + String result = s1 + s2; + for (String s : strs) { + result += s; + } + return result; + } + + public String instanceConcat(String... strs) { + String result = ""; + for (String s : strs) { + result += s; + } + return result; + } + + public String anotherInstanceConcat(String s1, String... strs) { + String result = s1; + for (String s : strs) { + result += s; + } + return result; + } + + private static class ClassWithVarArgsConstructor { + private class Inner { + private int sum; + Inner(int i, Integer... nums) { + this.sum = ClassWithVarArgsConstructor.this.sum + i; + for (Integer n: nums) { + sum += n; + } + } + } + + private int sum; + ClassWithVarArgsConstructor(int i, Integer... nums) { + sum = i; + for (Integer n: nums) { + sum += n; + } + } + + private MyFunction1 createInner1Param() { + return (MyFunction1) Inner::new; + } + + private MyFunction2 createInner2Param() { + return (MyFunction2) Inner::new; + } + + private MyFunction3 createInner3Param() { + return (MyFunction3) Inner::new; + } + + private MyFunction2 createInner2ParamArray() { + return (MyFunction2) Inner::new; + } + + private IntFunction1 createInner1IntParam() { + return (IntFunction1) Inner::new; + } + + private IntFunction2 createInner2IntParam() { + return (IntFunction2) Inner::new; + } + + private IntFunction3 createInner3IntParam() { + return (IntFunction3) Inner::new; + } } public void testMethodReference_varargs() { - assertFalse(isGwtSourceLevel8()); + // More functional arguments than varargs + MyFunction2 concat = Java8Test::concat; + assertEquals("ab", concat.apply("a", "b")); + + // Less functional arguments than varargs + MyFunction2 anotherConcat = Java8Test::anotherConcat; + assertEquals("ab", anotherConcat.apply("a", "b")); + + MyFunction2 instanceConcat = Java8Test::instanceConcat; + assertEquals("a", instanceConcat.apply(this, "a")); + + MyFunction2 anotherInstanceConcat = Java8Test::anotherInstanceConcat; + assertEquals("a", anotherInstanceConcat.apply(this, "a")); + + // constructor varargs + MyFunction1 constructor1Param = + ClassWithVarArgsConstructor::new; + assertEquals(1, constructor1Param.apply(1).sum); + + MyFunction2 constructor2Param = + ClassWithVarArgsConstructor::new; + assertEquals(3, constructor2Param.apply(1, 2).sum); + + MyFunction3 constructor3Param = + ClassWithVarArgsConstructor::new; + assertEquals(6, constructor3Param.apply(1, 2, 3).sum); + + MyFunction2 constructor2ParamArray = + ClassWithVarArgsConstructor::new; + assertEquals(6, constructor2ParamArray.apply(1, new Integer[] {2, 3}).sum); + + // constructor varargs + autoboxing + IntFunction1 constructor1IntParam = + ClassWithVarArgsConstructor::new; + assertEquals(1, constructor1IntParam.apply(1).sum); + + IntFunction2 constructor2IntParam = + ClassWithVarArgsConstructor::new; + assertEquals(3, constructor2IntParam.apply(1, 2).sum); + + IntFunction3 constructor3IntParam = + ClassWithVarArgsConstructor::new; + assertEquals(6, constructor3IntParam.apply(1, 2, 3).sum); + + ClassWithVarArgsConstructor outer = new ClassWithVarArgsConstructor(1); + + // inner class constructor varargs + assertEquals(2, outer.createInner1Param().apply(1).sum); + assertEquals(4, outer.createInner2Param().apply(1, 2).sum); + assertEquals(7, outer.createInner3Param().apply(1, 2, 3).sum); + assertEquals(7, outer.createInner2ParamArray().apply(1, new Integer[] {2, 3}).sum); + + // inner class constructor varargs + autoboxing + assertEquals(2, outer.createInner1IntParam().apply(1).sum); + assertEquals(4, outer.createInner2IntParam().apply(1, 2).sum); + assertEquals(7, outer.createInner3IntParam().apply(1, 2, 3).sum); + } + + private static void testMethodReference_genericTypeParameters( + Some some, T t1, T t2, MyFunction2 combine) { + T t1t2 = combine.apply(t1, t2); + + // Test all 4 flavours of methodReference + // 1. Static method + assertEquals(t1t2, ((MyFunction1) Java8Test::m).apply(t1t2)); + // 2. Qualified instance method + assertEquals(t1t2, ((MyFunction1) some::m).apply(t2)); + // 3. Unqualified instance method + assertEquals(t1, ((MyFunction1, T>) Some::m1).apply(some)); + assertEquals("Hello", + ((MyFunction1, String>) + Some::m1).apply(new Some<>("Hello", concat))); + // 4. Constructor reference. + assertEquals(t1t2, + ((MyFunction2, Some>) Some::new).apply(t1t2, combine).m1()); + } + + static MyFunction2 addInteger = (s,t) -> s + t; + + @FunctionalInterface + interface MyIntFunction1 { + int apply(int t); + } + + @FunctionalInterface + interface MyIntFunction2 { + int apply(int t, int u); + } + + @FunctionalInterface + interface MyIntFuncToSomeIntegeFunction2 { + SomeInteger apply(int t, MyFunction2 u); + } + + @FunctionalInterface + interface MySomeIntegerFunction1 { + int apply(SomeInteger t); } + @FunctionalInterface + interface MySomeIntegerIntFunction2 { + int apply(SomeInteger t, int u); + } + + static MyIntFunction2 addint = (s,t) -> s + t; + + static class SomeInteger { + int s; + MyFunction2 combine; + SomeInteger(int s, MyFunction2 combine) { + this.s = s; + this.combine = combine; + } + public int m(int s2) { + return combine.apply(s, s2); + } + public int m1() { + return s; + } + } + + public void testMethodReference_autoboxing() { + SomeInteger some = new SomeInteger(3, addInteger); + + // Test all 4 flavours of methodReference autoboxing parameters. + // 1. Static method + assertEquals((Integer) 5, ((MyFunction1) Java8Test::m).apply(5)); + // 2. Qualified instance method + assertEquals((Integer) 5, ((MyFunction1) some::m).apply(2)); + // 3. Unqualified instance method + assertEquals((Integer) 3, ((MyFunction1) SomeInteger::m1).apply(some)); + assertEquals((Integer) 5, ((MyFunction2) + SomeInteger::m).apply(some, 2)); + assertEquals((Integer) 5, + ((MyFunction1) + SomeInteger::m1).apply(new SomeInteger(5, addInteger))); + // 4. Constructor reference. + assertEquals(5, + ((MyFunction2, SomeInteger>) + SomeInteger::new).apply(5, addInteger).m1()); + + // Test all 4 flavours of methodReference (interface unboxed) + // 1. Static method + assertEquals(5, ((MyIntFunction1) Java8Test::m).apply(5)); + // 2. Qualified instance method + assertEquals(5, ((MyIntFunction1) some::m).apply(2)); + // 3. Unqualified instance method + assertEquals(3, ((MySomeIntegerFunction1) SomeInteger::m1).apply(some)); + // The next expression was the one that triggered bug #9346 where decisions on whether to + // box/unbox were decided incorrectly due to differring number of parameters in the method + // reference and the functional interface method. + assertEquals(5, ((MySomeIntegerIntFunction2) SomeInteger::m).apply(some, 2)); + assertEquals(5, + ((MySomeIntegerFunction1) + SomeInteger::m1).apply(new SomeInteger(5, addInteger))); + // 4. Constructor reference. + assertEquals(5, + ((MyIntFuncToSomeIntegeFunction2) SomeInteger::new).apply(5, addInteger).m1()); + } + + @JsType(isNative = true) + private static class NativeClassWithJsOverlay { + @JsOverlay + public static String m(String s) { + MyFunction1 id = (a) -> a; + return id.apply(s); + } + } public void testNativeJsOverlay_lambda() { - assertFalse(isGwtSourceLevel8()); + assertSame("Hello", NativeClassWithJsOverlay.m("Hello")); + } + + interface IntefaceWithDefaultMethodAndLambda { + boolean f(); + + default BooleanPredicate fAsPredicate() { + // This lambda will be defined as an instance method in the enclosing class, which is an + // interface. In this case the methdod will be devirtualized. + return () -> this.f(); + } + } + + interface BooleanPredicate { + boolean apply(); } public void testLambdaCapturingThis_onDefaultMethod() { - assertFalse(isGwtSourceLevel8()); + assertTrue( + new IntefaceWithDefaultMethodAndLambda() { + @Override + public boolean f() { + return true; + } + }.fAsPredicate().apply()); + } + + @JsFunction + interface MyJsFunctionInterface { + int foo(int a); + } + + public void testJsFunction_lambda() { + MyJsFunctionInterface jsFunctionInterface = a -> a + 2; + assertEquals(12, callAsFunction(jsFunctionInterface, 10)); + assertEquals(12, jsFunctionInterface.foo(10)); } + private static native int callAsFunction(Object fn, int arg) /*-{ + return fn(arg); + }-*/; + + @JsFunction + interface MyJsFunctionInterfaceWithOverlay { + Double m(); + @JsOverlay + default Double callM() { + return this.m(); + } + } + + private static native MyJsFunctionInterfaceWithOverlay createNative() /*-{ + return function () { return 5; }; + }-*/; + public void testJsFunction_withOverlay() { - assertFalse(isGwtSourceLevel8()); + MyJsFunctionInterfaceWithOverlay f = new MyJsFunctionInterfaceWithOverlay() { + @Override + public Double m() { + return new Double(2.0); + } + }; + assertEquals(2, f.callM().intValue()); + assertEquals(5, createNative().callM().intValue()); + } + + interface FunctionalExpressionBridges_I { + T apply(T t); + // TODO(rluble): uncomment the line below to when bridges for default methods are created + // in functional expressions + FunctionalExpressionBridges_I m(T t); + } + + @FunctionalInterface + interface FunctionalExpressionBridges_J + extends FunctionalExpressionBridges_I { + T apply(T t); + + // Overrides I.m() and specializes return type + default FunctionalExpressionBridges_J m(T t) { + return this; + } + } + + public static String identity(String s) { + return s; } public void testFunctionalExpressionBridges() { - assertFalse(isGwtSourceLevel8()); + FunctionalExpressionBridges_J ann = new FunctionalExpressionBridges_J() { + @Override + public String apply(String string) { + return string; + } + }; + + assertBrigdeDispatchIsCorrect(ann); + assertBrigdeDispatchIsCorrect((String s) -> s + ""); + assertBrigdeDispatchIsCorrect(Java8Test::identity); + } + + private void assertBrigdeDispatchIsCorrect( + FunctionalExpressionBridges_J functionalExpression) { + assertEquals("Hello", functionalExpression.m(null).apply("Hello")); + assertEquals("Hello", functionalExpression.apply("Hello")); + assertEquals("Hello", + ((FunctionalExpressionBridges_I) functionalExpression).apply("Hello")); + } + + static class ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName { + public static String m() { + return null; + } } + // Regression test for bug: #9426. public void testCorrectNaming() { - assertFalse(isGwtSourceLevel8()); + Function f = ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName::m; + assertNotNull(f); + } + + @JsType(isNative = true) + interface InterfaceWithOverlay { + + @JsProperty + int getLength(); + + @JsOverlay + default int len() { + return this.getLength(); + } + } + + @JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL) + static abstract class SubclassImplementingInterfaceWithOverlay implements InterfaceWithOverlay { } + // Regression test for bug: #9440 public void testInterfaceWithOverlayAndNativeSubclass() { - assertFalse(isGwtSourceLevel8()); + SubclassImplementingInterfaceWithOverlay object = + (SubclassImplementingInterfaceWithOverlay) (Object) new int[]{1, 2, 3}; + assertEquals(3, object.len()); + } + + interface Producer { + T get(); + } + + private static Producer createInnerClassProducer() { + class InnerClass { + } + return (Producer) InnerClass::new; } public void testLocalClassConstructorReferenceInStaticMethod() { - assertFalse(isGwtSourceLevel8()); + assertTrue(createInnerClassProducer().get() != null); + } + + // NOTE: DO NOT reorder the following classes, bug #9453 is only reproducible in certain + // orderings. + interface SubSub_SuperDefaultMethodDevirtualizationOrder + extends Sub_SuperDefaultMethodDevirtualizationOrder { + default String m() { + return Sub_SuperDefaultMethodDevirtualizationOrder.super.m(); + } + } + + interface Sub_SuperDefaultMethodDevirtualizationOrder + extends Super_SuperDefaultMethodDevirtualizationOrder { + @Override + default String m() { + return Super_SuperDefaultMethodDevirtualizationOrder.super.m(); + } + } + + interface Super_SuperDefaultMethodDevirtualizationOrder { + default String m() { + return "Hi"; + } } + // Regression test for bug #9453. public void testDefaultMethodDevirtualizationOrder() { - assertFalse(isGwtSourceLevel8()); + assertEquals("Hi", new SubSub_SuperDefaultMethodDevirtualizationOrder() { + }.m()); } + private static String first(String... strings) { + return strings[0]; + } + + // Regresion test for https://github.com/gwtproject/gwt/issues/9497 public void testVarargsFunctionalConversion() { - assertFalse(isGwtSourceLevel8()); + java.util.function.Function function = Java8Test::first; + assertEquals("Hello", function.apply(new String[] {"Hello", "GoodBye"})); + } + + interface SingleJsoImplA { + String getAData(); + + List getListOfB(); + } + + interface SingleJsoImplB { + String getBData(); + } + + private static final class AOverlay extends JavaScriptObject implements SingleJsoImplA { + protected AOverlay() { } + + @Override + public native String getAData() /*-{ + return this.data; + }-*/; + + @Override + public native List getListOfB() /*-{ + return @java.util.Arrays::asList(*)(this.listOfb); + }-*/; + } + + private static final class BOverlay extends JavaScriptObject implements SingleJsoImplB { + protected BOverlay() { } + + @Override + public native String getBData() /*-{ + return this.data; + }-*/; } + private static SingleJsoImplA createA() { + return JsonUtils.safeEval( + "{\"data\":\"a value\",\"listOfb\":[{\"data\":\"b1\"},{\"data\":\"b2\"}]}"); + } + + // Regression for issue #9558 public void testJSOLivenessSingleImplErasure() { - assertFalse(isGwtSourceLevel8()); + SingleJsoImplA a = createA(); + String result = a.getListOfB().stream() + .map(SingleJsoImplB::getBData).collect(Collectors.joining(",")); + assertEquals("b1,b2", result); + result = a.getListOfB().stream() + .map(b -> b.getBData()).collect(Collectors.joining(",")); + assertEquals("b1,b2", result); } + @SuppressWarnings({"rawtypes", "unchecked"}) public void testLambdaErasureCasts() { - assertFalse(isGwtSourceLevel8()); + List list = new ArrayList(); + list.add("2"); + try { + ((List) list).stream().map(n -> n.intValue() == 2).findAny(); + fail("Should have thrown."); + } catch (ClassCastException expected) { + } } public void testLambdaBoxing() { - assertFalse(isGwtSourceLevel8()); + BiFunction equals = (i, j) -> i + 0 == j; + assertTrue(equals.apply(1,1)); + assertTrue(equals.apply(new Integer(2),2)); + assertTrue(equals.apply(new Integer(3), new Integer(3))); + + IntFunction unboxBox = i -> i; + assertEquals(2, (int) unboxBox.apply(2)); + assertEquals(2, (int) unboxBox.apply(new Integer(2))); } + // Regression tests for #9598 public void testImproperMethodResolution() { - assertFalse(isGwtSourceLevel8()); + Predicate p = o -> true; + assertTrue(p.test(null)); } + interface I2 { T foo(T arg); } + + interface I1 extends I2 { String foo(String arg0); } + + @SuppressWarnings({"rawtypes", "unchecked"}) public void testIntersectionCastLambda() { - assertFalse(isGwtSourceLevel8()); + + Object instance = (I1 & I2) val -> "#" + val; + + assertTrue(instance instanceof I1); + assertTrue(instance instanceof I2); + + I1 lambda = (I1) instance; + I2 raw = lambda; + assertEquals("#1", raw.foo("1")); // tests that the bridge exists and is correct + assertEquals("#2", lambda.foo("2")); } - public void testIntersectionCastMethodReference() { - assertFalse(isGwtSourceLevel8()); + static class C2 { + public static String append(String str) { + return "#" + str; + } } + @SuppressWarnings({"rawtypes", "unchecked"}) + public void testIntersectionCastMethodReference() { + + Object instance = (I1 & I2) C2::append; + + assertTrue(instance instanceof I1); + assertTrue(instance instanceof I2); - private boolean isGwtSourceLevel8() { - return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA8) >= 0; + I1 lambda = (I1) instance; + I2 raw = lambda; + assertEquals("#1", raw.foo("1")); // tests that the bridge exists and is correct + assertEquals("#2", lambda.foo("2")); } } diff --git a/user/test/com/google/gwt/dev/jjs/test/Java9Test.java b/user/test/com/google/gwt/dev/jjs/test/Java9Test.java index 951c8bbcaa0..03662b4cb86 100644 --- a/user/test/com/google/gwt/dev/jjs/test/Java9Test.java +++ b/user/test/com/google/gwt/dev/jjs/test/Java9Test.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Google Inc. + * Copyright 2023 GWT Project Authors * * 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 @@ -15,45 +15,89 @@ */ package com.google.gwt.dev.jjs.test; -import com.google.gwt.dev.util.arg.SourceLevel; import com.google.gwt.junit.DoNotRunWith; -import com.google.gwt.junit.JUnitShell; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; +import java.util.function.Predicate; +import java.util.function.Supplier; + /** - * Dummy test case. Java9Test is super sourced so that GWT can be compiled by Java 8. - * - * NOTE: Make sure this class has the same test methods of its supersourced variant. + * Test Java 9 features. */ @DoNotRunWith(Platform.Devel) public class Java9Test extends GWTTestCase { + @Override public String getModuleName() { return "com.google.gwt.dev.jjs.Java9Test"; } - @Override - public void runTest() throws Throwable { - // Only run these tests if -sourceLevel 9 (or greater) is enabled. - if (isGwtSourceLevel9()) { - super.runTest(); + class Resource implements AutoCloseable { + boolean isOpen = true; + + public void close() { + this.isOpen = false; } } public void testTryWithResourcesJava9() { - assertFalse(isGwtSourceLevel9()); + Resource r1 = new Resource(); + assertTrue(r1.isOpen); + Resource r2Copy; + try (r1; Resource r2 = new Resource()) { + assertTrue(r1.isOpen); + assertTrue(r2.isOpen); + r2Copy = r2; + } + assertFalse(r1.isOpen); + assertFalse(r2Copy.isOpen); } - public void testInterfacePrivateMethodsJava9() { - assertFalse(isGwtSourceLevel9()); + interface Selector extends Predicate { + @Override + boolean test(String object); + + default Selector trueSelector() { + // Unused variable that creates a lambda with a bridge for the method test. The bug #9598 + // was caused by GwtAstBuilder associating the bridge method Lambda.test(Object) on the + // lambda below to the method Predicate.test(Object), causing the method resolution in the + // code that refers to the Predicate.test(Object) in the test below to refer to + // Lambda.test(Object) which is the wrong method. + return receiver -> true; + } } - public void testAnonymousDiamondJava9() { - assertFalse(isGwtSourceLevel9()); + private interface InterfaceWithPrivateMethods { + int implementedMethod(); + + default int defaultMethod() { + return privateMethod(); + } + + private int privateMethod() { + return implementedMethod(); + } + + private int staticPrivateMethod() { + return 42; + } } - private boolean isGwtSourceLevel9() { - return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA9) >= 0; + public void testInterfacePrivateMethodsJava9() { + InterfaceWithPrivateMethods implementor = () -> 50; + assertEquals(50, implementor.implementedMethod()); + assertEquals(50, implementor.defaultMethod()); + assertEquals(42, implementor.staticPrivateMethod()); + } + + public void testAnonymousDiamondJava9() { + Supplier helloSupplier = new Supplier<>() { + @Override + public String get() { + return "hello"; + } + }; + assertEquals("hello", helloSupplier.get()); } -} +} \ No newline at end of file diff --git a/user/test/com/google/gwt/dev/jjs/test/JsoTest.java b/user/test/com/google/gwt/dev/jjs/test/JsoTest.java index e9f3f5f00cb..93a6699331a 100644 --- a/user/test/com/google/gwt/dev/jjs/test/JsoTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/JsoTest.java @@ -639,6 +639,7 @@ public int hashCode() { assertEquals(stringHashCode, o.hashCode()); } + @SuppressWarnings("JUnitAssertSameCheck") public void testIdentity() { JavaScriptObject jso = makeJSO(); assertSame(jso, jso); diff --git a/user/test/com/google/gwt/dev/jjs/test/MethodCallTest.java b/user/test/com/google/gwt/dev/jjs/test/MethodCallTest.java index bdfed103f53..78c27e3b9ab 100644 --- a/user/test/com/google/gwt/dev/jjs/test/MethodCallTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/MethodCallTest.java @@ -27,6 +27,7 @@ private static final class MyException extends RuntimeException { private static Object field; + @SuppressWarnings("ReturnValueIgnored") private static void clobberFieldNoInline() { try { field = null; @@ -102,6 +103,7 @@ private static int manyArgs(int i0, int i1, int i2, int i3, int i4, int i5, * o will have been replaced by a direct reference to * {@link #field}. Both the Java and JS inliners must not inline this. */ + @SuppressWarnings("ReturnValueIgnored") private static void shouldNotInline(Object o) { field = null; o.toString(); @@ -111,6 +113,7 @@ private static void shouldNotInline(Object o) { * Same as {@link #shouldNotInline(Object)}, except the field clobber is done * indirectly in a non-inlinable method. */ + @SuppressWarnings("ReturnValueIgnored") private static void shouldNotInline2(Object o) { clobberFieldNoInline(); o.toString(); diff --git a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java index 5835a144b7c..e0ea32e2bac 100644 --- a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java @@ -58,6 +58,7 @@ public static int sfoo() { private static native void clinitInNative() /*-{ }-*/; + @SuppressWarnings("ReturnValueIgnored") private int foo() { this.toString(); return 3; @@ -216,7 +217,7 @@ public void testAssociativityCond() { assertEquals(100, result); } - @SuppressWarnings("cast") + @SuppressWarnings({"cast", "SelfAssignment"}) public void testCasts() { Object o = FALSE ? (Object) new PolyA() : (Object) new PolyB(); assertTrue(o instanceof I); diff --git a/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java b/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java index 9b28f6fc81c..9e0a4d36e48 100644 --- a/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java @@ -162,6 +162,7 @@ public void testLogicalOr() { assertEquals(3L, LONG_ONE | LONG_THREE); } + @SuppressWarnings("IdentityBinaryExpression") public void testLogicalXor() { assertTrue((255L ^ LONG_5DEECE66D) != 0); diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java b/user/test/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java rename to user/test/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java b/user/test/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java rename to user/test/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java b/user/test/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java rename to user/test/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package1/SimpleA.java b/user/test/com/google/gwt/dev/jjs/test/package1/SimpleA.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package1/SimpleA.java rename to user/test/com/google/gwt/dev/jjs/test/package1/SimpleA.java diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package1/SimpleD.java b/user/test/com/google/gwt/dev/jjs/test/package1/SimpleD.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package1/SimpleD.java rename to user/test/com/google/gwt/dev/jjs/test/package1/SimpleD.java diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package2/SimpleB.java b/user/test/com/google/gwt/dev/jjs/test/package2/SimpleB.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package2/SimpleB.java rename to user/test/com/google/gwt/dev/jjs/test/package2/SimpleB.java diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package3/SimpleC.java b/user/test/com/google/gwt/dev/jjs/test/package3/SimpleC.java similarity index 100% rename from user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/package3/SimpleC.java rename to user/test/com/google/gwt/dev/jjs/test/package3/SimpleC.java diff --git a/user/test/com/google/gwt/dev/js/client/CoverageTest.java b/user/test/com/google/gwt/dev/js/client/CoverageTest.java index 52f5c15efa3..54bb33d84d8 100644 --- a/user/test/com/google/gwt/dev/js/client/CoverageTest.java +++ b/user/test/com/google/gwt/dev/js/client/CoverageTest.java @@ -28,6 +28,7 @@ * Tests coverage instrumentation. */ public class CoverageTest extends GWTTestCase { + @SuppressWarnings("DoubleBraceInitialization") private static final Map EXPECTED_COVERAGE = new HashMap() { { put("25", 1.0); put("26", 1.0); diff --git a/user/test/com/google/gwt/dev/strict/bad/client/BadSource.java b/user/test/com/google/gwt/dev/strict/bad/client/BadSource.java index daa2153f591..7c30f12a1aa 100644 --- a/user/test/com/google/gwt/dev/strict/bad/client/BadSource.java +++ b/user/test/com/google/gwt/dev/strict/bad/client/BadSource.java @@ -19,6 +19,7 @@ * Used by {@link com.google.gwt.dev.StrictModeTest}. */ public class BadSource { + @SuppressWarnings("DeadThread") public void useThread() { new Thread(); } diff --git a/user/test/com/google/gwt/dom/client/ElementTest.java b/user/test/com/google/gwt/dom/client/ElementTest.java index 0b4fafa40cb..717448b7a9b 100644 --- a/user/test/com/google/gwt/dom/client/ElementTest.java +++ b/user/test/com/google/gwt/dom/client/ElementTest.java @@ -184,6 +184,7 @@ public void testElementAttribute() { * not return a numeric attribute based on the element property. See issue * 3238. */ + @SuppressWarnings("ReturnValueIgnored") public void testElementAttributeNumeric() { DivElement div = Document.get().createDivElement(); Document.get().getBody().appendChild(div); diff --git a/user/test/com/google/gwt/emultest/CollectionsSuite.java b/user/test/com/google/gwt/emultest/CollectionsSuite.java index a273ee038b8..24821cf12c0 100644 --- a/user/test/com/google/gwt/emultest/CollectionsSuite.java +++ b/user/test/com/google/gwt/emultest/CollectionsSuite.java @@ -40,6 +40,7 @@ import com.google.gwt.emultest.java.util.TreeSetIntegerTest; import com.google.gwt.emultest.java.util.TreeSetIntegerWithComparatorTest; import com.google.gwt.emultest.java.util.VectorTest; + import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; diff --git a/user/test/com/google/gwt/emultest/EmulJava10Suite.java b/user/test/com/google/gwt/emultest/EmulJava10Suite.java index e691477626a..06881ab9b80 100644 --- a/user/test/com/google/gwt/emultest/EmulJava10Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava10Suite.java @@ -15,10 +15,15 @@ */ package com.google.gwt.emultest; +import com.google.gwt.emultest.java10.util.ListTest; +import com.google.gwt.emultest.java10.util.MapTest; import com.google.gwt.emultest.java10.util.OptionalDoubleTest; import com.google.gwt.emultest.java10.util.OptionalIntTest; import com.google.gwt.emultest.java10.util.OptionalLongTest; import com.google.gwt.emultest.java10.util.OptionalTest; +import com.google.gwt.emultest.java10.util.SetTest; +import com.google.gwt.emultest.java10.util.stream.CollectorsTest; + import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @@ -26,10 +31,14 @@ /** Test JRE emulations. */ @RunWith(Suite.class) @SuiteClasses({ + CollectorsTest.class, + ListTest.class, + MapTest.class, OptionalDoubleTest.class, OptionalIntTest.class, OptionalLongTest.class, OptionalTest.class, + SetTest.class, }) public class EmulJava10Suite { } diff --git a/user/test/com/google/gwt/emultest/EmulJava11Suite.java b/user/test/com/google/gwt/emultest/EmulJava11Suite.java index 5e2ad3ab17e..01b44205b85 100644 --- a/user/test/com/google/gwt/emultest/EmulJava11Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava11Suite.java @@ -20,6 +20,7 @@ import com.google.gwt.emultest.java11.util.OptionalLongTest; import com.google.gwt.emultest.java11.util.OptionalTest; import com.google.gwt.emultest.java11.util.function.PredicateTest; + import org.junit.runner.RunWith; import org.junit.runners.Suite; diff --git a/user/test/com/google/gwt/emultest/EmulJava9Suite.java b/user/test/com/google/gwt/emultest/EmulJava9Suite.java index b2f81570e34..0a28abdf889 100644 --- a/user/test/com/google/gwt/emultest/EmulJava9Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava9Suite.java @@ -15,11 +15,6 @@ */ package com.google.gwt.emultest; -import com.google.gwt.emultest.java9.util.stream.CollectorsTest; -import com.google.gwt.emultest.java9.util.stream.DoubleStreamTest; -import com.google.gwt.emultest.java9.util.stream.IntStreamTest; -import com.google.gwt.emultest.java9.util.stream.LongStreamTest; -import com.google.gwt.emultest.java9.util.stream.StreamTest; import com.google.gwt.emultest.java9.util.ListTest; import com.google.gwt.emultest.java9.util.MapTest; import com.google.gwt.emultest.java9.util.OptionalDoubleTest; @@ -27,6 +22,12 @@ import com.google.gwt.emultest.java9.util.OptionalLongTest; import com.google.gwt.emultest.java9.util.OptionalTest; import com.google.gwt.emultest.java9.util.SetTest; +import com.google.gwt.emultest.java9.util.stream.CollectorsTest; +import com.google.gwt.emultest.java9.util.stream.DoubleStreamTest; +import com.google.gwt.emultest.java9.util.stream.IntStreamTest; +import com.google.gwt.emultest.java9.util.stream.LongStreamTest; +import com.google.gwt.emultest.java9.util.stream.StreamTest; + import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; diff --git a/user/test/com/google/gwt/emultest/EmulSuite.java b/user/test/com/google/gwt/emultest/EmulSuite.java index f6de1407b78..a8deb3049cb 100644 --- a/user/test/com/google/gwt/emultest/EmulSuite.java +++ b/user/test/com/google/gwt/emultest/EmulSuite.java @@ -62,6 +62,7 @@ import com.google.gwt.emultest.java.util.DateTest; import com.google.gwt.emultest.java.util.ObjectsTest; import com.google.gwt.emultest.java.util.RandomTest; + import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; diff --git a/user/test/com/google/gwt/emultest/java/internal/CoercionsTest.java b/user/test/com/google/gwt/emultest/java/internal/CoercionsTest.java index 20b252f6e74..9e07ac28866 100644 --- a/user/test/com/google/gwt/emultest/java/internal/CoercionsTest.java +++ b/user/test/com/google/gwt/emultest/java/internal/CoercionsTest.java @@ -18,7 +18,6 @@ import com.google.gwt.junit.client.GWTTestCase; import java.util.Random; - import javaemul.internal.Coercions; /** diff --git a/user/test/com/google/gwt/emultest/java/io/BufferedWriterTest.java b/user/test/com/google/gwt/emultest/java/io/BufferedWriterTest.java index 38b9a28abbe..6f0626c52f3 100644 --- a/user/test/com/google/gwt/emultest/java/io/BufferedWriterTest.java +++ b/user/test/com/google/gwt/emultest/java/io/BufferedWriterTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.io; import com.google.gwt.junit.client.GWTTestCase; + import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; diff --git a/user/test/com/google/gwt/emultest/java/io/OutputStreamWriterTest.java b/user/test/com/google/gwt/emultest/java/io/OutputStreamWriterTest.java index a9b9e25d3b2..5e1a9761bb8 100644 --- a/user/test/com/google/gwt/emultest/java/io/OutputStreamWriterTest.java +++ b/user/test/com/google/gwt/emultest/java/io/OutputStreamWriterTest.java @@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import com.google.gwt.junit.client.GWTTestCase; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; diff --git a/user/test/com/google/gwt/emultest/java/io/PrintStreamTest.java b/user/test/com/google/gwt/emultest/java/io/PrintStreamTest.java index a0dabfe530d..bdfeb4921cb 100644 --- a/user/test/com/google/gwt/emultest/java/io/PrintStreamTest.java +++ b/user/test/com/google/gwt/emultest/java/io/PrintStreamTest.java @@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import com.google.gwt.junit.client.GWTTestCase; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/user/test/com/google/gwt/emultest/java/lang/CharacterTest.java b/user/test/com/google/gwt/emultest/java/lang/CharacterTest.java index 426e81744e3..41c6f247ec4 100644 --- a/user/test/com/google/gwt/emultest/java/lang/CharacterTest.java +++ b/user/test/com/google/gwt/emultest/java/lang/CharacterTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.lang; import com.google.gwt.junit.client.GWTTestCase; + import java.util.Arrays; /** diff --git a/user/test/com/google/gwt/emultest/java/lang/JsExceptionTest.java b/user/test/com/google/gwt/emultest/java/lang/JsExceptionTest.java index 0daaac207ee..503d3ecd153 100644 --- a/user/test/com/google/gwt/emultest/java/lang/JsExceptionTest.java +++ b/user/test/com/google/gwt/emultest/java/lang/JsExceptionTest.java @@ -14,6 +14,7 @@ package com.google.gwt.emultest.java.lang; import com.google.gwt.testing.TestUtils; + import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; @@ -120,6 +121,7 @@ public void testTypeError() { } } + @SuppressWarnings("ReturnValueIgnored") private static void throwTypeError() { Object nullObject = null; nullObject.getClass(); diff --git a/user/test/com/google/gwt/emultest/java/lang/StringTest.java b/user/test/com/google/gwt/emultest/java/lang/StringTest.java index 59fe575011c..4b08a45eeea 100644 --- a/user/test/com/google/gwt/emultest/java/lang/StringTest.java +++ b/user/test/com/google/gwt/emultest/java/lang/StringTest.java @@ -18,6 +18,7 @@ import com.google.gwt.core.client.JavaScriptException; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.testing.TestUtils; + import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Arrays; @@ -651,6 +652,7 @@ public void testNull() { } } + @SuppressWarnings("ReturnValueIgnored") public void testRegionMatches() { String test = String.valueOf(new char[] {'a', 'b', 'c', 'd', 'e', 'f'}); assertTrue(test.regionMatches(1, "bcd", 0, 3)); diff --git a/user/test/com/google/gwt/emultest/java/lang/ThrowableTest.java b/user/test/com/google/gwt/emultest/java/lang/ThrowableTest.java index f1f369321b5..a30ea5466dc 100644 --- a/user/test/com/google/gwt/emultest/java/lang/ThrowableTest.java +++ b/user/test/com/google/gwt/emultest/java/lang/ThrowableTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.lang; import com.google.gwt.testing.TestUtils; + import java.io.IOException; import jsinterop.annotations.JsType; diff --git a/user/test/com/google/gwt/emultest/java/lang/ThrowableTestBase.java b/user/test/com/google/gwt/emultest/java/lang/ThrowableTestBase.java index 0397350f9bb..4b2324299db 100644 --- a/user/test/com/google/gwt/emultest/java/lang/ThrowableTestBase.java +++ b/user/test/com/google/gwt/emultest/java/lang/ThrowableTestBase.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.lang; import com.google.gwt.junit.client.GWTTestCase; + import jsinterop.annotations.JsFunction; import jsinterop.annotations.JsMethod; import jsinterop.annotations.JsPackage; diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java index c3992e527ee..a32f0d24c86 100644 --- a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java +++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java @@ -38,6 +38,7 @@ package com.google.gwt.emultest.java.math; import com.google.gwt.emultest.java.util.EmulTestBase; + import java.math.BigInteger; import java.util.Random; diff --git a/user/test/com/google/gwt/emultest/java/nio/charset/CharsetTest.java b/user/test/com/google/gwt/emultest/java/nio/charset/CharsetTest.java index 8811f06da4a..2b9c274e6d3 100644 --- a/user/test/com/google/gwt/emultest/java/nio/charset/CharsetTest.java +++ b/user/test/com/google/gwt/emultest/java/nio/charset/CharsetTest.java @@ -17,6 +17,7 @@ package com.google.gwt.emultest.java.nio.charset; import com.google.gwt.emultest.java.util.EmulTestBase; + import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; diff --git a/user/test/com/google/gwt/emultest/java/sql/SqlDateTest.java b/user/test/com/google/gwt/emultest/java/sql/SqlDateTest.java index f6a344bdef4..48003358d03 100644 --- a/user/test/com/google/gwt/emultest/java/sql/SqlDateTest.java +++ b/user/test/com/google/gwt/emultest/java/sql/SqlDateTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.sql; import com.google.gwt.junit.client.GWTTestCase; + import java.sql.Date; /** diff --git a/user/test/com/google/gwt/emultest/java/util/ArrayDequeTest.java b/user/test/com/google/gwt/emultest/java/util/ArrayDequeTest.java index be4db76ed36..4f939bf1e1c 100644 --- a/user/test/com/google/gwt/emultest/java/util/ArrayDequeTest.java +++ b/user/test/com/google/gwt/emultest/java/util/ArrayDequeTest.java @@ -19,6 +19,7 @@ import com.google.gwt.core.client.JavaScriptException; import com.google.gwt.testing.TestUtils; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; diff --git a/user/test/com/google/gwt/emultest/java/util/ArraysDoubleSemanticsTest.java b/user/test/com/google/gwt/emultest/java/util/ArraysDoubleSemanticsTest.java index 42d9b2fd976..6b83c1129ce 100644 --- a/user/test/com/google/gwt/emultest/java/util/ArraysDoubleSemanticsTest.java +++ b/user/test/com/google/gwt/emultest/java/util/ArraysDoubleSemanticsTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.Arrays; /** Tests {@link Arrays} (incorrect) Double semantics. */ diff --git a/user/test/com/google/gwt/emultest/java/util/ArraysFloatSemanticsTest.java b/user/test/com/google/gwt/emultest/java/util/ArraysFloatSemanticsTest.java index 2c38e2a284f..be30d20670f 100644 --- a/user/test/com/google/gwt/emultest/java/util/ArraysFloatSemanticsTest.java +++ b/user/test/com/google/gwt/emultest/java/util/ArraysFloatSemanticsTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.Arrays; /** Tests {@link Arrays} (incorrect) Float semantics. */ diff --git a/user/test/com/google/gwt/emultest/java/util/ArraysTest.java b/user/test/com/google/gwt/emultest/java/util/ArraysTest.java index bed413c995a..b62440314fc 100644 --- a/user/test/com/google/gwt/emultest/java/util/ArraysTest.java +++ b/user/test/com/google/gwt/emultest/java/util/ArraysTest.java @@ -67,6 +67,7 @@ public String getModuleName() { * embedded null references works properly (and most importantly doesn't * throw an NPE). */ + @SuppressWarnings("ReturnValueIgnored") public void testArraysHashCodeWithNullElements() { String[] a = new String[] { "foo", null, "bar", "baz" }; Arrays.hashCode(a); diff --git a/user/test/com/google/gwt/emultest/java/util/DateTest.java b/user/test/com/google/gwt/emultest/java/util/DateTest.java index e987c2ce118..452e1f53f94 100644 --- a/user/test/com/google/gwt/emultest/java/util/DateTest.java +++ b/user/test/com/google/gwt/emultest/java/util/DateTest.java @@ -17,6 +17,7 @@ import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.testing.TestUtils; + import java.util.ArrayList; import java.util.Date; diff --git a/user/test/com/google/gwt/emultest/java/util/IdentityHashMapTest.java b/user/test/com/google/gwt/emultest/java/util/IdentityHashMapTest.java index d4957bb9064..c0d1299d2c3 100644 --- a/user/test/com/google/gwt/emultest/java/util/IdentityHashMapTest.java +++ b/user/test/com/google/gwt/emultest/java/util/IdentityHashMapTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.Collection; import java.util.HashMap; import java.util.IdentityHashMap; diff --git a/user/test/com/google/gwt/emultest/java/util/LinkedHashMapTest.java b/user/test/com/google/gwt/emultest/java/util/LinkedHashMapTest.java index e6a11a2d1f4..80594bca676 100644 --- a/user/test/com/google/gwt/emultest/java/util/LinkedHashMapTest.java +++ b/user/test/com/google/gwt/emultest/java/util/LinkedHashMapTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; diff --git a/user/test/com/google/gwt/emultest/java/util/ObjectsTest.java b/user/test/com/google/gwt/emultest/java/util/ObjectsTest.java index 6ad573a3aed..ad89d1dc65f 100644 --- a/user/test/com/google/gwt/emultest/java/util/ObjectsTest.java +++ b/user/test/com/google/gwt/emultest/java/util/ObjectsTest.java @@ -32,7 +32,7 @@ public String getModuleName() { public void testCompare() { Comparator intComparator = new Comparator() { - @SuppressWarnings("NumberEquality") + @SuppressWarnings({"NumberEquality", "BoxedPrimitiveEquality"}) @Override public int compare(Integer a, Integer b) { if (a == b) { diff --git a/user/test/com/google/gwt/emultest/java/util/TestCollection.java b/user/test/com/google/gwt/emultest/java/util/TestCollection.java index 5fbf556a57f..611f5d95eab 100644 --- a/user/test/com/google/gwt/emultest/java/util/TestCollection.java +++ b/user/test/com/google/gwt/emultest/java/util/TestCollection.java @@ -598,6 +598,7 @@ public void testCollectionIterator() { } /** Tests removals from {@link Collection#iterator()}. */ + @SuppressWarnings("ReturnValueIgnored") public void testCollectionIteratorRemove() { if (!isRemoveSupported()) { return; diff --git a/user/test/com/google/gwt/emultest/java/util/TestMap.java b/user/test/com/google/gwt/emultest/java/util/TestMap.java index bded4581776..b38929e826a 100644 --- a/user/test/com/google/gwt/emultest/java/util/TestMap.java +++ b/user/test/com/google/gwt/emultest/java/util/TestMap.java @@ -18,6 +18,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.Arrays; import java.util.Collection; import java.util.ConcurrentModificationException; diff --git a/user/test/com/google/gwt/emultest/java/util/TestObject.java b/user/test/com/google/gwt/emultest/java/util/TestObject.java index 20d9c42c99d..63ce3e42a59 100644 --- a/user/test/com/google/gwt/emultest/java/util/TestObject.java +++ b/user/test/com/google/gwt/emultest/java/util/TestObject.java @@ -57,6 +57,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/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java b/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java index df8b3974038..372a24887ce 100644 --- a/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java +++ b/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; @@ -41,6 +42,7 @@ */ abstract class TreeMapTest, V> extends TestMap { + @SuppressWarnings("ComparableType") private static class ConflictingKey implements Comparable { private final String value; @@ -488,6 +490,7 @@ public void testContainsKey_ComparableKey() { * * @see java.util.Map#containsKey(Object) */ + @SuppressWarnings("ReturnValueIgnored") public void testContainsKey_throwsClassCastException() { K[] keys = getKeys(); V[] values = getValues(); @@ -549,6 +552,7 @@ public void testContainsValue() { * * @see java.util.Map#containsValue(Object) */ + @SuppressWarnings("ReturnValueIgnored") public void testContainsValue_throwsClassCastException() { K[] keys = getKeys(); V[] values = getValues(); @@ -759,6 +763,7 @@ public V setValue(V value) { } } + @SuppressWarnings("ReturnValueIgnored") public void testEntrySet() { K[] keys = getSortedKeys(); V[] values = getSortedValues(); @@ -2155,6 +2160,7 @@ public void testPut_entries3() { * * @see java.util.Map#put(Object, Object) */ + @SuppressWarnings("ReturnValueIgnored") public void testPut_nullKey() { K[] keys = getSortedKeys(); V[] values = getSortedValues(); @@ -2874,6 +2880,7 @@ public void testSubMap_empty() { assertTrue(subMap.values().isEmpty()); } + @SuppressWarnings("ReturnValueIgnored") public void testSubMap_entrySet() { K[] keys = getSortedKeys(); V[] values = getSortedValues(); @@ -3311,6 +3318,7 @@ public void testToString() { * * @see java.util.Map#values() */ + @SuppressWarnings("ReturnValueIgnored") public void testValues() { K[] keys = getSortedKeys(); V[] values = getSortedValues(); diff --git a/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java b/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java index 4b5ab8cd037..b9cd81d12ae 100644 --- a/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java +++ b/user/test/com/google/gwt/emultest/java/util/TreeSetTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java.util; import com.google.gwt.testing.TestUtils; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -588,6 +589,7 @@ public void testContains() { * * @see java.util.Set#contains(Object) */ + @SuppressWarnings("ReturnValueIgnored") public void testContains_throwsClassCastException() { Set set = createSet(); set.add(getKeys()[0]); diff --git a/user/test/com/google/gwt/emultest/java10/util/ListTest.java b/user/test/com/google/gwt/emultest/java10/util/ListTest.java new file mode 100644 index 00000000000..4fcb3f5ecd2 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/ListTest.java @@ -0,0 +1,57 @@ +/* + * 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.emultest.java10.util; + +import static com.google.gwt.emultest.java9.util.ListTest.assertIsImmutableListOf; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tests for java.util.List Java 10 API emulation. + */ +public class ListTest extends EmulTestBase { + public void testCopyOf() { + assertIsImmutableListOf(List.copyOf(List.of("a", "b")), "a", "b"); + assertIsImmutableListOf(List.copyOf(Arrays.asList("a", "b")), "a", "b"); + + ArrayList arrayList = new ArrayList<>(); + arrayList.add("a"); + arrayList.add("b"); + List copy = List.copyOf(arrayList); + assertIsImmutableListOf(copy, "a", "b"); + + // verify that mutating the original doesn't affect the copy + arrayList.add("c"); + assertEquals(2, copy.size()); + assertFalse(copy.contains("c")); + + arrayList.remove(0); + assertEquals(2, copy.size()); + assertTrue(copy.contains("a")); + + // ensure that null values in the collection result in a NPE + try { + List.copyOf(Arrays.asList("a", null)); + fail("Expected NullPointerException passing copy a collection with a null value"); + } catch (NullPointerException ignore) { + // expected + } + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/MapTest.java b/user/test/com/google/gwt/emultest/java10/util/MapTest.java new file mode 100644 index 00000000000..0d09a2d7bc4 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/MapTest.java @@ -0,0 +1,64 @@ +/* + * 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.emultest.java10.util; + +import static com.google.gwt.emultest.java9.util.MapTest.assertIsImmutableMapOf; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.HashMap; +import java.util.Map; + +/** + * Tests for java.util.Map Java 10 API emulation. + */ +public class MapTest extends EmulTestBase { + public void testCopyOf() { + assertIsImmutableMapOf(Map.copyOf(Map.of("a", 1)), "a"); + + HashMap hashMap = new HashMap<>(); + hashMap.put("a", 1); + Map copy = Map.copyOf(hashMap); + assertIsImmutableMapOf(copy, "a"); + + // verify that mutating the original has no effect on the copy + hashMap.put("b", 2); + assertFalse(copy.containsKey("b")); + assertEquals(1, copy.size()); + + hashMap.put("a", 5); + assertEquals(1, (int) copy.get("a")); + + // ensure that null values result in a NPE + HashMap mapWithNullKey = new HashMap<>(); + mapWithNullKey.put(null, 1); + try { + Map.copyOf(mapWithNullKey); + fail("expected NullPointerException from copyOf with a null key"); + } catch (NullPointerException ignored) { + // expected + } + + HashMap mapWithNullValue = new HashMap<>(); + mapWithNullValue.put("key", null); + try { + Map.copyOf(mapWithNullValue); + fail("expected NullPointerException from copyOf with a null value"); + } catch (NullPointerException ignored) { + // expected + } + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/SetTest.java b/user/test/com/google/gwt/emultest/java10/util/SetTest.java new file mode 100644 index 00000000000..17e37618b1d --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/SetTest.java @@ -0,0 +1,60 @@ +/* + * 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.emultest.java10.util; + +import static com.google.gwt.emultest.java9.util.SetTest.assertIsImmutableSetOf; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Tests for java.util.Set Java 10 API emulation. + */ +public class SetTest extends EmulTestBase { + public void testCopyOf() { + assertIsImmutableSetOf(Set.copyOf(Set.of("a", "b")), "a", "b"); + assertIsImmutableSetOf(Set.copyOf(Arrays.asList("a", "b")), "a", "b"); + + HashSet hashSet = new HashSet<>(); + hashSet.add("a"); + hashSet.add("b"); + Set copy = Set.copyOf(hashSet); + assertIsImmutableSetOf(copy, "a", "b"); + + // verify that mutating the original has no effect on the copy + hashSet.add("c"); + assertEquals(2, copy.size()); + assertFalse(copy.contains("c")); + + hashSet.remove("a"); + assertEquals(2, copy.size()); + assertTrue(copy.contains("a")); + + // ensure that null value result in a NPE + try { + Set.copyOf(Arrays.asList("a", null)); + fail("Expected NullPointerException from null item in collection passed to copyOf"); + } catch (NullPointerException ignored) { + // expected + } + + // ensure that duplicate values result in smaller output + assertIsImmutableSetOf(Set.copyOf(Arrays.asList("a", "a")), "a"); + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/stream/CollectorsTest.java b/user/test/com/google/gwt/emultest/java10/util/stream/CollectorsTest.java new file mode 100644 index 00000000000..ecf6654f19f --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/stream/CollectorsTest.java @@ -0,0 +1,162 @@ +/* + * 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.emultest.java10.util.stream; + +import static com.google.gwt.emultest.java8.util.stream.CollectorsTest.applyItems; +import static java.util.stream.Collectors.toUnmodifiableList; +import static java.util.stream.Collectors.toUnmodifiableMap; +import static java.util.stream.Collectors.toUnmodifiableSet; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Tests for java.util.stream.Collectors Java 10 API emulation. + */ +public class CollectorsTest extends EmulTestBase { + private static boolean unmodifiableCollection(Collection c, T existingSample, T newSample) { + try { + c.remove(existingSample); + return false; + } catch (UnsupportedOperationException ignore) { + // expected + } + try { + c.add(newSample); + return false; + } catch (UnsupportedOperationException ignore) { + // expected + } + Iterator itr = c.iterator(); + itr.next(); + try { + itr.remove(); + return false; + } catch (UnsupportedOperationException e) { + // expected + } + return true; + } + + public void testToUnmodifiableList() { + applyItems(List.of("a", "b"), toUnmodifiableList(), "a", "b", (expected, actual) -> { + if (!expected.equals(actual)) { + return false; + } + + if (!unmodifiableCollection(actual, "a", "z")) { + return false; + } + + return true; + }); + + // verify nulls fail + try { + Stream.of("a").map(ignore -> null).collect(toUnmodifiableList()); + fail("Expected NPE"); + } catch (NullPointerException ignore) { + // expected + } + } + + public void testToUnmodifiableMap() { + // verify simple cases copy all values and results are unmodifiable + applyItems(Map.of("a", 0, "b", 1), toUnmodifiableMap(Function.identity(), + k -> k.charAt(0) - 'a'), "a", "b", (expected, actual) -> { + if (!expected.equals(actual)) { + return false; + } + + if (!unmodifiableMap(actual, "a", 0, "z", 100)) { + return false; + } + + return true; + }); + + // verify merge works with only one key (but this is just passing through to the toMap func + // anyway...) + applyItems(Map.of("a", 2), toUnmodifiableMap(Function.identity(), ignore -> 1, Integer::sum), + "a", "a"); + + // verify nulls blow up for both keys and values + try { + Stream.of("a").collect(toUnmodifiableMap(obj -> null, Function.identity())); + fail("Expected NPE"); + } catch (NullPointerException ignore) { + // expected + } + try { + Stream.of("a").collect(toUnmodifiableMap(Function.identity(), obj -> null)); + fail("Expected NPE"); + } catch (Exception ignore) { + // expected + } + } + + private boolean unmodifiableMap(Map a, K existingKey, V existingValue, K newKey, + V newValue) { + if (!unmodifiableCollection(a.keySet(), existingKey, newKey)) { + return false; + } + if (!unmodifiableCollection(a.values(), existingValue, newValue)) { + return false; + } + + try { + a.put(newKey, newValue); + return false; + } catch (Exception ignore) { + // expected + } + try { + a.remove(existingKey); + return false; + } catch (Exception ignore) { + // expected + } + + return true; + } + + public void testToUnmodifiableSet() { + applyItems(Set.of("a", "b"), toUnmodifiableSet(), "a", "b", (expected, actual) -> { + if (!expected.equals(actual)) { + return false; + } + if (!unmodifiableCollection(actual, "a", "z")) { + return false; + } + return true; + }); + + // verify nulls fail + try { + Stream.of("a").map(ignore -> null).collect(toUnmodifiableSet()); + fail("Expected NPE"); + } catch (NullPointerException ignore) { + // expected + } + } +} diff --git a/user/test/com/google/gwt/emultest/java11/util/function/PredicateTest.java b/user/test/com/google/gwt/emultest/java11/util/function/PredicateTest.java index e2bf74df739..271a00bb634 100644 --- a/user/test/com/google/gwt/emultest/java11/util/function/PredicateTest.java +++ b/user/test/com/google/gwt/emultest/java11/util/function/PredicateTest.java @@ -16,6 +16,7 @@ package com.google.gwt.emultest.java11.util.function; import com.google.gwt.emultest.java.util.EmulTestBase; + import java.util.function.Predicate; /** diff --git a/user/test/com/google/gwt/emultest/java8/util/DoubleSummaryStatisticsTest.java b/user/test/com/google/gwt/emultest/java8/util/DoubleSummaryStatisticsTest.java index 191f3acfb32..6317d90fd47 100644 --- a/user/test/com/google/gwt/emultest/java8/util/DoubleSummaryStatisticsTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/DoubleSummaryStatisticsTest.java @@ -16,7 +16,6 @@ package com.google.gwt.emultest.java8.util; -import com.google.gwt.emultest.java.util.EmulTestBase; import static java.lang.Double.MAX_VALUE; import static java.lang.Double.MIN_VALUE; @@ -24,6 +23,8 @@ import static java.lang.Double.NaN; import static java.lang.Double.POSITIVE_INFINITY; +import com.google.gwt.emultest.java.util.EmulTestBase; + import java.util.Arrays; import java.util.DoubleSummaryStatistics; import java.util.List; diff --git a/user/test/com/google/gwt/emultest/java8/util/IntSummaryStatisticsTest.java b/user/test/com/google/gwt/emultest/java8/util/IntSummaryStatisticsTest.java index e1a49d28bb3..35a016c1606 100644 --- a/user/test/com/google/gwt/emultest/java8/util/IntSummaryStatisticsTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/IntSummaryStatisticsTest.java @@ -16,11 +16,11 @@ package com.google.gwt.emultest.java8.util; -import com.google.gwt.emultest.java.util.EmulTestBase; - import static java.lang.Integer.MAX_VALUE; import static java.lang.Integer.MIN_VALUE; +import com.google.gwt.emultest.java.util.EmulTestBase; + import java.util.IntSummaryStatistics; /** diff --git a/user/test/com/google/gwt/emultest/java8/util/LongSummaryStatisticsTest.java b/user/test/com/google/gwt/emultest/java8/util/LongSummaryStatisticsTest.java index 518351c5f9b..f35fb475591 100644 --- a/user/test/com/google/gwt/emultest/java8/util/LongSummaryStatisticsTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/LongSummaryStatisticsTest.java @@ -16,11 +16,11 @@ package com.google.gwt.emultest.java8.util; -import com.google.gwt.emultest.java.util.EmulTestBase; - import static java.lang.Long.MAX_VALUE; import static java.lang.Long.MIN_VALUE; +import com.google.gwt.emultest.java.util.EmulTestBase; + import java.util.LongSummaryStatistics; /** diff --git a/user/test/com/google/gwt/emultest/java8/util/OptionalTest.java b/user/test/com/google/gwt/emultest/java8/util/OptionalTest.java index 67907033ed6..551a51d9bf8 100644 --- a/user/test/com/google/gwt/emultest/java8/util/OptionalTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/OptionalTest.java @@ -139,6 +139,7 @@ public void testFilter() { assertFalse(filtered.isPresent()); } + @SuppressWarnings("ReturnValueIgnored") public void testMap() { // empty case try { @@ -167,6 +168,7 @@ public void testMap() { assertEquals(REFERENCE.toString(), mapped.get()); } + @SuppressWarnings("ReturnValueIgnored") public void testFlatMap() { // empty case try { diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java index 1cc6fbce97a..10619532ea3 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java @@ -181,6 +181,7 @@ public void testReduce() { assertFalse(maybe.isPresent()); } + @SuppressWarnings("ReturnValueIgnored") public void testFilter() { // unconsumed stream never runs filter boolean[] data = {false}; @@ -210,6 +211,7 @@ public void testFilter() { DoubleStream.of(1d, 2d, 3d, 4d, 3d).filter(a -> true).toArray()); } + @SuppressWarnings("ReturnValueIgnored") public void testMap() { // unconsumed stream never runs map int[] data = {0}; @@ -219,6 +221,7 @@ public void testMap() { assertEquals(new double[] {2d, 4d, 6d}, DoubleStream.of(1d, 2d, 3d).map(i -> i * 2).toArray()); } + @SuppressWarnings("ReturnValueIgnored") public void testPeek() { // unconsumed stream never peeks boolean[] data = {false}; diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java index d9b4ebb8304..9a5e19bb748 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java @@ -194,6 +194,7 @@ public void testReduce() { assertFalse(maybe.isPresent()); } + @SuppressWarnings("ReturnValueIgnored") public void testFilter() { // unconsumed stream never runs filter boolean[] data = {false}; @@ -219,6 +220,7 @@ public void testFilter() { new int[] {1, 2, 3, 4, 3}, IntStream.of(1, 2, 3, 4, 3).filter(a -> true).toArray()); } + @SuppressWarnings("ReturnValueIgnored") public void testMap() { // unconsumed stream never runs map int[] data = {0}; @@ -228,6 +230,7 @@ public void testMap() { assertEquals(new int[] {2, 4, 6}, IntStream.of(1, 2, 3).map(i -> i * 2).toArray()); } + @SuppressWarnings("ReturnValueIgnored") public void testPeek() { // unconsumed stream never peeks boolean[] data = {false}; diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java index 6297afdf71d..3720165cac9 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java @@ -193,6 +193,7 @@ public void testReduce() { assertFalse(maybe.isPresent()); } + @SuppressWarnings("ReturnValueIgnored") public void testFilter() { // unconsumed stream never runs filter boolean[] data = {false}; @@ -220,6 +221,7 @@ public void testFilter() { LongStream.of(1L, 2L, 3L, 4L, 3L).filter(a -> true).toArray()); } + @SuppressWarnings("ReturnValueIgnored") public void testMap() { // unconsumed stream never runs map int[] data = {0}; @@ -229,6 +231,7 @@ public void testMap() { assertEquals(new long[] {2L, 4L, 6L}, LongStream.of(1L, 2L, 3L).map(i -> i * 2).toArray()); } + @SuppressWarnings("ReturnValueIgnored") public void testPeek() { // unconsumed stream never peeks boolean[] data = {false}; diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java index f1aea123f02..d6f8eea8b97 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java @@ -19,7 +19,6 @@ import static java.util.Arrays.asList; import com.google.gwt.emultest.java.util.EmulTestBase; - import com.google.gwt.testing.TestUtils; import java.util.ArrayList; @@ -243,6 +242,7 @@ public void testCollect() { assertEquals(asList(values), collectedList); } + @SuppressWarnings("ReturnValueIgnored") public void testFilter() { // unconsumed stream never runs filter boolean[] data = {false}; @@ -277,6 +277,7 @@ public void testFilter() { Stream.of("a", "b", "c", "d", "c").filter(a -> true).collect(Collectors.toList())); } + @SuppressWarnings("ReturnValueIgnored") public void testMap() { // unconsumed stream never runs map boolean[] data = {false}; @@ -288,6 +289,7 @@ public void testMap() { Stream.of(1, 2, 3).map(i -> "#" + i).collect(Collectors.toList())); } + @SuppressWarnings("ReturnValueIgnored") public void testPeek() { // unconsumed stream never peeks boolean[] data = {false}; @@ -471,6 +473,7 @@ public void testCountLimitSkip() { // This frustrating test was written first on the JVM stream to discover the basic behavior before // trying to implement it in GWT. As far as I can tell, none of this is clearly described in // javadoc. Also note that it is *not* required to use the returned stream from calling onClose + @SuppressWarnings("ReturnValueIgnored") public void testCloseQuirks() { // all subclasses use the same close()/onClose(...) impl, just test once with Stream.empty() @@ -562,6 +565,7 @@ public void testClose() { assertEquals(1, calledCount[0]); } + @SuppressWarnings("ReturnValueIgnored") public void testCloseException() { // Try a single exception, confirm we catch it Stream s = Stream.of(1, 2, 3); diff --git a/user/test/com/google/gwt/emultest/java9/util/ListTest.java b/user/test/com/google/gwt/emultest/java9/util/ListTest.java index d1487a477f6..07afcb8db2e 100644 --- a/user/test/com/google/gwt/emultest/java9/util/ListTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/ListTest.java @@ -25,6 +25,7 @@ */ public class ListTest extends EmulTestBase { + @SuppressWarnings("ReturnValueIgnored") public void testOf() { assertIsImmutableListOf(List.of()); assertIsImmutableListOf(List.of("a"), "a"); @@ -83,7 +84,7 @@ public void testOf() { assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", null)); } - protected static void assertIsImmutableListOf(List list, String... contents) { + public static void assertIsImmutableListOf(List list, String... contents) { assertEquals(contents, list); // quick test that the list impl is sane diff --git a/user/test/com/google/gwt/emultest/java9/util/MapTest.java b/user/test/com/google/gwt/emultest/java9/util/MapTest.java index 9d1356f9ca3..50127d4366b 100644 --- a/user/test/com/google/gwt/emultest/java9/util/MapTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/MapTest.java @@ -24,6 +24,7 @@ */ public class MapTest extends EmulTestBase { + @SuppressWarnings("ReturnValueIgnored") public void testOf() { assertIsImmutableMapOf(Map.of()); assertIsImmutableMapOf(Map.of("a", 1), "a"); @@ -109,7 +110,7 @@ public void testOf() { "h", 8, "i", 9, "a", 10)); } - protected static void assertIsImmutableMapOf(Map map, String... contents) { + public static void assertIsImmutableMapOf(Map map, String... contents) { assertEquals(contents.length, map.size()); for (int i = 0; i < contents.length; i++) { assertTrue(map.containsKey(contents[i])); @@ -151,6 +152,7 @@ protected static void assertIsImmutableMapOf(Map map, String... } } + @SuppressWarnings("ReturnValueIgnored") public void testEntry() { Map.Entry entry = Map.entry("a", "b"); @@ -172,7 +174,7 @@ public void testEntry() { }); } - @SuppressWarnings("DuplicateMapKeys") + @SuppressWarnings({"DuplicateMapKeys", "ReturnValueIgnored"}) public void testOfEntries() { Map map = Map.ofEntries( Map.entry("a", 1), diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java index e7befa7724a..50252d0a027 100644 --- a/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java @@ -40,6 +40,7 @@ public void testIfPresentOrElse() { assertEquals(1, called[0]); } + @SuppressWarnings("ReturnValueIgnored") public void testOr() { Optional or = Optional.of("value").or(() -> Optional.of("replacement")); assertTrue(or.isPresent()); diff --git a/user/test/com/google/gwt/emultest/java9/util/SetTest.java b/user/test/com/google/gwt/emultest/java9/util/SetTest.java index 88b1b1bad5a..49f1674a817 100644 --- a/user/test/com/google/gwt/emultest/java9/util/SetTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/SetTest.java @@ -26,6 +26,7 @@ */ public class SetTest extends EmulTestBase { + @SuppressWarnings("ReturnValueIgnored") public void testOf() { assertIsImmutableSetOf(Set.of()); assertIsImmutableSetOf(Set.of("a"), "a"); @@ -96,7 +97,7 @@ public void testOf() { assertIAE("Set.of(...)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "a")); } - protected static void assertIsImmutableSetOf(Set set, String... contents) { + public static void assertIsImmutableSetOf(Set set, String... contents) { assertEquals(contents.length, set.size()); for (int i = 0; i < contents.length; i++) { assertTrue(set.contains(contents[i])); diff --git a/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java b/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java index 1e7adea0814..15f67118c9e 100644 --- a/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collector; +import java.util.stream.Stream; /** * Tests for java.util.stream.Collectors Java 9 API emulation. @@ -51,6 +52,14 @@ public void testFlatMapping() { applyItems(Arrays.asList("a"), flatMappingToNull, Arrays.asList("a"), Arrays.asList("b", "c")); } + @SuppressWarnings("ReturnValueIgnored") + public void testFlatMappingClose() { + int[] calledCount = {0}; + Stream mapped = Stream.of("x").onClose(() -> calledCount[0]++); + Stream.of(1).collect(flatMapping(x -> mapped, toList())); + assertEquals(1, calledCount[0]); + } + public void testFiltering() { Collector> filtering = filtering(s -> s.equals("a"), toList()); applyItems(Collections.singletonList("a"), filtering, "a", "b"); diff --git a/user/test/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreatorTest.java b/user/test/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreatorTest.java index ca23f82ac70..ef4d40c1cb5 100644 --- a/user/test/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreatorTest.java +++ b/user/test/com/google/gwt/i18n/rebind/ConstantsWithLookupImplCreatorTest.java @@ -15,6 +15,10 @@ */ package com.google.gwt.i18n.rebind; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; @@ -35,10 +39,6 @@ import junit.framework.TestCase; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/user/test/com/google/gwt/i18n/rebind/LookupMethodCreatorTest.java b/user/test/com/google/gwt/i18n/rebind/LookupMethodCreatorTest.java index 3fb045b0b05..565f652263a 100644 --- a/user/test/com/google/gwt/i18n/rebind/LookupMethodCreatorTest.java +++ b/user/test/com/google/gwt/i18n/rebind/LookupMethodCreatorTest.java @@ -15,6 +15,8 @@ */ package com.google.gwt.i18n.rebind; +import static org.mockito.Mockito.mock; + import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; @@ -35,8 +37,6 @@ import junit.framework.TestCase; -import static org.mockito.Mockito.mock; - import java.util.List; /** diff --git a/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java b/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java index ff89b0e4f9a..44681379679 100644 --- a/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java +++ b/user/test/com/google/gwt/junit/client/GWTTestCaseTest.java @@ -243,6 +243,7 @@ public void testAssertNullFailWithMessage() { assertNull("msg", "Hello"); } + @SuppressWarnings("JUnitAssertSameCheck") public void testAssertSame() { assertSame(obj1, obj1); assertSame("msg", obj1, obj1); diff --git a/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java b/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java index 2f1d9742c20..9e87f0a21a3 100644 --- a/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java +++ b/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java @@ -15,6 +15,11 @@ */ package com.google.gwt.resources.rg; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.linker.GeneratedResource; @@ -25,11 +30,6 @@ import junit.framework.TestCase; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.HashMap; diff --git a/user/test/com/google/gwt/storage/client/MapInterfaceTest.java b/user/test/com/google/gwt/storage/client/MapInterfaceTest.java index eae46222cb1..bb866bb92a0 100644 --- a/user/test/com/google/gwt/storage/client/MapInterfaceTest.java +++ b/user/test/com/google/gwt/storage/client/MapInterfaceTest.java @@ -133,6 +133,7 @@ protected Map makeEitherMap() { } } + @SuppressWarnings("ReturnValueIgnored") protected final boolean supportsValuesHashCode(Map map) { // get the first non-null value Collection values = map.values(); @@ -274,6 +275,7 @@ public void testClear() { assertInvariants(map); } + @SuppressWarnings("ReturnValueIgnored") public void testContainsKey() { final Map map; final K unmappedKey; @@ -297,6 +299,7 @@ public void testContainsKey() { assertInvariants(map); } + @SuppressWarnings("ReturnValueIgnored") public void testContainsValue() { final Map map; final V unmappedValue; diff --git a/user/test/com/google/gwt/uibinder/elementparsers/MenuItemParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/MenuItemParserTest.java index f0e9b2e9dcc..468be439d4e 100644 --- a/user/test/com/google/gwt/uibinder/elementparsers/MenuItemParserTest.java +++ b/user/test/com/google/gwt/uibinder/elementparsers/MenuItemParserTest.java @@ -172,6 +172,7 @@ private void assertStatements(String... expected) { * Containers method to reference types referenced only from JavaDoc, used to * prevent CheckStyle errors. */ + @SuppressWarnings("ReturnValueIgnored") public void unusedReferences(XMLElement p1, MenuBar p2) { p1.hashCode(); p2.hashCode(); diff --git a/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java b/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java index ebaa500e508..294f04aa358 100644 --- a/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java +++ b/user/test/com/google/gwt/uibinder/rebind/HandlerEvaluatorTest.java @@ -15,6 +15,9 @@ */ package com.google.gwt.uibinder.rebind; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.util.log.PrintWriterTreeLogger; @@ -24,9 +27,6 @@ import junit.framework.TestCase; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import java.io.PrintWriter; import java.io.StringWriter; diff --git a/user/test/com/google/gwt/user/LoggingRPCSuite.gwt.xml b/user/test/com/google/gwt/user/LoggingRPCSuite.gwt.xml index c50cd919ff8..ef64d4cb5a9 100644 --- a/user/test/com/google/gwt/user/LoggingRPCSuite.gwt.xml +++ b/user/test/com/google/gwt/user/LoggingRPCSuite.gwt.xml @@ -19,24 +19,16 @@ + + + - - - - - - - - - - + + - - - + - diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java index 92aa9d22039..ff8fc27feef 100644 --- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java +++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java @@ -559,6 +559,7 @@ public void onFailure(Throwable caught) { } @Override + @SuppressWarnings("CollectionIncompatibleType") public void onSuccess( LinkedHashMap result) { assertNotNull(result); @@ -586,6 +587,7 @@ public void onFailure(Throwable caught) { } @Override + @SuppressWarnings("CollectionIncompatibleType") public void onSuccess( LinkedHashMap actual) { assertNotNull(actual); diff --git a/user/test/com/google/gwt/user/client/rpc/LoggingRPCTest.java b/user/test/com/google/gwt/user/client/rpc/LoggingRPCTest.java index 40b368fc5a5..be9ba701808 100644 --- a/user/test/com/google/gwt/user/client/rpc/LoggingRPCTest.java +++ b/user/test/com/google/gwt/user/client/rpc/LoggingRPCTest.java @@ -179,7 +179,7 @@ public void onSuccess(LogRecord record) { break; } } - assertTrue(found); + assertTrue("expected frame found in stack trace", found); finishTest(); } }); diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java index d398bdab4a7..0dccfa203c8 100644 --- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java +++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java @@ -15,6 +15,11 @@ */ package com.google.gwt.user.client.rpc; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertSame; + import com.google.gwt.event.shared.UmbrellaException; import com.google.gwt.user.client.rpc.FinalFieldsTestService.FinalFieldsNode; import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmptyKey; @@ -33,11 +38,6 @@ import com.google.gwt.user.client.rpc.TestSetFactory.SerializablePrivateNoArg; import com.google.gwt.user.client.rpc.TestSetFactory.SerializableWithTwoArrays; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertSame; - import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; diff --git a/user/test/com/google/gwt/user/client/rpc/TypeCheckedObjectsTestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TypeCheckedObjectsTestSetValidator.java index 64cde649bdf..046be6fc9f1 100644 --- a/user/test/com/google/gwt/user/client/rpc/TypeCheckedObjectsTestSetValidator.java +++ b/user/test/com/google/gwt/user/client/rpc/TypeCheckedObjectsTestSetValidator.java @@ -28,11 +28,13 @@ public class TypeCheckedObjectsTestSetValidator { public static final Integer markerKey = 12345; public static final String markerValue = "Marker"; + @SuppressWarnings("DoubleBraceInitialization") public static final HashSet invalidMarkerKey = new HashSet() { { add(12345); } }; + @SuppressWarnings("DoubleBraceInitialization") public static final HashSet invalidMarkerValue = new HashSet() { { add("Marker");