Skip to content

Commit 1b53ce9

Browse files
committed
DATACMNS-836 - Cleanups.
Convert single-instance classes to enums. Consolidate single/multi type checking into ReactiveWrappers class. Guard QueryExecutionConverters.registerConvertersIn against NPE in case of absence of AsyncResult.
1 parent e1a63f5 commit 1b53ce9

File tree

3 files changed

+97
-70
lines changed

3 files changed

+97
-70
lines changed

src/main/java/org/springframework/data/repository/query/ReactiveWrapperConverters.java

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.util.Assert;
3030
import org.springframework.util.ClassUtils;
3131

32+
import io.reactivex.Flowable;
3233
import reactor.core.publisher.Flux;
3334
import reactor.core.publisher.Mono;
3435
import rx.Observable;
@@ -76,7 +77,7 @@ private ReactiveWrapperConverters() {
7677
* Returns whether the given type is a supported wrapper type.
7778
*
7879
* @param type must not be {@literal null}.
79-
* @return
80+
* @return {@literal true} if the {@code type} is a supported reactive wrapper type.
8081
*/
8182
public static boolean supports(Class<?> type) {
8283
return assignableStream(type).isPresent();
@@ -86,25 +87,28 @@ public static boolean supports(Class<?> type) {
8687
* Returns whether the type is a single-like wrapper.
8788
*
8889
* @param type must not be {@literal null}.
89-
* @return
90-
* @see Single
90+
* @return {@literal true} if the {@code type} is a single-like reactive wrapper type.
91+
* @see rx.Single
92+
* @see io.reactivex.Single
9193
* @see Mono
9294
*/
9395
public static boolean isSingleLike(Class<?> type) {
94-
return assignableStream(type).map(wrapper -> wrapper.getMultiplicity() == Multiplicity.ONE).orElse(false);
96+
return ReactiveWrappers.isSingleType(type);
9597
}
9698

9799
/**
98100
* Returns whether the type is a collection/multi-element-like wrapper.
99101
*
100102
* @param type must not be {@literal null}.
101-
* @return
102-
* @see Observable
103+
* @return {@literal true} if the {@code type} is a collection/multi-element-like reactive wrapper type.
104+
* @see rx.Observable
105+
* @see io.reactivex.Observable
106+
* @see io.reactivex.Flowable
103107
* @see Flux
104108
* @see Publisher
105109
*/
106110
public static boolean isCollectionLike(Class<?> type) {
107-
return assignableStream(type).map(wrapper -> wrapper.getMultiplicity() == Multiplicity.MANY).orElse(false);
111+
return ReactiveWrappers.isMultiType(type);
108112
}
109113

110114
/**
@@ -114,6 +118,7 @@ public static boolean isCollectionLike(Class<?> type) {
114118
* @param expectedWrapperType must not be {@literal null}.
115119
* @return
116120
*/
121+
@SuppressWarnings("unchecked")
117122
public static <T> T toWrapper(Object stream, Class<? extends T> expectedWrapperType) {
118123

119124
Assert.notNull(stream, "Stream must not be null!");
@@ -162,59 +167,49 @@ private static Optional<AbstractReactiveWrapper<?>> findWrapper(
162167
return REACTIVE_WRAPPERS.stream().filter(predicate).findFirst();
163168
}
164169

165-
private abstract static class AbstractReactiveWrapper<T> {
166-
167-
private final Class<? super T> wrapperClass;
168-
private final Multiplicity multiplicity;
170+
private interface AbstractReactiveWrapper<T> {
169171

170-
public AbstractReactiveWrapper(Class<? super T> wrapperClass, Multiplicity multiplicity) {
171-
this.wrapperClass = wrapperClass;
172-
this.multiplicity = multiplicity;
173-
}
172+
Class<? super T> getWrapperClass();
174173

175-
public Class<? super T> getWrapperClass() {
176-
return wrapperClass;
177-
}
178-
179-
public Multiplicity getMultiplicity() {
180-
return multiplicity;
181-
}
182-
183-
public abstract Object map(Object wrapper, Converter<Object, Object> converter);
174+
Object map(Object wrapper, Converter<Object, Object> converter);
184175
}
185176

186-
private static class MonoWrapper extends AbstractReactiveWrapper<Mono<?>> {
177+
private enum MonoWrapper implements AbstractReactiveWrapper<Mono<?>> {
187178

188-
static final MonoWrapper INSTANCE = new MonoWrapper();
179+
INSTANCE;
189180

190-
private MonoWrapper() {
191-
super(Mono.class, Multiplicity.ONE);
181+
@Override
182+
public Class<? super Mono<?>> getWrapperClass() {
183+
return Mono.class;
192184
}
193185

186+
@Override
194187
public Mono<?> map(Object wrapper, Converter<Object, Object> converter) {
195188
return ((Mono<?>) wrapper).map(converter::convert);
196189
}
197190
}
198191

199-
private static class FluxWrapper extends AbstractReactiveWrapper<Flux<?>> {
192+
private enum FluxWrapper implements AbstractReactiveWrapper<Flux<?>> {
200193

201-
static final FluxWrapper INSTANCE = new FluxWrapper();
194+
INSTANCE;
202195

203-
private FluxWrapper() {
204-
super(Flux.class, Multiplicity.MANY);
196+
@Override
197+
public Class<? super Flux<?>> getWrapperClass() {
198+
return Flux.class;
205199
}
206200

207201
public Flux<?> map(Object wrapper, Converter<Object, Object> converter) {
208202
return ((Flux<?>) wrapper).map(converter::convert);
209203
}
210204
}
211205

212-
private static class PublisherWrapper extends AbstractReactiveWrapper<Publisher<?>> {
206+
private enum PublisherWrapper implements AbstractReactiveWrapper<Publisher<?>> {
213207

214-
static final PublisherWrapper INSTANCE = new PublisherWrapper();
208+
INSTANCE;
215209

216-
public PublisherWrapper() {
217-
super(Publisher.class, Multiplicity.MANY);
210+
@Override
211+
public Class<? super Publisher<?>> getWrapperClass() {
212+
return Publisher.class;
218213
}
219214

220215
@Override
@@ -232,12 +227,13 @@ public Publisher<?> map(Object wrapper, Converter<Object, Object> converter) {
232227
}
233228
}
234229

235-
private static class RxJava1SingleWrapper extends AbstractReactiveWrapper<Single<?>> {
230+
private enum RxJava1SingleWrapper implements AbstractReactiveWrapper<Single<?>> {
236231

237-
static final RxJava1SingleWrapper INSTANCE = new RxJava1SingleWrapper();
232+
INSTANCE;
238233

239-
private RxJava1SingleWrapper() {
240-
super(Single.class, Multiplicity.ONE);
234+
@Override
235+
public Class<? super Single<?>> getWrapperClass() {
236+
return Single.class;
241237
}
242238

243239
@Override
@@ -246,12 +242,13 @@ public Single<?> map(Object wrapper, Converter<Object, Object> converter) {
246242
}
247243
}
248244

249-
private static class RxJava1ObservableWrapper extends AbstractReactiveWrapper<Observable<?>> {
245+
private enum RxJava1ObservableWrapper implements AbstractReactiveWrapper<Observable<?>> {
250246

251-
static final RxJava1ObservableWrapper INSTANCE = new RxJava1ObservableWrapper();
247+
INSTANCE;
252248

253-
private RxJava1ObservableWrapper() {
254-
super(Observable.class, Multiplicity.MANY);
249+
@Override
250+
public Class<? super Observable<?>> getWrapperClass() {
251+
return Observable.class;
255252
}
256253

257254
@Override
@@ -260,12 +257,13 @@ public Observable<?> map(Object wrapper, Converter<Object, Object> converter) {
260257
}
261258
}
262259

263-
private static class RxJava2SingleWrapper extends AbstractReactiveWrapper<io.reactivex.Single<?>> {
260+
private enum RxJava2SingleWrapper implements AbstractReactiveWrapper<io.reactivex.Single<?>> {
264261

265-
static final RxJava2SingleWrapper INSTANCE = new RxJava2SingleWrapper();
262+
INSTANCE;
266263

267-
private RxJava2SingleWrapper() {
268-
super(io.reactivex.Single.class, Multiplicity.ONE);
264+
@Override
265+
public Class<? super io.reactivex.Single<?>> getWrapperClass() {
266+
return io.reactivex.Single.class;
269267
}
270268

271269
@Override
@@ -274,12 +272,13 @@ public io.reactivex.Single<?> map(Object wrapper, Converter<Object, Object> conv
274272
}
275273
}
276274

277-
private static class RxJava2MaybeWrapper extends AbstractReactiveWrapper<io.reactivex.Maybe<?>> {
275+
private enum RxJava2MaybeWrapper implements AbstractReactiveWrapper<io.reactivex.Maybe<?>> {
278276

279-
static final RxJava2MaybeWrapper INSTANCE = new RxJava2MaybeWrapper();
277+
INSTANCE;
280278

281-
private RxJava2MaybeWrapper() {
282-
super(io.reactivex.Maybe.class, Multiplicity.MANY);
279+
@Override
280+
public Class<? super io.reactivex.Maybe<?>> getWrapperClass() {
281+
return io.reactivex.Maybe.class;
283282
}
284283

285284
@Override
@@ -288,12 +287,13 @@ public io.reactivex.Maybe<?> map(Object wrapper, Converter<Object, Object> conve
288287
}
289288
}
290289

291-
private static class RxJava2ObservableWrapper extends AbstractReactiveWrapper<io.reactivex.Observable<?>> {
290+
private enum RxJava2ObservableWrapper implements AbstractReactiveWrapper<io.reactivex.Observable<?>> {
292291

293-
static final RxJava2ObservableWrapper INSTANCE = new RxJava2ObservableWrapper();
292+
INSTANCE;
294293

295-
private RxJava2ObservableWrapper() {
296-
super(io.reactivex.Observable.class, Multiplicity.MANY);
294+
@Override
295+
public Class<? super io.reactivex.Observable<?>> getWrapperClass() {
296+
return io.reactivex.Observable.class;
297297
}
298298

299299
@Override
@@ -302,12 +302,13 @@ public io.reactivex.Observable<?> map(Object wrapper, Converter<Object, Object>
302302
}
303303
}
304304

305-
private static class RxJava2FlowableWrapper extends AbstractReactiveWrapper<io.reactivex.Flowable<?>> {
305+
private enum RxJava2FlowableWrapper implements AbstractReactiveWrapper<io.reactivex.Flowable<?>> {
306306

307-
static final RxJava2FlowableWrapper INSTANCE = new RxJava2FlowableWrapper();
307+
INSTANCE;
308308

309-
private RxJava2FlowableWrapper() {
310-
super(io.reactivex.Flowable.class, Multiplicity.MANY);
309+
@Override
310+
public Class<? super Flowable<?>> getWrapperClass() {
311+
return io.reactivex.Flowable.class;
311312
}
312313

313314
@Override
@@ -316,8 +317,4 @@ public io.reactivex.Flowable<?> map(Object wrapper, Converter<Object, Object> co
316317
}
317318
}
318319

319-
private enum Multiplicity {
320-
ONE, MANY,
321-
}
322-
323320
}

src/main/java/org/springframework/data/repository/query/ReactiveWrappers.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
package org.springframework.data.repository.query;
1818

1919
import java.util.Collections;
20-
import java.util.HashSet;
20+
import java.util.LinkedHashSet;
2121
import java.util.Set;
2222

23+
import org.reactivestreams.Publisher;
2324
import org.springframework.util.Assert;
2425
import org.springframework.util.ClassUtils;
2526

@@ -35,14 +36,24 @@
3536
*
3637
* @author Mark Paluch
3738
* @since 2.0
38-
* @see Single
39-
* @see Observable
39+
* @see org.reactivestreams.Publisher
40+
* @see rx.Single
41+
* @see rx.Observable
42+
* @see rx.Completable
43+
* @see io.reactivex.Single
44+
* @see io.reactivex.Maybe
45+
* @see io.reactivex.Observable
46+
* @see io.reactivex.Completable
47+
* @see io.reactivex.Flowable
4048
* @see Mono
4149
* @see Flux
4250
*/
4351
@UtilityClass
4452
public class ReactiveWrappers {
4553

54+
public static final boolean PUBLISHER_PRESENT = ClassUtils.isPresent("org.reactivestreams.Publisher",
55+
ReactiveWrappers.class.getClassLoader());
56+
4657
public static final boolean PROJECT_REACTOR_PRESENT = ClassUtils.isPresent("reactor.core.publisher.Flux",
4758
ReactiveWrappers.class.getClassLoader());
4859

@@ -57,8 +68,8 @@ public class ReactiveWrappers {
5768

5869
static {
5970

60-
Set<Class<?>> singleTypes = new HashSet<>();
61-
Set<Class<?>> multiTypes = new HashSet<>();
71+
Set<Class<?>> singleTypes = new LinkedHashSet<>();
72+
Set<Class<?>> multiTypes = new LinkedHashSet<>();
6273

6374
if (RXJAVA1_PRESENT) {
6475
singleTypes.add(getRxJava1SingleClass());
@@ -77,6 +88,10 @@ public class ReactiveWrappers {
7788
multiTypes.add(getReactorFluxClass());
7889
}
7990

91+
if (PUBLISHER_PRESENT) {
92+
multiTypes.add(getReactorPublisherClass());
93+
}
94+
8095
SINGLE_TYPES = Collections.unmodifiableSet(singleTypes);
8196
MULTI_TYPES = Collections.unmodifiableSet(multiTypes);
8297
}
@@ -106,6 +121,12 @@ public static boolean isMultiType(Class<?> theClass) {
106121

107122
Assert.notNull(theClass, "Class type must not be null!");
108123

124+
// Prevent single-types with a multi-hierarchy supertype to be reported as multi type
125+
// See Mono implements Publisher
126+
if (isSingleType(theClass)) {
127+
return false;
128+
}
129+
109130
return isAssignable(MULTI_TYPES, theClass);
110131
}
111132

@@ -151,4 +172,8 @@ private static Class<?> getReactorMonoClass() {
151172
private static Class<?> getReactorFluxClass() {
152173
return Flux.class;
153174
}
175+
176+
private static Class<?> getReactorPublisherClass() {
177+
return Publisher.class;
178+
}
154179
}

src/main/java/org/springframework/data/repository/util/QueryExecutionConverters.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public abstract class QueryExecutionConverters {
7575
"org.springframework.core.annotation.AnnotationConfigurationException",
7676
QueryExecutionConverters.class.getClassLoader());
7777

78+
private static final boolean ASYNC_RESULT_PRESENT = ClassUtils.isPresent(
79+
"org.springframework.scheduling.annotation.AsyncResult", QueryExecutionConverters.class.getClassLoader());
80+
7881
private static final boolean GUAVA_PRESENT = ClassUtils.isPresent("com.google.common.base.Optional",
7982
QueryExecutionConverters.class.getClassLoader());
8083
private static final boolean JDK_8_PRESENT = ClassUtils.isPresent("java.util.Optional",
@@ -206,7 +209,9 @@ public static void registerConvertersIn(ConfigurableConversionService conversion
206209
conversionService.addConverter(new NullableWrapperToScalaOptionConverter(conversionService));
207210
}
208211

209-
conversionService.addConverter(new NullableWrapperToFutureConverter(conversionService));
212+
if (ASYNC_RESULT_PRESENT) {
213+
conversionService.addConverter(new NullableWrapperToFutureConverter(conversionService));
214+
}
210215

211216
if (PROJECT_REACTOR_PRESENT) {
212217

0 commit comments

Comments
 (0)