From 9b9e888bfc5c8991425da65b0e2f12577d0ac638 Mon Sep 17 00:00:00 2001 From: Colin Alworth Date: Mon, 3 Jul 2023 08:48:40 -0500 Subject: [PATCH] Add Java 9 Optional APIs (#9838) Partial #9547 --- .../google/gwt/emul/java/util/Optional.java | 34 +++++++- .../gwt/emul/java/util/OptionalDouble.java | 21 ++++- .../gwt/emul/java/util/OptionalInt.java | 21 ++++- .../gwt/emul/java/util/OptionalLong.java | 21 ++++- .../google/gwt/emultest/EmulJava9Suite.java | 12 ++- .../java9/util/OptionalDoubleTest.java | 57 ++++++++++++ .../emultest/java9/util/OptionalIntTest.java | 57 ++++++++++++ .../emultest/java9/util/OptionalLongTest.java | 57 ++++++++++++ .../gwt/emultest/java9/util/OptionalTest.java | 86 +++++++++++++++++++ 9 files changed, 354 insertions(+), 12 deletions(-) create mode 100644 user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/OptionalTest.java diff --git a/user/super/com/google/gwt/emul/java/util/Optional.java b/user/super/com/google/gwt/emul/java/util/Optional.java index 32584444093..59796306c1d 100644 --- a/user/super/com/google/gwt/emul/java/util/Optional.java +++ b/user/super/com/google/gwt/emul/java/util/Optional.java @@ -15,14 +15,15 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; +import static javaemul.internal.InternalPreconditions.checkNotNull; + import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; -import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; -import static javaemul.internal.InternalPreconditions.checkNotNull; +import java.util.stream.Stream; /** * See @@ -72,6 +73,14 @@ public void ifPresent(Consumer consumer) { } } + public void ifPresentOrElse(Consumer action, Runnable emptyAction) { + if (isPresent()) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + public Optional filter(Predicate predicate) { checkNotNull(predicate); if (!isPresent() || predicate.test(ref)) { @@ -96,6 +105,23 @@ public Optional flatMap(Function> mapper) { return empty(); } + public Optional or(Supplier> supplier) { + checkNotNull(supplier); + if (isPresent()) { + return this; + } else { + return (Optional) checkNotNull(supplier.get()); + } + } + + public Stream stream() { + if (isPresent()) { + return Stream.of(ref); + } else { + return Stream.empty(); + } + } + public T orElse(T other) { return isPresent() ? ref : other; } diff --git a/user/super/com/google/gwt/emul/java/util/OptionalDouble.java b/user/super/com/google/gwt/emul/java/util/OptionalDouble.java index e6b06af100a..b098495758c 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalDouble.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalDouble.java @@ -15,11 +15,12 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; + import java.util.function.DoubleConsumer; import java.util.function.DoubleSupplier; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import java.util.stream.DoubleStream; /** * See @@ -65,6 +66,22 @@ public void ifPresent(DoubleConsumer consumer) { } } + public void ifPresentOrElse(DoubleConsumer action, Runnable emptyAction) { + if (isPresent()) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + + public DoubleStream stream() { + if (isPresent()) { + return DoubleStream.of(ref); + } else { + return DoubleStream.empty(); + } + } + public double orElse(double other) { return present ? ref : other; } diff --git a/user/super/com/google/gwt/emul/java/util/OptionalInt.java b/user/super/com/google/gwt/emul/java/util/OptionalInt.java index 10b7ce66394..a9a36e2b641 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalInt.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalInt.java @@ -15,11 +15,12 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; + import java.util.function.IntConsumer; import java.util.function.IntSupplier; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import java.util.stream.IntStream; /** * See @@ -65,6 +66,22 @@ public void ifPresent(IntConsumer consumer) { } } + public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) { + if (present) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + + public IntStream stream() { + if (present) { + return IntStream.of(ref); + } else { + return IntStream.empty(); + } + } + public int orElse(int other) { return present ? ref : other; } diff --git a/user/super/com/google/gwt/emul/java/util/OptionalLong.java b/user/super/com/google/gwt/emul/java/util/OptionalLong.java index 8551777860b..2b4ba21ffda 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalLong.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalLong.java @@ -15,11 +15,12 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; + import java.util.function.LongConsumer; import java.util.function.LongSupplier; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import java.util.stream.LongStream; /** * See @@ -65,6 +66,22 @@ public void ifPresent(LongConsumer consumer) { } } + public void ifPresentOrElse(LongConsumer action, Runnable emptyAction) { + if (present) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + + public LongStream stream() { + if (present) { + return LongStream.of(ref); + } else { + return LongStream.empty(); + } + } + public long orElse(long other) { return present ? ref : other; } diff --git a/user/test/com/google/gwt/emultest/EmulJava9Suite.java b/user/test/com/google/gwt/emultest/EmulJava9Suite.java index db677087f04..6cdf37ed743 100644 --- a/user/test/com/google/gwt/emultest/EmulJava9Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava9Suite.java @@ -17,6 +17,10 @@ import com.google.gwt.emultest.java9.util.ListTest; import com.google.gwt.emultest.java9.util.MapTest; +import com.google.gwt.emultest.java9.util.OptionalDoubleTest; +import com.google.gwt.emultest.java9.util.OptionalIntTest; +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 org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -26,8 +30,12 @@ @RunWith(Suite.class) @SuiteClasses({ ListTest.class, - SetTest.class, - MapTest.class + MapTest.class, + OptionalDoubleTest.class, + OptionalIntTest.class, + OptionalLongTest.class, + OptionalTest.class, + SetTest.class }) public class EmulJava9Suite { } diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.java new file mode 100644 index 00000000000..6c1aaf294e9 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalDouble; +import java.util.stream.Stream; + +/** + * Tests for java.util.OptionalDouble Java 9 API emulation. + */ +public class OptionalDoubleTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + OptionalDouble.of(10.0).ifPresentOrElse(value -> { + assertEquals(10.0, value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + OptionalDouble.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testStream() { + assertEquals(0, OptionalDouble.empty().stream().count()); + assertEquals(1, OptionalDouble.of(10.0).stream().count()); + + assertEquals( + new double[] {10.0, 100.0, 1000.0}, + Stream.of( + OptionalDouble.of(10.0), + OptionalDouble.empty(), + OptionalDouble.of(100.0), + OptionalDouble.of(1000.0) + ).flatMapToDouble(OptionalDouble::stream).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.java new file mode 100644 index 00000000000..b6fa3783451 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalInt; +import java.util.stream.Stream; + +/** + * Tests for java.util.OptionalInt Java 9 API emulation. + */ +public class OptionalIntTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + OptionalInt.of(10).ifPresentOrElse(value -> { + assertEquals(10, value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + OptionalInt.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testStream() { + assertEquals(0, OptionalInt.empty().stream().count()); + assertEquals(1, OptionalInt.of(10).stream().count()); + + assertEquals( + new int[] {10, 100, 1000}, + Stream.of( + OptionalInt.of(10), + OptionalInt.empty(), + OptionalInt.of(100), + OptionalInt.of(1000) + ).flatMapToInt(OptionalInt::stream).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.java new file mode 100644 index 00000000000..5bb4ed670d8 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalLong; +import java.util.stream.Stream; + +/** + * Tests for java.util.OptionalLong Java 9 API emulation. + */ +public class OptionalLongTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + OptionalLong.of(10).ifPresentOrElse(value -> { + assertEquals(10, value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + OptionalLong.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testStream() { + assertEquals(0, OptionalLong.empty().stream().count()); + assertEquals(1, OptionalLong.of(10).stream().count()); + + assertEquals( + new long[] {10, 100, 1000}, + Stream.of( + OptionalLong.of(10), + OptionalLong.empty(), + OptionalLong.of(100), + OptionalLong.of(1000) + ).flatMapToLong(OptionalLong::stream).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java new file mode 100644 index 00000000000..e7befa7724a --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java @@ -0,0 +1,86 @@ +/* + * 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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Tests for java.util.Optional Java 9 API emulation. + */ +public class OptionalTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + Optional.of("value").ifPresentOrElse(value -> { + assertEquals("value", value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + Optional.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testOr() { + Optional or = Optional.of("value").or(() -> Optional.of("replacement")); + assertTrue(or.isPresent()); + assertEquals("value", or.get()); + + or = Optional.empty().or(() -> Optional.of("replacement")); + assertTrue(or.isPresent()); + assertEquals("replacement", or.get()); + + or = Optional.of("value").or(() -> Optional.empty()); + assertTrue(or.isPresent()); + assertEquals("value", or.get()); + + or = Optional.empty().or(() -> Optional.empty()); + assertFalse(or.isPresent()); + + Optional empty = Optional.empty(); + Optional present = Optional.of("asdf"); + assertNPE("empty().or(null)", () -> { + empty.or(null); + }); + assertNPE("present.or(null)", () -> { + present.or(null); + }); + assertNPE("empty.or(() -> null)", () -> { + empty.or(() -> null); + }); + } + + public void testStream() { + assertEquals(0, Optional.empty().stream().count()); + assertEquals(1, Optional.of("foo").stream().count()); + + assertEquals( + new String[] {"a", "b", "c"}, + Stream.of( + Optional.of("a"), + Optional.empty(), + Optional.of("b"), + Optional.of("c") + ).flatMap(Optional::stream).toArray(String[]::new) + ); + } +}