Match if empty by default in InstanceFilter and ExceptionTypeFilter
Prior to this commit, the constructors for InstanceFilter and ExceptionTypeFilter required one to supply the matchIfEmpty flag. However, users will typically want that to be true. Moreover, we always supply true for the matchIfEmpty flag within the Spring Framework. This commit therefore makes the matchIfEmpty flag optional by introducing overloaded constructors for InstanceFilter and ExceptionTypeFilter that only accept the includes and excludes collections. In addition, this commit overhauls the Javadoc for InstanceFilter and ExceptionTypeFilter, fixing several issues in the documentation. Furthermore, this commit applies consistent @Nullable declarations in ExceptionTypeFilter. Closes gh-35158
This commit is contained in:
parent
46c40e7b96
commit
d510b738f4
|
@ -134,7 +134,7 @@ abstract class AbstractJCacheOperation<A extends Annotation> implements JCacheOp
|
|||
protected ExceptionTypeFilter createExceptionTypeFilter(
|
||||
Class<? extends Throwable>[] includes, Class<? extends Throwable>[] excludes) {
|
||||
|
||||
return new ExceptionTypeFilter(Arrays.asList(includes), Arrays.asList(excludes), true);
|
||||
return new ExceptionTypeFilter(Arrays.asList(includes), Arrays.asList(excludes));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ public record MethodRetrySpec(
|
|||
|
||||
|
||||
MethodRetryPredicate combinedPredicate() {
|
||||
ExceptionTypeFilter exceptionFilter = new ExceptionTypeFilter(this.includes, this.excludes, true);
|
||||
ExceptionTypeFilter exceptionFilter = new ExceptionTypeFilter(this.includes, this.excludes);
|
||||
return (method, throwable) -> exceptionFilter.match(throwable.getClass()) &&
|
||||
this.predicate.shouldRetry(method, throwable);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class DefaultRetryPolicy implements RetryPolicy {
|
|||
|
||||
this.includes = includes;
|
||||
this.excludes = excludes;
|
||||
this.exceptionFilter = new ExceptionTypeFilter(this.includes, this.excludes, true);
|
||||
this.exceptionFilter = new ExceptionTypeFilter(this.includes, this.excludes);
|
||||
this.predicate = predicate;
|
||||
this.backOff = backOff;
|
||||
}
|
||||
|
|
|
@ -18,21 +18,63 @@ package org.springframework.util;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An {@link InstanceFilter} implementation that handles exception types. A type
|
||||
* will match against a given candidate if it is assignable to that candidate.
|
||||
* An {@link InstanceFilter} that handles exception types.
|
||||
*
|
||||
* <p>An exception type will match against a given candidate if it is assignable
|
||||
* to that candidate.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
public class ExceptionTypeFilter extends InstanceFilter<Class<? extends Throwable>> {
|
||||
|
||||
public ExceptionTypeFilter(Collection<? extends Class<? extends Throwable>> includes,
|
||||
Collection<? extends Class<? extends Throwable>> excludes, boolean matchIfEmpty) {
|
||||
/**
|
||||
* Create a new {@code ExceptionTypeFilter} based on include and exclude
|
||||
* collections, with the {@code matchIfEmpty} flag set to {@code true}.
|
||||
* <p>See {@link #ExceptionTypeFilter(Collection, Collection, boolean)} for
|
||||
* details.
|
||||
* @param includes the collection of includes
|
||||
* @param excludes the collection of excludes
|
||||
* @since 7.0
|
||||
*/
|
||||
public ExceptionTypeFilter(@Nullable Collection<Class<? extends Throwable>> includes,
|
||||
@Nullable Collection<Class<? extends Throwable>> excludes) {
|
||||
|
||||
super(includes, excludes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code ExceptionTypeFilter} based on include and exclude
|
||||
* collections.
|
||||
* <p>See {@link InstanceFilter#InstanceFilter(Collection, Collection, boolean)
|
||||
* InstanceFilter} for details.
|
||||
* @param includes the collection of includes
|
||||
* @param excludes the collection of excludes
|
||||
* @param matchIfEmpty the matching result if the includes and the excludes
|
||||
* collections are both {@code null} or empty
|
||||
*/
|
||||
public ExceptionTypeFilter(@Nullable Collection<? extends Class<? extends Throwable>> includes,
|
||||
@Nullable Collection<? extends Class<? extends Throwable>> excludes, boolean matchIfEmpty) {
|
||||
|
||||
super(includes, excludes, matchIfEmpty);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the specified {@code instance} matches the specified
|
||||
* {@code candidate}.
|
||||
* <p>By default, the two instances match if the {@code candidate} type is
|
||||
* {@linkplain Class#isAssignableFrom(Class) is assignable from} the
|
||||
* {@code instance} type.
|
||||
* <p>Can be overridden by subclasses.
|
||||
* @param instance the instance to check
|
||||
* @param candidate a candidate defined by this filter
|
||||
* @return {@code true} if the instance matches the candidate
|
||||
*/
|
||||
@Override
|
||||
protected boolean match(Class<? extends Throwable> instance, Class<? extends Throwable> candidate) {
|
||||
return candidate.isAssignableFrom(instance);
|
||||
|
|
|
@ -22,13 +22,14 @@ import java.util.Collections;
|
|||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A simple instance filter that checks if a given instance match based on
|
||||
* a collection of includes and excludes element.
|
||||
* A simple instance filter that checks if a given instance matches based on
|
||||
* collections of includes and excludes.
|
||||
*
|
||||
* <p>Subclasses may want to override {@link #match(Object, Object)} to provide
|
||||
* a custom matching algorithm.
|
||||
* <p>Subclasses may override {@link #match(Object, Object)} to provide a custom
|
||||
* matching algorithm.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @param <T> the instance type
|
||||
*/
|
||||
|
@ -42,17 +43,33 @@ public class InstanceFilter<T> {
|
|||
|
||||
|
||||
/**
|
||||
* Create a new instance based on includes/excludes collections.
|
||||
* <p>A particular element will match if it "matches" the one of the element in the
|
||||
* includes list and does not match one of the element in the excludes list.
|
||||
* <p>Subclasses may redefine what matching means. By default, an element match with
|
||||
* another if it is equals according to {@link Object#equals(Object)}
|
||||
* <p>If both collections are empty, {@code matchIfEmpty} defines if
|
||||
* an element matches or not.
|
||||
* Create a new {@code InstanceFilter} based on include and exclude collections,
|
||||
* with the {@code matchIfEmpty} flag set to {@code true}.
|
||||
* <p>See {@link #InstanceFilter(Collection, Collection, boolean)} for details.
|
||||
* @param includes the collection of includes
|
||||
* @param excludes the collection of excludes
|
||||
* @param matchIfEmpty the matching result if both the includes and the excludes
|
||||
* collections are empty
|
||||
* @since 7.0
|
||||
*/
|
||||
public InstanceFilter(@Nullable Collection<? extends T> includes,
|
||||
@Nullable Collection<? extends T> excludes) {
|
||||
|
||||
this(includes, excludes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code InstanceFilter} based on include and exclude collections.
|
||||
* <p>A particular element will match if it <em>matches</em> one of the elements
|
||||
* in the {@code includes} list and does not match one of the elements in the
|
||||
* {@code excludes} list.
|
||||
* <p>Subclasses may redefine what matching means. By default, an element
|
||||
* {@linkplain #match(Object, Object) matches} another if the two elements are
|
||||
* {@linkplain Object#equals(Object) equal}.
|
||||
* <p>If both collections are empty, {@code matchIfEmpty} defines if an element
|
||||
* matches or not.
|
||||
* @param includes the collection of includes
|
||||
* @param excludes the collection of excludes
|
||||
* @param matchIfEmpty the matching result if the includes and the excludes
|
||||
* collections are both {@code null} or empty
|
||||
*/
|
||||
public InstanceFilter(@Nullable Collection<? extends T> includes,
|
||||
@Nullable Collection<? extends T> excludes, boolean matchIfEmpty) {
|
||||
|
@ -87,9 +104,12 @@ public class InstanceFilter<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified {@code instance} is equal to the
|
||||
* specified {@code candidate}.
|
||||
* @param instance the instance to handle
|
||||
* Determine if the specified {@code instance} matches the specified
|
||||
* {@code candidate}.
|
||||
* <p>By default, the two instances match if they are
|
||||
* {@linkplain Object#equals(Object) equal}.
|
||||
* <p>Can be overridden by subclasses.
|
||||
* @param instance the instance to check
|
||||
* @param candidate a candidate defined by this filter
|
||||
* @return {@code true} if the instance matches the candidate
|
||||
*/
|
||||
|
@ -99,10 +119,10 @@ public class InstanceFilter<T> {
|
|||
|
||||
/**
|
||||
* Determine if the specified {@code instance} matches one of the candidates.
|
||||
* <p>If the candidates collection is {@code null}, returns {@code false}.
|
||||
* @param instance the instance to check
|
||||
* @param candidates a list of candidates
|
||||
* @return {@code true} if the instance match or the candidates collection is null
|
||||
* @param candidates the collection of candidates
|
||||
* @return {@code true} if the instance matches; {@code false} if the
|
||||
* candidates collection is empty or there is no match
|
||||
*/
|
||||
protected boolean match(T instance, Collection<? extends T> candidates) {
|
||||
for (T candidate : candidates) {
|
||||
|
|
|
@ -29,7 +29,7 @@ class ExceptionTypeFilterTests {
|
|||
|
||||
@Test
|
||||
void subClassMatch() {
|
||||
ExceptionTypeFilter filter = new ExceptionTypeFilter(List.of(RuntimeException.class), null, true);
|
||||
ExceptionTypeFilter filter = new ExceptionTypeFilter(List.of(RuntimeException.class), null);
|
||||
assertThat(filter.match(RuntimeException.class)).isTrue();
|
||||
assertThat(filter.match(IllegalStateException.class)).isTrue();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.List;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
|
@ -30,47 +29,44 @@ class InstanceFilterTests {
|
|||
|
||||
@Test
|
||||
void emptyFilterApplyMatchIfEmpty() {
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(null, null, true);
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(null, null);
|
||||
match(filter, "foo");
|
||||
match(filter, "bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void includesFilter() {
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(
|
||||
asList("First", "Second"), null, true);
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(List.of("First", "Second"), null);
|
||||
match(filter, "Second");
|
||||
doNotMatch(filter, "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void excludesFilter() {
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(
|
||||
null, asList("First", "Second"), true);
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(null, List.of("First", "Second"));
|
||||
doNotMatch(filter, "Second");
|
||||
match(filter, "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void includesAndExcludesFilters() {
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(
|
||||
asList("foo", "Bar"), asList("First", "Second"), true);
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(List.of("foo", "Bar"), List.of("First", "Second"));
|
||||
doNotMatch(filter, "Second");
|
||||
match(filter, "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void includesAndExcludesFiltersConflict() {
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(
|
||||
List.of("First"), List.of("First"), true);
|
||||
InstanceFilter<String> filter = new InstanceFilter<>(List.of("First"), List.of("First"));
|
||||
doNotMatch(filter, "First");
|
||||
}
|
||||
|
||||
private <T> void match(InstanceFilter<T> filter, T candidate) {
|
||||
|
||||
private static <T> void match(InstanceFilter<T> filter, T candidate) {
|
||||
assertThat(filter.match(candidate)).as("filter '" + filter + "' should match " + candidate).isTrue();
|
||||
}
|
||||
|
||||
private <T> void doNotMatch(InstanceFilter<T> filter, T candidate) {
|
||||
private static <T> void doNotMatch(InstanceFilter<T> filter, T candidate) {
|
||||
assertThat(filter.match(candidate)).as("filter '" + filter + "' should not match " + candidate).isFalse();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue