GH-243, GH-257 Added reactive consumer wrapper

- Added wrapper for an already reactive consumer to ensure that consumers can be consistently represented as Function<Flux, Mono>
- Fixed the big that deal with inconsistent result in web environments due to inconsistent representation of the Consumers
- Polished tests

Resolves #243
Resolves #257
This commit is contained in:
Oleg Zhurakousky
2019-02-11 15:30:04 +01:00
parent 660aebc4d9
commit 805b85b102
10 changed files with 175 additions and 69 deletions

View File

@@ -17,35 +17,29 @@
package org.springframework.cloud.function.core;
import java.util.function.Consumer;
import java.util.function.Function;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Wrapper for a {@link Consumer} implementation that converts a non-reactive consumer
* into a reactive function.
* Wrapper for a {@link Consumer} implementation that converts a <i>non-reactive</i>
* consumer into a reactive function ({@code Function<Flux<?>, Mono<?>>}).
*
* @param <T> input type of target consumer
* @param <I> input type of target consumer
* @author Dave Syer
* @author Oleg Zhurakousky
* @see FluxedConsumer
*/
public class FluxConsumer<T>
implements Function<Flux<T>, Mono<Void>>, FluxWrapper<Consumer<T>> {
public class FluxConsumer<I>
extends WrappedFunction<I, Void, Flux<I>, Mono<Void>, Consumer<I>> {
private final Consumer<T> consumer;
public FluxConsumer(Consumer<T> consumer) {
this.consumer = consumer;
public FluxConsumer(Consumer<I> target) {
super(target);
}
@Override
public Consumer<T> getTarget() {
return this.consumer;
}
@Override
public Mono<Void> apply(Flux<T> input) {
return input.doOnNext(this.consumer).then();
public Mono<Void> apply(Flux<I> input) {
return input.doOnNext(this.getTarget()).then();
}
}

View File

@@ -27,24 +27,18 @@ import reactor.core.publisher.Flux;
* @param <T> input type of target function
* @param <R> output type of target function
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public class FluxFunction<T, R>
implements Function<Flux<T>, Flux<R>>, FluxWrapper<Function<T, R>> {
public class FluxFunction<I, O>
extends WrappedFunction<I, O, Flux<I>, Flux<O>, Function<I, O>> {
private final Function<T, R> function;
public FluxFunction(Function<T, R> function) {
this.function = function;
public FluxFunction(Function<I, O> target) {
super(target);
}
@Override
public Function<T, R> getTarget() {
return this.function;
}
@Override
public Flux<R> apply(Flux<T> input) {
return input.map(i -> this.function.apply(i));
public Flux<O> apply(Flux<I> input) {
return input.map(value -> this.getTarget().apply(value));
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2019-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.core;
import java.util.function.Consumer;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Wrapper for a {@link Consumer} implementation that converts a reactive consumer into a
* reactive function ({@code Function<Flux<?>, Mono<?>>}). This is primarily done for
* consistent representation of reactive and non-reactive consumers.
*
* @param <I> input type of target consumer
* @author Oleg Zhurakousky
* @since 2.0.1
* @see FluxConsumer
*
*/
public class FluxedConsumer<I>
extends WrappedFunction<I, Void, Flux<I>, Mono<Void>, Consumer<Flux<I>>> {
public FluxedConsumer(Consumer<Flux<I>> target) {
super(target);
}
@Override
public Mono<Void> apply(Flux<I> input) {
return Mono.fromRunnable(() -> this.getTarget().accept(input));
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2019-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.core;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
/**
* Base class for all wrappers that represent underlying functions (user defined
* suppliers, functions and/or consumers) as reactive functions.
*
* @param <I> input type of target consumer
* @param <O> output type of target consumer
* @param <IP> reactive input type of target function (instance of {@link Publisher}
* @param <OP> reactive output type of target function (instance of {@link Publisher}
* @param <T> actual target function (instance of {@link Supplier}, {@link Function} or
* {@link Consumer})
* @author Oleg Zhurakousky
* @since 2.0.1
*/
abstract class WrappedFunction<I, O, IP extends Publisher<I>, OP extends Publisher<O>, T>
implements Function<IP, OP>, FluxWrapper<T> {
private final T target;
WrappedFunction(T target) {
this.target = target;
}
@Override
public T getTarget() {
return this.target;
}
}