From 11b1bc19ab360afce8a48167002bfcb747faeb68 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 21 Aug 2022 14:47:13 -0400 Subject: [PATCH] Deprecate ThreadUtils code that defines custom function interfaces in favor of stock java.util.function.Predicate usage. --- src/changes/changes.xml | 1 + .../org/apache/commons/lang3/ThreadUtils.java | 267 ++++++++++++------ .../apache/commons/lang3/ThreadUtilsTest.java | 16 +- 3 files changed, 194 insertions(+), 90 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0121fc61d..fa7d08420 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -97,6 +97,7 @@ The type attribute can be add,update,fix,remove. Simplify conditional expression. #941. Fix some Javadoc comments #938. Deprecate getNanosOfMiili() method with typo and create proper getNanosOfMilli() #940. + Deprecate ThreadUtils code that defines custom function interfaces in favor of stock java.util.function.Predicate usage. Add GitHub coverage.yml. Add EnumUtils.getEnumSystemProperty(...). diff --git a/src/main/java/org/apache/commons/lang3/ThreadUtils.java b/src/main/java/org/apache/commons/lang3/ThreadUtils.java index 369a6c9a4..362b32ac2 100644 --- a/src/main/java/org/apache/commons/lang3/ThreadUtils.java +++ b/src/main/java/org/apache/commons/lang3/ThreadUtils.java @@ -17,10 +17,13 @@ package org.apache.commons.lang3; import java.time.Duration; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.time.DurationUtils; @@ -40,7 +43,10 @@ public class ThreadUtils { /** * A predicate implementation which always returns true. + * + * @deprecated Use a {@link Predicate}. */ + @Deprecated private static final class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate { private AlwaysTruePredicate() { @@ -58,14 +64,20 @@ public class ThreadUtils { } /** + * Used internally, consider private. + *

* A predicate implementation which matches a thread or thread group name. + *

+ * + * @deprecated Use a {@link Predicate}. */ + @Deprecated public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate { private final String name; /** - * Predicate constructor + * Constructs an instance. * * @param name thread or thread group name * @throws NullPointerException if the name is {@code null} @@ -88,7 +100,10 @@ public class ThreadUtils { /** * A predicate for selecting thread groups. + * + * @deprecated Use a {@link Predicate}. */ + @Deprecated // When breaking BC, replace this with Predicate @FunctionalInterface public interface ThreadGroupPredicate { @@ -103,7 +118,10 @@ public class ThreadUtils { /** * A predicate implementation which matches a thread id. + * + * @deprecated Use a {@link Predicate}. */ + @Deprecated public static class ThreadIdPredicate implements ThreadPredicate { private final long threadId; @@ -129,7 +147,10 @@ public class ThreadUtils { /** * A predicate for selecting threads. + * + * @deprecated Use a {@link Predicate}. */ + @Deprecated // When breaking BC, replace this with Predicate @FunctionalInterface public interface ThreadPredicate { @@ -144,9 +165,19 @@ public class ThreadUtils { /** * Predicate which always returns true. + * + * @deprecated Use a {@link Predicate}. */ + @Deprecated public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate(); + private static final Predicate ALWAYS_TRUE = t -> true; + + @SuppressWarnings("unchecked") + private static Predicate alwaysTruePredicate() { + return (Predicate) ALWAYS_TRUE; + } + /** * Finds the active thread with the specified id. * @@ -160,7 +191,10 @@ public class ThreadUtils { * thread groups from this thread's thread group up to the system thread group */ public static Thread findThreadById(final long threadId) { - final Collection result = findThreads(new ThreadIdPredicate(threadId)); + if (threadId <= 0) { + throw new IllegalArgumentException("The thread id must be greater than zero"); + } + final Collection result = findThreads((Predicate) t -> t != null && t.getId() == threadId); return result.isEmpty() ? null : result.iterator().next(); } @@ -213,39 +247,7 @@ public class ThreadUtils { } /** - * Select all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). - * - * @param threadGroup the thread group - * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group - * @param predicate the predicate - * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group - * @throws NullPointerException if the given group or predicate is null - * @throws SecurityException if the current thread cannot modify - * thread groups from this thread's thread group up to the system thread group - */ - public static Collection findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) { - Validate.notNull(threadGroup, "group"); - Validate.notNull(predicate, "predicate"); - - int count = threadGroup.activeGroupCount(); - ThreadGroup[] threadGroups; - do { - threadGroups = new ThreadGroup[count + (count / 2) + 1]; //slightly grow the array size - count = threadGroup.enumerate(threadGroups, recurse); - //return value of enumerate() must be strictly less than the array size according to javadoc - } while (count >= threadGroups.length); - - final List result = new ArrayList<>(count); - for (int i = 0; i < count; ++i) { - if (predicate.test(threadGroups[i])) { - result.add(threadGroups[i]); - } - } - return Collections.unmodifiableCollection(result); - } - - /** - * Select all active thread groups which match the given predicate. + * Finds all active thread groups which match the given predicate. * * @param predicate the predicate * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate @@ -254,7 +256,68 @@ public class ThreadUtils { * if the current thread cannot access the system thread group * @throws SecurityException if the current thread cannot modify * thread groups from this thread's thread group up to the system thread group + * @since 3.13.0 */ + public static Collection findThreadGroups(final Predicate predicate) { + return findThreadGroups(getSystemThreadGroup(), true, predicate); + } + + /** + * Finds all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). + * + * @param threadGroup the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group + * @throws NullPointerException if the given group or predicate is null + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + * @since 3.13.0 + */ + public static Collection findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final Predicate predicate) { + Validate.notNull(threadGroup, "group"); + Validate.notNull(predicate, "predicate"); + + int count = threadGroup.activeGroupCount(); + ThreadGroup[] threadGroups; + do { + threadGroups = new ThreadGroup[count + count / 2 + 1]; //slightly grow the array size + count = threadGroup.enumerate(threadGroups, recurse); + //return value of enumerate() must be strictly less than the array size according to Javadoc + } while (count >= threadGroups.length); + return Collections.unmodifiableCollection(Stream.of(threadGroups).filter(predicate).collect(Collectors.toList())); + } + + /** + * Finds all active thread groups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). + * + * @param threadGroup the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all thread groups in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@link Collection} of active thread groups which match the given predicate and which is a subgroup of the given thread group + * @throws NullPointerException if the given group or predicate is null + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + * @deprecated Use {@link #findThreadGroups(ThreadGroup, boolean, Predicate)}. + */ + @Deprecated + public static Collection findThreadGroups(final ThreadGroup threadGroup, final boolean recurse, final ThreadGroupPredicate predicate) { + return findThreadGroups(threadGroup, recurse, (Predicate) predicate::test); + } + + /** + * Finds all active thread groups which match the given predicate. + * + * @param predicate the predicate + * @return An unmodifiable {@link Collection} of active thread groups matching the given predicate + * @throws NullPointerException if the predicate is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + * @deprecated Use {@link #findThreadGroups(Predicate)}. + */ + @Deprecated public static Collection findThreadGroups(final ThreadGroupPredicate predicate) { return findThreadGroups(getSystemThreadGroup(), true, predicate); } @@ -272,43 +335,11 @@ public class ThreadUtils { * thread groups from this thread's thread group up to the system thread group */ public static Collection findThreadGroupsByName(final String threadGroupName) { - return findThreadGroups(new NamePredicate(threadGroupName)); + return findThreadGroups(predicateThreadGroup(threadGroupName)); } /** - * Select all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). - * - * @param threadGroup the thread group - * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group - * @param predicate the predicate - * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group - * @throws NullPointerException if the given group or predicate is null - * @throws SecurityException if the current thread cannot modify - * thread groups from this thread's thread group up to the system thread group - */ - public static Collection findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) { - Validate.notNull(threadGroup, "The group must not be null"); - Validate.notNull(predicate, "The predicate must not be null"); - - int count = threadGroup.activeCount(); - Thread[] threads; - do { - threads = new Thread[count + (count / 2) + 1]; //slightly grow the array size - count = threadGroup.enumerate(threads, recurse); - //return value of enumerate() must be strictly less than the array size according to javadoc - } while (count >= threads.length); - - final List result = new ArrayList<>(count); - for (int i = 0; i < count; ++i) { - if (predicate.test(threads[i])) { - result.add(threads[i]); - } - } - return Collections.unmodifiableCollection(result); - } - - /** - * Select all active threads which match the given predicate. + * Finds all active threads which match the given predicate. * * @param predicate the predicate * @return An unmodifiable {@link Collection} of active threads matching the given predicate @@ -318,7 +349,68 @@ public class ThreadUtils { * if the current thread cannot access the system thread group * @throws SecurityException if the current thread cannot modify * thread groups from this thread's thread group up to the system thread group + * @since 3.13.0 */ + public static Collection findThreads(final Predicate predicate) { + return findThreads(getSystemThreadGroup(), true, predicate); + } + + /** + * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). + * + * @param threadGroup the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group + * @throws NullPointerException if the given group or predicate is null + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + * @since 3.13.0 + */ + public static Collection findThreads(final ThreadGroup threadGroup, final boolean recurse, final Predicate predicate) { + Validate.notNull(threadGroup, "The group must not be null"); + Validate.notNull(predicate, "The predicate must not be null"); + int count = threadGroup.activeCount(); + Thread[] threads; + do { + threads = new Thread[count + count / 2 + 1]; //slightly grow the array size + count = threadGroup.enumerate(threads, recurse); + //return value of enumerate() must be strictly less than the array size according to javadoc + } while (count >= threads.length); + return Collections.unmodifiableCollection(Stream.of(threads).filter(predicate).collect(Collectors.toList())); + } + + /** + * Finds all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). + * + * @param threadGroup the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@link Collection} of active threads which match the given predicate and which belongs to the given thread group + * @throws NullPointerException if the given group or predicate is null + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + * @deprecated Use {@link #findThreads(ThreadGroup, boolean, Predicate)}. + */ + @Deprecated + public static Collection findThreads(final ThreadGroup threadGroup, final boolean recurse, final ThreadPredicate predicate) { + return findThreads(threadGroup, recurse, (Predicate) predicate::test); + } + + /** + * Finds all active threads which match the given predicate. + * + * @param predicate the predicate + * @return An unmodifiable {@link Collection} of active threads matching the given predicate + * + * @throws NullPointerException if the predicate is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + * @deprecated Use {@link #findThreads(Predicate)}. + */ + @Deprecated public static Collection findThreads(final ThreadPredicate predicate) { return findThreads(getSystemThreadGroup(), true, predicate); } @@ -336,7 +428,7 @@ public class ThreadUtils { * thread groups from this thread's thread group up to the system thread group */ public static Collection findThreadsByName(final String threadName) { - return findThreads(new NamePredicate(threadName)); + return findThreads(predicateThread(threadName)); } /** @@ -356,17 +448,8 @@ public class ThreadUtils { public static Collection findThreadsByName(final String threadName, final String threadGroupName) { Validate.notNull(threadName, "threadName"); Validate.notNull(threadGroupName, "threadGroupName"); - - final Collection threadGroups = findThreadGroups(new NamePredicate(threadGroupName)); - - if (threadGroups.isEmpty()) { - return Collections.emptyList(); - } - - final Collection result = new ArrayList<>(); - final NamePredicate threadNamePredicate = new NamePredicate(threadName); - threadGroups.forEach(group -> result.addAll(findThreads(group, false, threadNamePredicate))); - return Collections.unmodifiableCollection(result); + return Collections.unmodifiableCollection(findThreadGroups(predicateThreadGroup(threadGroupName)).stream() + .flatMap(group -> findThreads(group, false, predicateThread(threadName)).stream()).collect(Collectors.toList())); } /** @@ -384,7 +467,7 @@ public class ThreadUtils { * thread groups from this thread's thread group up to the system thread group */ public static Collection findThreadsByName(final String threadName, final ThreadGroup threadGroup) { - return findThreads(threadGroup, false, new NamePredicate(threadName)); + return findThreads(threadGroup, false, predicateThread(threadName)); } /** @@ -398,7 +481,7 @@ public class ThreadUtils { * thread groups from this thread's thread group up to the system thread group */ public static Collection getAllThreadGroups() { - return findThreadGroups(ALWAYS_TRUE_PREDICATE); + return findThreadGroups(alwaysTruePredicate()); } /** @@ -412,7 +495,7 @@ public class ThreadUtils { * thread groups from this thread's thread group up to the system thread group */ public static Collection getAllThreads() { - return findThreads(ALWAYS_TRUE_PREDICATE); + return findThreads(alwaysTruePredicate()); } /** @@ -446,6 +529,18 @@ public class ThreadUtils { DurationUtils.accept(thread::join, duration); } + private static Predicate namePredicate(final String name, final Function nameGetter) { + return (Predicate) t -> t != null && Objects.equals(nameGetter.apply(t), Objects.requireNonNull(name)); + } + + private static Predicate predicateThread(final String threadName) { + return namePredicate(threadName, Thread::getName); + } + + private static Predicate predicateThreadGroup(final String threadGroupName) { + return namePredicate(threadGroupName, ThreadGroup::getName); + } + /** * Sleeps the current thread for the given duration. Implemented using {@link Thread#sleep(long, int)}. * diff --git a/src/test/java/org/apache/commons/lang3/ThreadUtilsTest.java b/src/test/java/org/apache/commons/lang3/ThreadUtilsTest.java index 5b0891db5..ac4d72a15 100644 --- a/src/test/java/org/apache/commons/lang3/ThreadUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ThreadUtilsTest.java @@ -33,7 +33,10 @@ import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.function.Predicate; +import org.apache.commons.lang3.ThreadUtils.ThreadGroupPredicate; +import org.apache.commons.lang3.ThreadUtils.ThreadPredicate; import org.junit.jupiter.api.Test; /** @@ -275,13 +278,16 @@ public class ThreadUtilsTest extends AbstractLangTest { } @Test - public void testThreadgroupsNullParent() { + public void testThreadGroupsNullParent() { assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null, true, ThreadUtils.ALWAYS_TRUE_PREDICATE)); + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null, false, ThreadUtils.ALWAYS_TRUE_PREDICATE)); } @Test - public void testThreadgroupsNullPredicate() { - assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups(null)); + public void testThreadGroupsNullPredicate() { + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((ThreadGroupPredicate) null)); + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((Predicate) null)); + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreadGroups((Predicate) null)); } @Test @@ -361,7 +367,9 @@ public class ThreadUtilsTest extends AbstractLangTest { @Test public void testThreadsNullPredicate() { - assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads(null)); + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((ThreadPredicate) null)); + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((Predicate) null)); + assertThrows(NullPointerException.class, () -> ThreadUtils.findThreads((Predicate) null)); } @Test