Created
July 22, 2019 12:04
-
-
Save michael-simons/b15b81dc759da98cffb0ead185e688c7 to your computer and use it in GitHub Desktop.
Ongoing discussion about issue when shading Project Reactor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | |
@Test | |
public void normalContextualFlow() { | |
// Reading about the contextual api: | |
// https://projectreactor.io/docs/core/release/reference/#_the_context_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", "'")); | |
StepVerifier.create(r) | |
.expectNext("Data'") | |
.verifyComplete(); | |
} | |
@Test | |
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", "'")); | |
StepVerifier.create(r) | |
.expectErrorMatches(NoSuchElementException.class::isInstance) | |
.verify(); | |
} | |
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(); | |
} | |
} | |
@Test | |
public void normalUsageOfOurDriverApi() { | |
// Assumes a user don't want to work with raw publishers ;) | |
Flux<String> strings = Flux.usingWhen( | |
Mono.fromSupplier(FakeRxSession::new), | |
// 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( | |
s.run("MATCH (m:Movie) RETURN m ORDER BY m.name ASC").records() | |
), | |
FakeRxSession::close | |
); | |
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", "'")); | |
StepVerifier.create(strings) | |
.expectNext("A'", "B'", "C'") | |
.verifyComplete(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!-- I used Spring Boot's dependency cause I'm lazy… --> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>2.1.6.RELEASE</version> | |
<relativePath/> <!-- lookup parent from repository --> | |
</parent> | |
<groupId>com.example</groupId> | |
<artifactId>demo</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<name>demo</name> | |
<description>Demo project for Spring Boot</description> | |
<properties> | |
<java.version>1.8</java.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-webflux</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.neo4j.driver</groupId> | |
<artifactId>neo4j-java-driver</artifactId> | |
<version>2.0.0-alpha03</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>io.projectreactor</groupId> | |
<artifactId>reactor-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> | |
</project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment