Honor Emission result in FluxMessageChannel

* Implement `Emission` handling in the `FluxMessageChannel` and `IntegrationReactiveUtils`
* Upgrade to Spring Kafka `2.6.0`
* Fix R2DBC components for deprecation in the Spring Data R2DBC
* Implement `StatementMapper.SelectSpec` for query expression
* Clean up for some sporadic test failures
This commit is contained in:
Artem Bilan
2020-08-21 14:57:56 -04:00
parent e4b8b32b01
commit af5bcdf4d7
9 changed files with 134 additions and 97 deletions

View File

@@ -16,19 +16,18 @@
package org.springframework.integration.r2dbc.inbound;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import org.springframework.data.r2dbc.convert.EntityRowMapper;
import org.springframework.data.r2dbc.core.R2dbcEntityOperations;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.core.StatementMapper;
import org.springframework.expression.Expression;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.integration.endpoint.AbstractMessageSource;
import org.springframework.integration.expression.ExpressionUtils;
import org.springframework.r2dbc.core.ColumnMapRowMapper;
@@ -40,6 +39,7 @@ import io.r2dbc.spi.Row;
import io.r2dbc.spi.RowMetadata;
import reactor.core.publisher.Mono;
/**
* An instance of {@link org.springframework.integration.core.MessageSource} which returns
* a {@link org.springframework.messaging.Message} with a payload which is the result of
@@ -59,9 +59,11 @@ import reactor.core.publisher.Mono;
*/
public class R2dbcMessageSource extends AbstractMessageSource<Publisher<?>> {
private final R2dbcEntityOperations r2dbcEntityOperations;
private final DatabaseClient databaseClient;
private final ReactiveDataAccessStrategy dataAccessStrategy;
private final StatementMapper statementMapper;
private final Expression queryExpression;
@@ -97,20 +99,22 @@ public class R2dbcMessageSource extends AbstractMessageSource<Publisher<?>> {
* It assumes that the {@link R2dbcEntityOperations} is fully initialized and ready to be used.
* The 'queryExpression' will be evaluated on every call to the {@link #receive()} method.
* @param r2dbcEntityOperations The reactive for performing database calls.
* @param queryExpression The query expression.
* @param queryExpression The query expression. The root object for evaluation context is a {@link StatementMapper}
* for its {@link StatementMapper#createSelect} fluent API.
*/
@SuppressWarnings("deprecation")
public R2dbcMessageSource(R2dbcEntityOperations r2dbcEntityOperations, Expression queryExpression) {
Assert.notNull(r2dbcEntityOperations, "'r2dbcEntityOperations' must not be null");
Assert.notNull(queryExpression, "'queryExpression' must not be null");
this.r2dbcEntityOperations = r2dbcEntityOperations;
this.databaseClient = r2dbcEntityOperations.getDatabaseClient();
this.dataAccessStrategy = r2dbcEntityOperations.getDataAccessStrategy();
this.statementMapper = r2dbcEntityOperations.getDataAccessStrategy().getStatementMapper();
this.queryExpression = queryExpression;
}
/**
* Provide a way to set the type of the entityClass that will be passed to the
* {@link org.springframework.data.r2dbc.core.DatabaseClient#execute(String)}
* method.
* {@link DatabaseClient#sql(String)} method.
* @param payloadType The t class.
*/
public void setPayloadType(Class<?> payloadType) {
@@ -120,8 +124,7 @@ public class R2dbcMessageSource extends AbstractMessageSource<Publisher<?>> {
/**
* Provide a way to set update query that will be passed to the
* {@link org.springframework.data.r2dbc.core.DatabaseClient#execute(String)}
* method.
* {@link DatabaseClient#sql(String)} method.
* @param updateSql Update query string.
*/
public void setUpdateSql(String updateSql) {
@@ -163,15 +166,8 @@ public class R2dbcMessageSource extends AbstractMessageSource<Publisher<?>> {
@Override
protected void onInit() {
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
TypeLocator typeLocator = this.evaluationContext.getTypeLocator();
if (typeLocator instanceof StandardTypeLocator) {
/*
* Register the R2dbc Query DSL package so they don't need a FQCN for QueryBuilder, for example.
*/
((StandardTypeLocator) typeLocator).registerImport("org.springframework.data.relational.core.query");
}
if (!Map.class.isAssignableFrom(this.payloadType)) {
this.rowMapper = this.dataAccessStrategy.getRowMapper(this.payloadType);
this.rowMapper = new EntityRowMapper<>(this.payloadType, this.r2dbcEntityOperations.getConverter());
}
this.initialized = true;
}
@@ -189,7 +185,8 @@ public class R2dbcMessageSource extends AbstractMessageSource<Publisher<?>> {
protected Object doReceive() {
Assert.isTrue(this.initialized, "This class is not yet initialized. Invoke its afterPropertiesSet() method");
Mono<RowsFetchSpec<?>> queryMono =
Mono.fromSupplier(() -> this.queryExpression.getValue(this.evaluationContext))
Mono.fromSupplier(() ->
this.queryExpression.getValue(this.evaluationContext, this.statementMapper))
.map(this::prepareFetch);
if (this.expectSingleResult) {
return queryMono.flatMap(RowsFetchSpec::one)
@@ -213,18 +210,20 @@ public class R2dbcMessageSource extends AbstractMessageSource<Publisher<?>> {
}
private RowsFetchSpec<?> prepareFetch(Object queryObject) {
String queryString = evaluateQueryObject(queryObject);
return this.databaseClient
.sql(queryString)
Supplier<String> query = evaluateQueryObject(queryObject);
return this.databaseClient.sql(query)
.map(this.rowMapper);
}
private String evaluateQueryObject(Object queryObject) {
private Supplier<String> evaluateQueryObject(Object queryObject) {
if (queryObject instanceof String) {
return (String) queryObject;
return () -> (String) queryObject;
}
else if (queryObject instanceof StatementMapper.SelectSpec) {
return this.statementMapper.getMappedObject((StatementMapper.SelectSpec) queryObject);
}
throw new IllegalStateException("'queryExpression' must evaluate to String " +
"or org.springframework.data.relational.core.query.Query, but not: " + queryObject);
"or org.springframework.data.r2dbc.core.StatementMapper.SelectSpec, but not: " + queryObject);
}
}

View File

@@ -76,6 +76,7 @@ public class R2dbcMessageHandler extends AbstractReactiveMessageHandler {
* {@link R2dbcEntityOperations}
* @param r2dbcEntityOperations The R2dbcEntityOperations implementation.
*/
@SuppressWarnings("deprecation")
public R2dbcMessageHandler(R2dbcEntityOperations r2dbcEntityOperations) {
Assert.notNull(r2dbcEntityOperations, "'r2dbcEntityOperations' must not be null");
this.r2dbcEntityOperations = r2dbcEntityOperations;