|
4 | 4 | import edu.umd.cs.findbugs.annotations.Nullable;
|
5 | 5 |
|
6 | 6 | import javax.annotation.ParametersAreNonnullByDefault;
|
| 7 | +import java.util.Optional; |
| 8 | +import java.util.function.Function; |
7 | 9 | import java.util.function.Predicate;
|
8 | 10 |
|
9 | 11 | import static io.foldright.inspectablewrappers.InternalUtils.unwrapNonNull;
|
@@ -68,18 +70,13 @@ static <W> boolean isInstanceOf(final W wrapper, final Class<?> clazz) {
|
68 | 70 | * otherwise return {@code true}
|
69 | 71 | * @throws NullPointerException if any arguments is null or any wrapper {{@link #unwrap()}} returns null
|
70 | 72 | */
|
71 |
| - @SuppressWarnings("unchecked") |
72 | 73 | static <W> boolean inspect(final W wrapper, final Predicate<? super W> predicate) {
|
73 | 74 | requireNonNull(wrapper, "wrapper is null");
|
74 | 75 | requireNonNull(predicate, "predicate is null");
|
75 |
| - |
76 |
| - Object w = wrapper; |
77 |
| - while (true) { |
78 |
| - if (predicate.test((W) w)) return true; |
79 |
| - |
80 |
| - if (!(w instanceof Wrapper)) return false; |
81 |
| - w = unwrapNonNull(w); |
82 |
| - } |
| 76 | + return travel(wrapper, w -> { |
| 77 | + if (predicate.test(w)) return Optional.of(true); |
| 78 | + else return Optional.empty(); |
| 79 | + }).orElse(false); |
83 | 80 | }
|
84 | 81 |
|
85 | 82 | /**
|
@@ -107,15 +104,41 @@ static <W> boolean inspect(final W wrapper, final Predicate<? super W> predicate
|
107 | 104 | static <W, K, V> V getAttachment(final W wrapper, final K key) {
|
108 | 105 | requireNonNull(wrapper, "wrapper is null");
|
109 | 106 | requireNonNull(key, "key is null");
|
110 |
| - |
111 |
| - Object w = wrapper; |
112 |
| - while (true) { |
| 107 | + return travel(wrapper, w -> { |
113 | 108 | if (w instanceof Attachable) {
|
114 | 109 | V value = ((Attachable<K, V>) w).getAttachment(key);
|
115 |
| - if (value != null) return value; |
| 110 | + return Optional.ofNullable(value); |
| 111 | + } else { |
| 112 | + return Optional.empty(); |
116 | 113 | }
|
| 114 | + }).orElse(null); |
| 115 | + } |
| 116 | + |
| 117 | + /** |
| 118 | + * Traverses the wrapper chain, and apply the given {@code process} function to each wrapper, |
| 119 | + * and returns the first non-empty({@link Optional#empty()}) result of the process function, |
| 120 | + * otherwise returns {@link Optional#empty()}. |
| 121 | + * <p> |
| 122 | + * The wrapper chain consists of wrapper itself, followed by the wrappers |
| 123 | + * obtained by repeatedly calling {@link #unwrap()}. |
| 124 | + * |
| 125 | + * @param wrapper wrapper instance |
| 126 | + * @param process process function |
| 127 | + * @param <W> the type of instances that be wrapped |
| 128 | + * @param <T> the return data type of process function |
| 129 | + * @return the first non-empty({@link Optional#empty()}) result of the process function, |
| 130 | + * otherwise returns {@link Optional#empty()}. |
| 131 | + */ |
| 132 | + @SuppressWarnings("unchecked") |
| 133 | + static <W, T> Optional<T> travel(final W wrapper, final Function<W, Optional<T>> process) { |
| 134 | + requireNonNull(wrapper, "wrapper is null"); |
| 135 | + requireNonNull(process, "process is null"); |
| 136 | + Object w = wrapper; |
| 137 | + while (true) { |
| 138 | + Optional<T> result = process.apply((W) w); |
| 139 | + if (result.isPresent()) return result; |
117 | 140 |
|
118 |
| - if (!(w instanceof Wrapper)) return null; |
| 141 | + if (!(w instanceof Wrapper)) return Optional.empty(); |
119 | 142 | w = unwrapNonNull(w);
|
120 | 143 | }
|
121 | 144 | }
|
|
0 commit comments