DATACMNS-983 - Added support for Javaslang and Vavr Try as method return types.

We now support the use of Vavr's Try as repository method return type so that exceptions caused by the repository method execution are wrapped into a Failure. Introduced a return type specific indirection of the execution. We now also recursively handle wrapper types so that Try<Option<…>> is valid, too.

Added support for Javaslang's Try, too.
This commit is contained in:
Oliver Gierke
2018-05-17 12:06:35 +02:00
parent 7ab2c84ea8
commit 0f9e88fcaf
5 changed files with 129 additions and 9 deletions

View File

@@ -17,6 +17,7 @@ package org.springframework.data.repository.core.support;
import static org.assertj.core.api.Assertions.*;
import io.vavr.control.Try;
import javaslang.control.Option;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -35,7 +36,6 @@ import java.util.stream.Collectors;
import org.junit.Test;
import org.reactivestreams.Publisher;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.repository.Repository;
import org.springframework.data.util.Streamable;
@@ -345,23 +345,33 @@ public class QueryExecutionResultHandlerUnitTests {
Entity value = new Entity();
Optional<Entity> entity = Optional.of(value);
Object result = handler.postProcessInvocationResult(entity, TypeDescriptor.valueOf(Option.class));
Object result = handler.postProcessInvocationResult(entity, getMethod("option"));
assertThat(result).isInstanceOfSatisfying(Option.class, it -> assertThat(it.get()).isEqualTo(value));
}
@Test // DATACMNS-1165
@SuppressWarnings("unchecked")
public void convertsIterableIntoStreamable() {
public void convertsIterableIntoStreamable() throws Exception {
Iterable<?> source = Arrays.asList(new Object());
Object result = handler.postProcessInvocationResult(source, TypeDescriptor.valueOf(Streamable.class));
Object result = handler.postProcessInvocationResult(source, getMethod("streamable"));
assertThat(result).isInstanceOfSatisfying(Streamable.class,
it -> assertThat(it.stream().collect(Collectors.toList())).isEqualTo(source));
}
@Test // DATACMNS-938
public void resolvesNestedWrapperIfOuterDoesntNeedConversion() throws Exception {
Entity entity = new Entity();
Object result = handler.postProcessInvocationResult(entity, getMethod("tryOfOption"));
assertThat(result).isInstanceOfSatisfying(Option.class, it -> assertThat(it.get()).isEqualTo(entity));
}
private static Method getMethod(String methodName) throws Exception {
return Sample.class.getMethod(methodName);
}
@@ -387,6 +397,15 @@ public class QueryExecutionResultHandlerUnitTests {
Single<Entity> single();
Completable completable();
// DATACMNS-1056
Option<Entity> option();
// DATACMNS-1165
Streamable<Entity> streamable();
// DATACMNS-938
Try<Option<Entity>> tryOfOption();
}
static class Entity {}

View File

@@ -22,6 +22,8 @@ import javaslang.collection.LinkedHashMap;
import javaslang.collection.LinkedHashSet;
import javaslang.collection.Seq;
import javaslang.collection.Traversable;
import javaslang.control.Try;
import javaslang.control.Try.Failure;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import rx.Completable;
@@ -29,6 +31,7 @@ import rx.Observable;
import rx.Single;
import scala.Option;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
@@ -361,8 +364,64 @@ public class QueryExecutionConvertersUnitTests {
.isEqualTo(ClassTypeInformation.from(String.class));
}
@Test // DATACMNS-983
public void exposesExecutionAdapterForJavaslangTry() throws Throwable {
Object result = getExecutionAdapter(Try.class).apply(() -> {
throw new IOException("Some message!");
});
assertThat(result).isInstanceOf(Failure.class);
}
@Test // DATACMNS-983
public void unwrapsDomainTypeFromJavaslangTryWrapper() throws Exception {
for (String methodName : Arrays.asList("tryMethod", "tryForSeqMethod")) {
Method method = Sample.class.getMethod(methodName);
TypeInformation<?> type = QueryExecutionConverters
.unwrapWrapperTypes(ClassTypeInformation.fromReturnTypeOf(method));
assertThat(type.getType()).isEqualTo(Sample.class);
}
}
@Test // DATACMNS-983
public void exposesExecutionAdapterForVavrTry() throws Throwable {
Object result = getExecutionAdapter(io.vavr.control.Try.class).apply(() -> {
throw new IOException("Some message!");
});
assertThat(result).isInstanceOf(io.vavr.control.Try.Failure.class);
}
@Test // DATACMNS-983
public void unwrapsDomainTypeFromVavrTryWrapper() throws Exception {
for (String methodName : Arrays.asList("tryMethod", "tryForSeqMethod")) {
Method method = Sample.class.getMethod(methodName);
TypeInformation<?> type = QueryExecutionConverters
.unwrapWrapperTypes(ClassTypeInformation.fromReturnTypeOf(method));
assertThat(type.getType()).isEqualTo(Sample.class);
}
}
interface Sample {
Page<String> pages();
Try<Sample> tryMethod();
Try<Seq<Sample>> tryForSeqMethod();
io.vavr.control.Try<Sample> vavrTryMethod();
io.vavr.control.Try<io.vavr.collection.Seq<Sample>> vavrTryForSeqMethod();
}
}