You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2021/04/30 08:32:17 UTC
[groovy] 01/02: Move stream-related extension methods to
StreamGroovyMethods
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 37af188c3f944f730b6140f44b1e72131a13137a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Apr 28 16:04:39 2021 -0500
Move stream-related extension methods to StreamGroovyMethods
---
build.gradle | 8 +-
.../groovy/runtime/DefaultGroovyMethods.java | 20 +-
.../groovy/runtime/StreamGroovyMethods.java | 486 ++++++++++++++
.../typehandling/DefaultTypeTransformation.java | 4 +-
.../vmplugin/v8/PluginDefaultGroovyMethods.java | 746 +++++----------------
subprojects/groovy-binary/build.gradle | 1 +
6 files changed, 675 insertions(+), 590 deletions(-)
diff --git a/build.gradle b/build.gradle
index 980e5d9..b3ae7fb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -231,10 +231,10 @@ tasks.named('test') {
if (!JavaVersion.current().java10Compatible) {
logger.lifecycle '''
- **************************************** WARNING ********************************************
- ****** You are running the build with an older JDK. NEVER try to release with 1.8. ******
- ****** You must use a JDK 10+ in order to compile all features of the language. ******
- *********************************************************************************************
+**************************************** WARNING ********************************************
+****** You are running the build with an older JDK. NEVER try to release with 1.8. ******
+****** You must use a JDK 10+ in order to compile all features of the language. ******
+*********************************************************************************************
'''
}
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index c756d84..d58862c 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -219,15 +219,17 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
ProcessGroovyMethods.class,
ResourceGroovyMethods.class,
SocketGroovyMethods.class,
- StringGroovyMethods.class//,
- // Below are registered as module extension classes
-// DateUtilExtensions.class,
-// DateTimeStaticExtensions.class,
-// DateTimeExtensions.class,
-// SqlExtensions.class,
-// SwingGroovyMethods.class,
-// XmlExtensions.class,
-// NioExtensions.class
+ StreamGroovyMethods.class,
+ StringGroovyMethods.class,
+ /* registered extensions:
+ DateUtilExtensions.class,
+ DateTimeExtensions.class,
+ DateTimeStaticExtensions.class,
+ NioExtensions.class,
+ SqlExtensions.class,
+ SwingGroovyMethods.class,
+ XmlExtensions.class,
+ */
};
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
private static final NumberAwareComparator<Comparable> COMPARABLE_NUMBER_AWARE_COMPARATOR = new NumberAwareComparator<>();
diff --git a/src/main/java/org/codehaus/groovy/runtime/StreamGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/StreamGroovyMethods.java
new file mode 100644
index 0000000..fa82132
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/StreamGroovyMethods.java
@@ -0,0 +1,486 @@
+package org.codehaus.groovy.runtime;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.stream.BaseStream;
+import java.util.stream.Collectors;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public class StreamGroovyMethods {
+
+ private StreamGroovyMethods() {
+ }
+
+ /**
+ * TODO
+ *
+ * <pre class="groovyTestCase">
+ * import java.util.stream.Stream
+ * assert (Stream.of(1) + [2]).toList() == [1,2]
+ * assert (Stream.of(1) + []).toList() == [1]
+ * </pre>
+ *
+ * @since 4.0.0
+ */
+ public static <T> Stream<T> plus(final Stream<? extends T> lhs, final Collection<? extends T> rhs) {
+ return Stream.concat(lhs, rhs.stream());
+ }
+
+ /**
+ * TODO
+ *
+ * <pre class="groovyTestCase">
+ * import java.util.stream.Stream
+ * assert (Stream.of(1) + [2]).toList() == [1,2]
+ * assert (Stream.of(1) + []).toList() == [1]
+ * </pre>
+ *
+ * @since 4.0.0
+ */
+ public static <T> Stream<T> plus(final Stream<? extends T> lhs, final Iterable<? extends T> rhs) {
+ return Stream.concat(lhs, stream(rhs));
+ }
+
+ /**
+ * TODO
+ *
+ * <pre class="groovyTestCase">
+ * import java.util.stream.Stream
+ * assert (Stream.of(1) + Stream.<Integer>empty()).toList() == [1]
+ * assert (Stream.of(1) + Stream.of(2)).toList() == [1,2]
+ * assert (Stream.of(1) + [2].stream()).toList() == [1,2]
+ * </pre>
+ *
+ * @since 4.0.0
+ */
+ public static <T> Stream<T> plus(final Stream<? extends T> lhs, final Stream<? extends T> rhs) {
+ return Stream.concat(lhs, rhs);
+ }
+
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns a sequential {@link Stream} containing a single element.
+ *
+ * <pre class="groovyTestCase">
+ * def item = 'string'
+ * assert item.stream().toList() == ['string']
+ * assert item.stream().findFirst().isPresent()
+ * </pre>
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final T self) {
+ return Stream.of(self);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param <T> The type of the array elements
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static <T> Stream<T> stream(final T[] self) {
+ return Arrays.stream(self);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Integer> stream(final int[] self) {
+ return Arrays.stream(self).boxed();
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Long> stream(final long[] self) {
+ return Arrays.stream(self).boxed();
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Double> stream(final double[] self) {
+ return Arrays.stream(self).boxed();
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Character> stream(final char[] self) {
+ return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Byte> stream(final byte[] self) {
+ return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Short> stream(final short[] self) {
+ return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Boolean> stream(final boolean[] self) {
+ return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 2.5.0
+ */
+ public static Stream<Float> stream(final float[] self) {
+ return IntStream.range(0, self.length).mapToObj(i -> self[i]);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified element(s) as its
+ * source.
+ * <pre class="groovyTestCase">
+ * def tokens = new StringTokenizer('one two')
+ * assert tokens.stream().toList() == ['one', 'two']
+ * </pre>
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final Enumeration<T> self) {
+ return stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
+ @Override
+ public void forEachRemaining(final Consumer<? super T> action) {
+ while (self.hasMoreElements()) {
+ action.accept(self.nextElement());
+ }
+ }
+ @Override
+ public boolean tryAdvance(final Consumer<? super T> action) {
+ if (self.hasMoreElements()) {
+ action.accept(self.nextElement());
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified element(s) as its
+ * source.
+ *
+ * <pre class="groovyTestCase">
+ * class Items implements Iterable<String> {
+ * Iterator<String> iterator() {
+ * ['one', 'two'].iterator()
+ * }
+ * }
+ * def items = new Items()
+ * assert items.stream().toList() == ['one', 'two']
+ * </pre>
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final Iterable<T> self) {
+ return StreamSupport.stream(self.spliterator(), false);
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified element(s) as its
+ * source.
+ *
+ * <pre class="groovyTestCase">
+ * [].iterator().stream().toList().isEmpty()
+ * ['one', 'two'].iterator().stream().toList() == ['one', 'two']
+ * </pre>
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final Iterator<T> self) {
+ return stream(Spliterators.spliteratorUnknownSize(self, Spliterator.ORDERED));
+ }
+
+ /**
+ * Returns a sequential {@link Stream} with the specified element(s) as its
+ * source.
+ *
+ * <pre class="groovyTestCase">
+ * assert [].spliterator().stream().toList().isEmpty()
+ * assert ['one', 'two'].spliterator().stream().toList() == ['one', 'two']
+ * </pre>
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final Spliterator<T> self) {
+ return StreamSupport.stream(self, false);
+ }
+
+ /**
+ * Returns an empty sequential {@link Stream}.
+ *
+ * <pre class="groovyTestCase">
+ * def item = null
+ * assert item.stream().toList() == []
+ * assert !item.stream().findFirst().isPresent()
+ * </pre>
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final NullObject self) {
+ return Stream.empty();
+ }
+
+ /**
+ * If a value is present in the {@link Optional}, returns a {@link Stream}
+ * with the value as its source or else an empty stream.
+ *
+ * @since 3.0.0
+ */
+ public static <T> Stream<T> stream(final Optional<T> self) {
+ return self.map(Stream::of).orElseGet(Stream::empty);
+ }
+
+ //
+
+ /**
+ * If a value is present in the {@link OptionalInt}, returns an {@link IntStream}
+ * with the value as its source or else an empty stream.
+ *
+ * @since 3.0.0
+ */
+ public static IntStream stream(final OptionalInt self) {
+ if (!self.isPresent()) {
+ return IntStream.empty();
+ }
+ return IntStream.of(self.getAsInt());
+ }
+
+ /**
+ * If a value is present in the {@link OptionalLong}, returns a {@link LongStream}
+ * with the value as its source or else an empty stream.
+ *
+ * @since 3.0.0
+ */
+ public static LongStream stream(final OptionalLong self) {
+ if (!self.isPresent()) {
+ return LongStream.empty();
+ }
+ return LongStream.of(self.getAsLong());
+ }
+
+ /**
+ * If a value is present in the {@link OptionalDouble}, returns a {@link DoubleStream}
+ * with the value as its source or else an empty stream.
+ *
+ * @since 3.0.0
+ */
+ public static DoubleStream stream(final OptionalDouble self) {
+ if (!self.isPresent()) {
+ return DoubleStream.empty();
+ }
+ return DoubleStream.of(self.getAsDouble());
+ }
+
+ /**
+ * Returns a sequential {@link IntStream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 3.0.8
+ */
+ public static IntStream intStream(final int[] self) {
+ return Arrays.stream(self);
+ }
+
+ /**
+ * Returns a sequential {@link LongStream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 3.0.8
+ */
+ public static LongStream longStream(final long[] self) {
+ return Arrays.stream(self);
+ }
+
+ /**
+ * Returns a sequential {@link DoubleStream} with the specified array as its
+ * source.
+ *
+ * @param self The array, assumed to be unmodified during use
+ * @return a {@code Stream} for the array
+ *
+ * @since 3.0.8
+ */
+ public static DoubleStream doubleStream(final double[] self) {
+ return Arrays.stream(self);
+ }
+
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns an array containing the elements of the stream.
+ * <pre class="groovyTestCase">
+ * import static groovy.test.GroovyAssert.shouldFail
+ *
+ * assert Arrays.equals([].stream().toArray(Object), new Object[0])
+ * assert Arrays.equals([].stream().toArray(String), new String[0])
+ * assert Arrays.equals([].stream().toArray(String[]), new String[0][])
+ * assert Arrays.equals(['x'].stream().toArray(Object), ['x'].toArray())
+ * assert Arrays.equals(['x'].stream().toArray(String), ['x'] as String[])
+ * assert Arrays.deepEquals([['x'] as String[]].stream().toArray(String[]), [['x'] as String[]] as String[][])
+ * assert Arrays.equals(['x'].stream().toArray(CharSequence), ['x'] as CharSequence[])
+ *
+ * shouldFail(ArrayStoreException) {
+ * ['x'].stream().toArray(Thread)
+ * }
+ *
+ * shouldFail(IllegalArgumentException) {
+ * ['x'].stream().toArray((Class) null)
+ * }
+ *
+ * // Stream#toArray(IntFunction) should still be used for closure literal:
+ * assert Arrays.equals(['x'].stream().toArray { n -> new String[n] }, ['x'] as String[])
+ *
+ * // Stream#toArray(IntFunction) should still be used for method reference:
+ * assert Arrays.equals(['x'].stream().toArray(String[]::new), ['x'] as String[])
+ * </pre>
+ *
+ * @param self the stream
+ * @param type the array element type
+ *
+ * @since 3.0.4
+ */
+ public static <T> T[] toArray(final Stream<? extends T> self, final Class<T> type) {
+ if (type == null) throw new IllegalArgumentException("type cannot be null");
+ return self.toArray(length -> (T[]) Array.newInstance(type, length));
+ }
+
+ /**
+ * Accumulates the elements of stream into a new List.
+ *
+ * @param self the stream
+ * @param <T> the type of element
+ * @return a new {@code java.util.List} instance
+ *
+ * @since 2.5.0
+ */
+ public static <T> List<T> toList(final Stream<T> self) {
+ return self.collect(Collectors.toList());
+ }
+
+ /**
+ * Accumulates the elements of stream into a new List.
+ *
+ * @param self the {@code java.util.stream.BaseStream}
+ * @param <T> the type of element
+ * @return a new {@code java.util.List} instance
+ *
+ * @since 2.5.0
+ */
+ public static <T> List<T> toList(final BaseStream<T, ? extends BaseStream> self) {
+ return stream(self.iterator()).collect(Collectors.toList());
+ }
+
+ /**
+ * Accumulates the elements of stream into a new Set.
+ *
+ * @param self the stream
+ * @param <T> the type of element
+ * @return a new {@code java.util.Set} instance
+ *
+ * @since 2.5.0
+ */
+ public static <T> Set<T> toSet(final Stream<T> self) {
+ return self.collect(Collectors.toSet());
+ }
+
+ /**
+ * Accumulates the elements of stream into a new Set.
+ *
+ * @param self the {@code java.util.stream.BaseStream}
+ * @param <T> the type of element
+ * @return a new {@code java.util.Set} instance
+ *
+ * @since 2.5.0
+ */
+ public static <T> Set<T> toSet(final BaseStream<T, ? extends BaseStream> self) {
+ return stream(self.iterator()).collect(Collectors.toSet());
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
index c96e4f9..503d782 100644
--- a/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++ b/src/main/java/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -30,8 +30,8 @@ import org.codehaus.groovy.runtime.IteratorClosureAdapter;
import org.codehaus.groovy.runtime.MethodClosure;
import org.codehaus.groovy.runtime.NullObject;
import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+import org.codehaus.groovy.runtime.StreamGroovyMethods;
import org.codehaus.groovy.runtime.StringGroovyMethods;
-import org.codehaus.groovy.vmplugin.v8.PluginDefaultGroovyMethods;
import java.io.File;
import java.io.IOException;
@@ -476,7 +476,7 @@ public class DefaultTypeTransformation {
} else if (value.getClass().isArray()) {
return arrayAsCollection(value);
} else if (value instanceof BaseStream) {
- return PluginDefaultGroovyMethods.toList((BaseStream) value);
+ return StreamGroovyMethods.toList((BaseStream) value);
} else if (value instanceof MethodClosure) {
MethodClosure method = (MethodClosure) value;
IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate());
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java
index 106d209..874b4a6 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/PluginDefaultGroovyMethods.java
@@ -26,29 +26,19 @@ import groovy.transform.stc.ClosureParams;
import groovy.transform.stc.FirstParam;
import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
import org.codehaus.groovy.runtime.InvokerHelper;
-import org.codehaus.groovy.runtime.NullObject;
import org.codehaus.groovy.runtime.RangeInfo;
-import java.lang.management.ManagementFactory;
-import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.Spliterators;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.function.Consumer;
import java.util.function.DoubleFunction;
import java.util.function.DoublePredicate;
import java.util.function.IntFunction;
@@ -59,13 +49,6 @@ import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
-import java.util.stream.BaseStream;
-import java.util.stream.Collectors;
-import java.util.stream.DoubleStream;
-import java.util.stream.IntStream;
-import java.util.stream.LongStream;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
/**
* Defines new Groovy methods which appear on standard Java 8 classes within the
@@ -75,10 +58,116 @@ import java.util.stream.StreamSupport;
*/
public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
- // No instances, static methods only
private PluginDefaultGroovyMethods() {
}
+ //--------------------------------------------------------------------------
+ // Enum
+
+ /**
+ * Overloads the {@code ++} operator for enums. It will invoke Groovy's
+ * default next behaviour for enums that do not have their own next method.
+ *
+ * @param self an Enum
+ * @return the next defined enum from the enum class
+ *
+ * @since 1.5.2
+ */
+ public static Object next(final Enum self) {
+ for (Method method : self.getClass().getMethods()) {
+ if (method.getName().equals("next") && method.getParameterCount() == 0) {
+ return InvokerHelper.invokeMethod(self, "next", InvokerHelper.EMPTY_ARGS);
+ }
+ }
+ Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
+ int index = Arrays.asList(values).indexOf(self);
+ return values[index < values.length - 1 ? index + 1 : 0];
+ }
+
+ /**
+ * Overloads the {@code --} operator for enums. It will invoke Groovy's
+ * default previous behaviour for enums that do not have their own previous method.
+ *
+ * @param self an Enum
+ * @return the previous defined enum from the enum class
+ *
+ * @since 1.5.2
+ */
+ public static Object previous(final Enum self) {
+ for (Method method : self.getClass().getMethods()) {
+ if (method.getName().equals("previous") && method.getParameterCount() == 0) {
+ return InvokerHelper.invokeMethod(self, "previous", InvokerHelper.EMPTY_ARGS);
+ }
+ }
+ Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
+ int index = Arrays.asList(values).indexOf(self);
+ return values[index > 0 ? index - 1 : values.length - 1];
+ }
+
+ //--------------------------------------------------------------------------
+ // Future
+
+ /**
+ * Returns a Future asynchronously returning a transformed result.
+ * <pre class="_temp_disabled_groovyTestCase">
+ * import java.util.concurrent.*
+ * def executor = Executors.newSingleThreadExecutor()
+ * Future<String> foobar = executor.submit{ "foobar" }
+ * Future<Integer> foobarSize = foobar.collect{ it.size() }
+ * assert foobarSize.get() == 6
+ * executor.shutdown()
+ * </pre>
+ *
+ * @param self a Future
+ * @param transform the closure used to transform the Future value
+ * @return a Future allowing the transformed value to be obtained asynchronously
+ *
+ * @since 3.0.0
+ */
+ public static <S,T> Future<T> collect(final Future<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
+ Objects.requireNonNull(self);
+ Objects.requireNonNull(transform);
+ return new TransformedFuture<T>(self, transform);
+ }
+
+ private static class TransformedFuture<E> implements Future<E> {
+ private final Future delegate;
+ private final Closure<E> transform;
+
+ private TransformedFuture(final Future delegate, final Closure<E> transform) {
+ this.delegate = delegate;
+ this.transform = transform;
+ }
+
+ @Override
+ public boolean cancel(final boolean mayInterruptIfRunning) {
+ return delegate.cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return delegate.isCancelled();
+ }
+
+ @Override
+ public boolean isDone() {
+ return delegate.isDone();
+ }
+
+ @Override
+ public E get() throws InterruptedException, ExecutionException {
+ return transform.call(delegate.get());
+ }
+
+ @Override
+ public E get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ return transform.call(delegate.get(timeout, unit));
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Optional
+
/**
* Coerce an {@code Optional} instance to a {@code boolean} value.
* <pre class="groovyTestCase">
@@ -135,6 +224,26 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
}
/**
+ * If the optional contains a value, returns an optional containing the transformed value obtained using the <code>transform</code> closure
+ * or otherwise an empty optional.
+ * <pre class="groovyTestCase">
+ * assert Optional.of("foobar").collect{ it.size() }.get() == 6
+ * assert !Optional.empty().collect{ it.size() }.isPresent()
+ * </pre>
+ *
+ * @param self an Optional
+ * @param transform the closure used to transform the optional value if present
+ * @return an Optional containing the transformed value or empty if the optional is empty or the transform returns null
+ *
+ * @since 3.0.0
+ */
+ public static <S,T> Optional<T> collect(final Optional<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
+ Objects.requireNonNull(self);
+ Objects.requireNonNull(transform);
+ return self.map(transform::call);
+ }
+
+ /**
* Tests given value against specified type and changes generics of result.
* This is equivalent to: <code>self.filter(it -> it instanceof Type).map(it -> (Type) it)</code>
* <pre class="groovyTestCase">
@@ -310,102 +419,42 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
}
/**
- * If the optional contains a value, returns an optional containing the transformed value obtained using the <code>transform</code> closure
- * or otherwise an empty optional.
+ * Provides similar functionality to JDK9 {@code or} on JDK8.
* <pre class="groovyTestCase">
- * assert Optional.of("foobar").collect{ it.size() }.get() == 6
- * assert !Optional.empty().collect{ it.size() }.isPresent()
+ * def x = Optional.empty()
+ * def y = Optional.of('y')
+ * assert y.orOptional(() -> Optional.of('z')).get() == 'y'
+ * assert x.orOptional(() -> Optional.of('z')).get() == 'z'
* </pre>
*
- * @param self an Optional
- * @param transform the closure used to transform the optional value if present
- * @return an Optional containing the transformed value or empty if the optional is empty or the transform returns null
- *
- * @since 3.0.0
- */
- public static <S,T> Optional<T> collect(final Optional<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
- Objects.requireNonNull(self);
- Objects.requireNonNull(transform);
- return self.map(transform::call);
- }
-
- /**
- * Returns a Future asynchronously returning a transformed result.
- * <pre class="_temp_disabled_groovyTestCase">
- * import java.util.concurrent.*
- * def executor = Executors.newSingleThreadExecutor()
- * Future<String> foobar = executor.submit{ "foobar" }
- * Future<Integer> foobarSize = foobar.collect{ it.size() }
- * assert foobarSize.get() == 6
- * executor.shutdown()
- * </pre>
- *
- * @param self a Future
- * @param transform the closure used to transform the Future value
- * @return a Future allowing the transformed value to be obtained asynchronously
- *
- * @since 3.0.0
- */
- public static <S,T> Future<T> collect(final Future<S> self, @ClosureParams(FirstParam.FirstGenericType.class) final Closure<T> transform) {
- Objects.requireNonNull(self);
- Objects.requireNonNull(transform);
- return new TransformedFuture<T>(self, transform);
- }
-
- /**
- * Overloads the {@code ++} operator for enums. It will invoke Groovy's
- * default next behaviour for enums that do not have their own next method.
- *
- * @param self an Enum
- * @return the next defined enum from the enum class
- *
- * @since 1.5.2
+ * @since 3.0.6
*/
- public static Object next(final Enum self) {
- for (Method method : self.getClass().getMethods()) {
- if (method.getName().equals("next") && method.getParameterCount() == 0) {
- return InvokerHelper.invokeMethod(self, "next", InvokerHelper.EMPTY_ARGS);
- }
+ public static <T> Optional<T> orOptional(final Optional<T> self, final Supplier<Optional<? extends T>> supplier) {
+ if (self.isPresent()) {
+ return self;
}
- Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
- int index = Arrays.asList(values).indexOf(self);
- return values[index < values.length - 1 ? index + 1 : 0];
+ return (Optional<T>) supplier.get();
}
+ //--------------------------------------------------------------------------
+ // Runtime
+
/**
- * Overloads the {@code --} operator for enums. It will invoke Groovy's
- * default previous behaviour for enums that do not have their own previous method.
- *
- * @param self an Enum
- * @return the previous defined enum from the enum class
+ * Gets the pid of the current Java process.
*
- * @since 1.5.2
+ * @since 4.0.0
*/
- public static Object previous(final Enum self) {
- for (Method method : self.getClass().getMethods()) {
- if (method.getName().equals("previous") && method.getParameterCount() == 0) {
- return InvokerHelper.invokeMethod(self, "previous", InvokerHelper.EMPTY_ARGS);
- }
+ public static String getPid(final Runtime self) {
+ String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
+ int index = name.indexOf('@');
+ if (index == -1) { // should never happen
+ return name;
}
- Object[] values = (Object[]) InvokerHelper.invokeStaticMethod(self.getClass(), "values", InvokerHelper.EMPTY_ARGS);
- int index = Arrays.asList(values).indexOf(self);
- return values[index > 0 ? index - 1 : values.length - 1];
+ return name.substring(0, index);
}
- /**
- * Provides the standard Groovy <code>size()</code> method for <code>StringBuilder</code>.
- *
- * @param self a StringBuilder
- * @return the length of the StringBuilder
- *
- * @since 1.5.2
- *
- * @see org.codehaus.groovy.runtime.StringGroovyMethods#size(CharSequence)
- */
- @Deprecated
- public static int size(final StringBuilder self) {
- return self.length();
- }
+ //--------------------------------------------------------------------------
+ // StringBuilder
/**
* Overloads the left shift operator to provide an easy way to append multiple
@@ -431,18 +480,16 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
}
/**
- * Supports the range subscript operator for StringBuilder.
- * Index values are treated as characters within the builder.
+ * Appends a String to this StringBuilder.
*
* @param self a StringBuilder
- * @param range a Range
- * @param value the object that's toString() will be inserted
+ * @param value a String
+ * @return a String
*
* @since 1.5.2
*/
- public static void putAt(final StringBuilder self, final IntRange range, final Object value) {
- RangeInfo info = DefaultGroovyMethodsSupport.subListBorders(self.length(), range);
- self.replace(info.from, info.to, value.toString());
+ public static String plus(final StringBuilder self, final String value) {
+ return self + value;
}
/**
@@ -455,488 +502,37 @@ public class PluginDefaultGroovyMethods extends DefaultGroovyMethodsSupport {
* @since 1.5.2
*/
public static void putAt(final StringBuilder self, final EmptyRange range, final Object value) {
- RangeInfo info = DefaultGroovyMethodsSupport.subListBorders(self.length(), range);
+ RangeInfo info = subListBorders(self.length(), range);
self.replace(info.from, info.to, value.toString());
}
/**
- * Appends a String to this StringBuilder.
+ * Supports the range subscript operator for StringBuilder.
+ * Index values are treated as characters within the builder.
*
* @param self a StringBuilder
- * @param value a String
- * @return a String
+ * @param range a Range
+ * @param value the object that's toString() will be inserted
*
* @since 1.5.2
*/
- public static String plus(final StringBuilder self, final String value) {
- return self + value;
- }
-
- private static class TransformedFuture<E> implements Future<E> {
- private final Future delegate;
- private final Closure<E> transform;
-
- private TransformedFuture(final Future delegate, final Closure<E> transform) {
- this.delegate = delegate;
- this.transform = transform;
- }
-
- @Override
- public boolean cancel(final boolean mayInterruptIfRunning) {
- return delegate.cancel(mayInterruptIfRunning);
- }
-
- @Override
- public boolean isCancelled() {
- return delegate.isCancelled();
- }
-
- @Override
- public boolean isDone() {
- return delegate.isDone();
- }
-
- @Override
- public E get() throws InterruptedException, ExecutionException {
- return transform.call(delegate.get());
- }
-
- @Override
- public E get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- return transform.call(delegate.get(timeout, unit));
- }
- }
-
- /**
- * Returns an array containing the elements of the stream.
- * <pre class="groovyTestCase">
- * import static groovy.test.GroovyAssert.shouldFail
- *
- * assert Arrays.equals([].stream().toArray(Object), new Object[0])
- * assert Arrays.equals([].stream().toArray(String), new String[0])
- * assert Arrays.equals([].stream().toArray(String[]), new String[0][])
- * assert Arrays.equals(['x'].stream().toArray(Object), ['x'].toArray())
- * assert Arrays.equals(['x'].stream().toArray(String), ['x'] as String[])
- * assert Arrays.deepEquals([['x'] as String[]].stream().toArray(String[]), [['x'] as String[]] as String[][])
- * assert Arrays.equals(['x'].stream().toArray(CharSequence), ['x'] as CharSequence[])
- *
- * shouldFail(ArrayStoreException) {
- * ['x'].stream().toArray(Thread)
- * }
- *
- * shouldFail(IllegalArgumentException) {
- * ['x'].stream().toArray((Class) null)
- * }
- *
- * // Stream#toArray(IntFunction) should still be used for closure literal:
- * assert Arrays.equals(['x'].stream().toArray { n -> new String[n] }, ['x'] as String[])
- *
- * // Stream#toArray(IntFunction) should still be used for method reference:
- * assert Arrays.equals(['x'].stream().toArray(String[]::new), ['x'] as String[])
- * </pre>
- *
- * @param self the stream
- * @param type the array element type
- *
- * @since 3.0.4
- */
- public static <T> T[] toArray(final Stream<? extends T> self, final Class<T> type) {
- if (type == null) throw new IllegalArgumentException("type cannot be null");
- return self.toArray(length -> (T[]) Array.newInstance(type, length));
- }
-
- /**
- * Accumulates the elements of stream into a new List.
- *
- * @param self the stream
- * @param <T> the type of element
- * @return a new {@code java.util.List} instance
- *
- * @since 2.5.0
- */
- public static <T> List<T> toList(final Stream<T> self) {
- return self.collect(Collectors.toList());
- }
-
- /**
- * Accumulates the elements of stream into a new Set.
- *
- * @param self the stream
- * @param <T> the type of element
- * @return a new {@code java.util.Set} instance
- *
- * @since 2.5.0
- */
- public static <T> Set<T> toSet(final Stream<T> self) {
- return self.collect(Collectors.toSet());
- }
-
- /**
- * Accumulates the elements of stream into a new List.
- *
- * @param self the {@code java.util.stream.BaseStream}
- * @param <T> the type of element
- * @return a new {@code java.util.List} instance
- *
- * @since 2.5.0
- */
- public static <T> List<T> toList(final BaseStream<T, ? extends BaseStream> self) {
- return stream(self.iterator()).collect(Collectors.toList());
- }
-
- /**
- * Accumulates the elements of stream into a new Set.
- *
- * @param self the {@code java.util.stream.BaseStream}
- * @param <T> the type of element
- * @return a new {@code java.util.Set} instance
- *
- * @since 2.5.0
- */
- public static <T> Set<T> toSet(final BaseStream<T, ? extends BaseStream> self) {
- return stream(self.iterator()).collect(Collectors.toSet());
- }
-
- /**
- * Returns an empty sequential {@link Stream}.
- *
- * <pre class="groovyTestCase">
- * def item = null
- * assert item.stream().toList() == []
- * assert !item.stream().findFirst().isPresent()
- * </pre>
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final NullObject self) {
- return Stream.empty();
- }
-
- /**
- * Returns a sequential {@link Stream} containing a single element.
- *
- * <pre class="groovyTestCase">
- * def item = 'string'
- * assert item.stream().toList() == ['string']
- * assert item.stream().findFirst().isPresent()
- * </pre>
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final T self) {
- return Stream.of(self);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param <T> The type of the array elements
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static <T> Stream<T> stream(final T[] self) {
- return Arrays.stream(self);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Integer> stream(final int[] self) {
- return Arrays.stream(self).boxed();
- }
-
- /**
- * Returns a sequential {@link IntStream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 3.0.8
- */
- public static IntStream intStream(final int[] self) {
- return Arrays.stream(self);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Long> stream(final long[] self) {
- return Arrays.stream(self).boxed();
- }
-
- /**
- * Returns a sequential {@link LongStream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 3.0.8
- */
- public static LongStream longStream(final long[] self) {
- return Arrays.stream(self);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Double> stream(final double[] self) {
- return Arrays.stream(self).boxed();
- }
-
- /**
- * Returns a sequential {@link DoubleStream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 3.0.8
- */
- public static DoubleStream doubleStream(final double[] self) {
- return Arrays.stream(self);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Character> stream(final char[] self) {
- return IntStream.range(0, self.length).mapToObj(i -> self[i]);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Byte> stream(final byte[] self) {
- return IntStream.range(0, self.length).mapToObj(i -> self[i]);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Short> stream(final short[] self) {
- return IntStream.range(0, self.length).mapToObj(i -> self[i]);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Boolean> stream(final boolean[] self) {
- return IntStream.range(0, self.length).mapToObj(i -> self[i]);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified array as its
- * source.
- *
- * @param self The array, assumed to be unmodified during use
- * @return a {@code Stream} for the array
- *
- * @since 2.5.0
- */
- public static Stream<Float> stream(final float[] self) {
- return IntStream.range(0, self.length).mapToObj(i -> self[i]);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified element(s) as its
- * source.
- * <pre class="groovyTestCase">
- * def tokens = new StringTokenizer('one two')
- * assert tokens.stream().toList() == ['one', 'two']
- * </pre>
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final Enumeration<T> self) {
- return stream(new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
- @Override
- public void forEachRemaining(final Consumer<? super T> action) {
- while (self.hasMoreElements()) {
- action.accept(self.nextElement());
- }
- }
- @Override
- public boolean tryAdvance(final Consumer<? super T> action) {
- if (self.hasMoreElements()) {
- action.accept(self.nextElement());
- return true;
- }
- return false;
- }
- });
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified element(s) as its
- * source.
- *
- * <pre class="groovyTestCase">
- * class Items implements Iterable<String> {
- * Iterator<String> iterator() {
- * ['one', 'two'].iterator()
- * }
- * }
- * def items = new Items()
- * assert items.stream().toList() == ['one', 'two']
- * </pre>
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final Iterable<T> self) {
- return StreamSupport.stream(self.spliterator(), false);
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified element(s) as its
- * source.
- *
- * <pre class="groovyTestCase">
- * [].iterator().stream().toList().isEmpty()
- * ['one', 'two'].iterator().stream().toList() == ['one', 'two']
- * </pre>
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final Iterator<T> self) {
- return stream(Spliterators.spliteratorUnknownSize(self, Spliterator.ORDERED));
- }
-
- /**
- * Returns a sequential {@link Stream} with the specified element(s) as its
- * source.
- *
- * <pre class="groovyTestCase">
- * assert [].spliterator().stream().toList().isEmpty()
- * assert ['one', 'two'].spliterator().stream().toList() == ['one', 'two']
- * </pre>
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final Spliterator<T> self) {
- return StreamSupport.stream(self, false);
- }
-
- /**
- * If a value is present in the {@link Optional}, returns a {@link Stream}
- * with the value as its source or else an empty stream.
- *
- * @since 3.0.0
- */
- public static <T> Stream<T> stream(final Optional<T> self) {
- return self.map(Stream::of).orElseGet(Stream::empty);
- }
-
- /**
- * If a value is present in the {@link OptionalInt}, returns an {@link IntStream}
- * with the value as its source or else an empty stream.
- *
- * @since 3.0.0
- */
- public static IntStream stream(final OptionalInt self) {
- if (!self.isPresent()) {
- return IntStream.empty();
- }
- return IntStream.of(self.getAsInt());
- }
-
- /**
- * If a value is present in the {@link OptionalLong}, returns a {@link LongStream}
- * with the value as its source or else an empty stream.
- *
- * @since 3.0.0
- */
- public static LongStream stream(final OptionalLong self) {
- if (!self.isPresent()) {
- return LongStream.empty();
- }
- return LongStream.of(self.getAsLong());
+ public static void putAt(final StringBuilder self, final IntRange range, final Object value) {
+ RangeInfo info = subListBorders(self.length(), range);
+ self.replace(info.from, info.to, value.toString());
}
/**
- * If a value is present in the {@link OptionalDouble}, returns a {@link DoubleStream}
- * with the value as its source or else an empty stream.
+ * Provides the standard Groovy {@code size()} method for StringBuilder.
*
- * @since 3.0.0
- */
- public static DoubleStream stream(final OptionalDouble self) {
- if (!self.isPresent()) {
- return DoubleStream.empty();
- }
- return DoubleStream.of(self.getAsDouble());
- }
-
- /**
- * Provide similar functionality to JDK9 {@code or} on JDK8.
+ * @param self a StringBuilder
+ * @return the length of the StringBuilder
*
- * @since 3.0.6
- */
- public static <T> Optional<T> orOptional(Optional<T> self, Supplier<? extends Optional<? extends T>> supplier) {
- if (self.isPresent()) {
- return self;
- }
- return (Optional<T>) supplier.get();
- }
-
- /**
- * Get the pid of the current Java process
+ * @since 1.5.2
*
- * @param self
- * @return the pid
- * @since 4.0.0
+ * @see org.codehaus.groovy.runtime.StringGroovyMethods#size(CharSequence)
*/
- public static String getPid(Runtime self) {
- String name = ManagementFactory.getRuntimeMXBean().getName();
- int index = name.indexOf('@');
- if (-1 == index) { // should never happen
- return name;
- }
- return name.substring(0, index);
+ @Deprecated
+ public static int size(final StringBuilder self) {
+ return self.length();
}
}
diff --git a/subprojects/groovy-binary/build.gradle b/subprojects/groovy-binary/build.gradle
index 3e4fcb8..61b82c5 100644
--- a/subprojects/groovy-binary/build.gradle
+++ b/subprojects/groovy-binary/build.gradle
@@ -45,6 +45,7 @@ distribution {
'org.codehaus.groovy.runtime.ProcessGroovyMethods',
'org.codehaus.groovy.runtime.ResourceGroovyMethods',
'org.codehaus.groovy.runtime.SocketGroovyMethods',
+ 'org.codehaus.groovy.runtime.StreamGroovyMethods',
'org.codehaus.groovy.runtime.StringGroovyMethods',
'org.codehaus.groovy.vmplugin.v8.PluginDefaultGroovyMethods',
'org.codehaus.groovy.vmplugin.v9.PluginDefaultGroovyMethods',