Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Ongoing discussion about issue when shading Project Reactor
package com.example.demo;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.NoSuchElementException;
import org.junit.Test;
import org.reactivestreams.Publisher;
* This meant to be read top to bottm. The first test is the scenario describe in the official reactor docs,
* the second test describes a possible messy situation for the user, when the wrong Flux get's imported somehow
* and the third one shows the usage of our API.
* </p>
* As we only expose reactive streams, we cannot expose our contextual information and cannot / do not expect
* contextual information coming in.
* </p>
* Spring Data Neo4j wraps the reactive streams returned from the driver inside Flux' and Monos (Flux.from(Publisher)).
* Contextual information stays on that level.
public class ContextualScenarious {
public void normalContextualFlow() {
// Reading about the contextual api:
// One of the main takeaways is
// > Note that in your chain of operators, the relative positions of where you write to the Context and where you
// > read from it matters: the Context is immutable and its content can only be seen by operators above it, as
// > demonstrated in the following code example:
// "Above" is meant pretty literally above: The usage of context elements happens in above the line were the context element is added
Publisher<String> publisher = Mono.just("Data")
.flatMap(s -> Mono.subscriberContext().map(ctx -> s + ctx.get("k")));
Mono<String> r = Mono.from(publisher)
.subscriberContext(ctx -> ctx.put("k", "'"));
public void shadedTypesAndStandardTypesGetsMixedUp() {
// This is unlikely, but you never now
Publisher<String> publisher = org.neo4j.driver.internal.shaded.reactor.core.publisher.Mono.just("Data")
.flatMap(s -> org.neo4j.driver.internal.shaded.reactor.core.publisher.Mono.subscriberContext()
.map(ctx -> s + ctx.get("k")));
Mono<String> r = Mono.from(publisher)
.subscriberContext(ctx -> ctx.put("k", "'"));
static class FakeRxStatementResult {
Publisher<String> records() {
return org.neo4j.driver.internal.shaded.reactor.core.publisher.Flux.just("A", "B", "C");
static class FakeRxSession {
FakeRxStatementResult run(String statementTemplate) {
return new FakeRxStatementResult();
<T> Publisher<T> close() {
return org.neo4j.driver.internal.shaded.reactor.core.publisher.Mono.empty();
public void normalUsageOfOurDriverApi() {
// Assumes a user don't want to work with raw publishers ;)
Flux<String> strings = Flux.usingWhen(
// The user always has to wrap in a standard flux, he has no means of adding or using the
// Project reactor context here.
// The driver itself doesn't make use of the context and even if it would, it could not gave
// away the information to the outside world, as our api shall be publishers alonw.
s -> Flux.from("MATCH (m:Movie) RETURN m ORDER BY ASC").records()
strings = strings
// The user is free to do whatever he wants with the so created flux, i.e. adding contextual information
.flatMap(s -> Mono.subscriberContext().map(ctx -> s + ctx.get("k")))
.subscriberContext(ctx -> ctx.put("k", "'"));
.expectNext("A'", "B'", "C'")
<?xml version="1.0" encoding="UTF-8"?>
<!-- I used Spring Boot's dependency cause I'm lazy… -->
<project xmlns="" xmlns:xsi=""
<relativePath/> <!-- lookup parent from repository -->
<description>Demo project for Spring Boot</description>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.