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 ;
@@ -46,13 +48,7 @@ public interface Wrapper<T> {
46
48
static <W > boolean isInstanceOf (final W wrapper , final Class <?> clazz ) {
47
49
requireNonNull (wrapper , "wrapper is null" );
48
50
requireNonNull (clazz , "clazz is null" );
49
- return inspect (wrapper , w -> {
50
- if (w instanceof WrapperAdapter ) {
51
- Object adaptee = ((WrapperAdapter <?>) w ).adaptee ();
52
- if (clazz .isAssignableFrom (adaptee .getClass ())) return true ;
53
- }
54
- return clazz .isAssignableFrom (w .getClass ());
55
- });
51
+ return inspect (wrapper , w -> clazz .isAssignableFrom (w .getClass ()));
56
52
}
57
53
58
54
/**
@@ -68,18 +64,13 @@ static <W> boolean isInstanceOf(final W wrapper, final Class<?> clazz) {
68
64
* otherwise return {@code true}
69
65
* @throws NullPointerException if any arguments is null or any wrapper {{@link #unwrap()}} returns null
70
66
*/
71
- @ SuppressWarnings ("unchecked" )
72
67
static <W > boolean inspect (final W wrapper , final Predicate <? super W > predicate ) {
73
68
requireNonNull (wrapper , "wrapper is null" );
74
69
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
- }
70
+ return travel (wrapper , w -> {
71
+ if (predicate .test (w )) return Optional .of (true );
72
+ else return Optional .empty ();
73
+ }).orElse (false );
83
74
}
84
75
85
76
/**
@@ -107,15 +98,60 @@ static <W> boolean inspect(final W wrapper, final Predicate<? super W> predicate
107
98
static <W , K , V > V getAttachment (final W wrapper , final K key ) {
108
99
requireNonNull (wrapper , "wrapper is null" );
109
100
requireNonNull (key , "key is null" );
101
+ return travel (wrapper , w -> {
102
+ if (w instanceof Attachable ) {
103
+ V value = ((Attachable <K , V >) w ).getAttachment (key );
104
+ return Optional .ofNullable (value );
105
+ } else {
106
+ return Optional .empty ();
107
+ }
108
+ }).orElse (null );
109
+ }
110
+
111
+ /**
112
+ * Traverses the wrapper chain, and apply the given {@code process} function to each wrapper,
113
+ * and returns the first non-empty({@link Optional#empty()}) result of the process function,
114
+ * otherwise returns {@link Optional#empty()}.
115
+ * <p>
116
+ * The wrapper chain consists of wrapper itself, followed by the wrappers
117
+ * obtained by repeatedly calling {@link #unwrap()}.
118
+ *
119
+ * @param wrapper wrapper instance
120
+ * @param process process function
121
+ * @param <W> the type of instances that be wrapped
122
+ * @param <T> the return data type of process function
123
+ * @return the first non-empty({@link Optional#empty()}) result of the process function,
124
+ * otherwise returns {@link Optional#empty()}.
125
+ * @throws NullPointerException if any arguments is null or any wrapper {{@link #unwrap()}} returns null
126
+ * @throws IllegalStateException if the adaptee of {@link WrapperAdapter} is a wrapper instance,
127
+ * the use of WrapperAdapter is unnecessary!
128
+ */
129
+ @ NonNull
130
+ @ SuppressWarnings ("unchecked" )
131
+ static <W , T > Optional <T > travel (final W wrapper , final Function <W , Optional <T >> process ) {
132
+ requireNonNull (wrapper , "wrapper is null" );
133
+ requireNonNull (process , "process is null" );
110
134
111
135
Object w = wrapper ;
112
136
while (true ) {
113
- if (w instanceof Attachable ) {
114
- V value = ((Attachable <K , V >) w ).getAttachment (key );
115
- if (value != null ) return value ;
137
+ // process the instance on wrapper chain
138
+ Optional <T > result = process .apply ((W ) w );
139
+ if (result .isPresent ()) return result ;
140
+
141
+ // also process the adaptee if it's a WrapperAdapter
142
+ if (w instanceof WrapperAdapter ) {
143
+ final Object adaptee = ((WrapperAdapter <?>) w ).adaptee ();
144
+ if (adaptee instanceof Wrapper ) {
145
+ throw new IllegalStateException ("adaptee(" + adaptee .getClass ().getName () +
146
+ ") of WrapperAdapter(" + w .getClass ().getName () +
147
+ ") is a wrapper instance, the use of WrapperAdapter is unnecessary!" );
148
+ }
149
+
150
+ Optional <T > r = process .apply ((W ) adaptee );
151
+ if (r .isPresent ()) return r ;
116
152
}
117
153
118
- if (!(w instanceof Wrapper )) return null ;
154
+ if (!(w instanceof Wrapper )) return Optional . empty () ;
119
155
w = unwrapNonNull (w );
120
156
}
121
157
}
0 commit comments