DATACMNS-1467 - Decouple sync and reactive bits.
Add dedicated interfaces for sync and reactive usage. Hide default implementation and use reflective callback method lookup. Update documentation and add initial reference documentation snippet for store specific modules. Original Pull Request: #332
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* https://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.data.mapping.callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.mapping.PersonDocument;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class CapturingEntityCallback implements EntityCallback<Person> {
|
||||
|
||||
final List<Person> captured = new ArrayList<>(3);
|
||||
final @Nullable Person returnValue;
|
||||
|
||||
CapturingEntityCallback() {
|
||||
this(new PersonDocument(null, null, null));
|
||||
}
|
||||
|
||||
CapturingEntityCallback(@Nullable Person returnValue) {
|
||||
this.returnValue = returnValue;
|
||||
}
|
||||
|
||||
public Person doSomething(Person person) {
|
||||
|
||||
captured.add(person);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
Person capturedValue() {
|
||||
return CollectionUtils.lastElement(captured);
|
||||
}
|
||||
|
||||
List<Person> capturedValues() {
|
||||
return captured;
|
||||
}
|
||||
|
||||
static class FirstCallback extends CapturingEntityCallback implements Ordered {
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static class SecondCallback extends CapturingEntityCallback implements Ordered {
|
||||
|
||||
public SecondCallback() {}
|
||||
|
||||
public SecondCallback(Person returnValue) {
|
||||
super(returnValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static class ThirdCallback extends CapturingEntityCallback implements Ordered {
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* https://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.data.mapping.callback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.mapping.PersonDocument;
|
||||
import org.springframework.data.mapping.callback.CapturingEntityCallback.FirstCallback;
|
||||
import org.springframework.data.mapping.callback.CapturingEntityCallback.SecondCallback;
|
||||
import org.springframework.data.mapping.callback.CapturingEntityCallback.ThirdCallback;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultEntityCallbacks}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class DefaultEntityCallbacksUnitTests {
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldDispatchCallback() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
PersonDocument afterCallback = callbacks.callback(BeforeSaveCallback.class, personDocument);
|
||||
|
||||
assertThat(afterCallback.getSsn()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldDispatchCallsToLambdaReceivers() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(LambdaConfig.class);
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
PersonDocument afterCallback = callbacks.callback(BeforeSaveCallback.class, personDocument);
|
||||
|
||||
assertThat(afterCallback).isSameAs(personDocument);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void invokeGenericEvent() {
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks();
|
||||
callbacks.addEntityCallback(new GenericPersonCallback());
|
||||
|
||||
Person afterCallback = callbacks.callback(GenericPersonCallback.class, new PersonDocument(null, "Walter", null));
|
||||
|
||||
assertThat(afterCallback.getSsn()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void invokeGenericEventWithArgs() {
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks();
|
||||
callbacks.addEntityCallback(new GenericPersonCallbackWithArgs());
|
||||
|
||||
Person afterCallback = callbacks.callback(GenericPersonCallbackWithArgs.class,
|
||||
new PersonDocument(null, "Walter", null), "agr0", Float.POSITIVE_INFINITY);
|
||||
|
||||
assertThat(afterCallback.getSsn()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void invokeInvalidEvent() {
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks();
|
||||
callbacks.addEntityCallback(new InvalidEntityCallback() {});
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException.class)
|
||||
.isThrownBy(() -> callbacks.callback(InvalidEntityCallback.class, new PersonDocument(null, "Walter", null),
|
||||
"agr0", Float.POSITIVE_INFINITY));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void passesInvocationResultOnAlongTheChain() {
|
||||
|
||||
CapturingEntityCallback first = new FirstCallback();
|
||||
CapturingEntityCallback second = new SecondCallback();
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks();
|
||||
callbacks.addEntityCallback(first);
|
||||
callbacks.addEntityCallback(second);
|
||||
|
||||
PersonDocument initial = new PersonDocument(null, "Walter", null);
|
||||
|
||||
callbacks.callback(CapturingEntityCallback.class, initial);
|
||||
|
||||
assertThat(first.capturedValue()).isSameAs(initial);
|
||||
assertThat(first.capturedValues()).hasSize(1);
|
||||
assertThat(second.capturedValue()).isNotSameAs(initial);
|
||||
assertThat(second.capturedValues()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void errorsOnNullEntity() {
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks();
|
||||
callbacks.addEntityCallback(new CapturingEntityCallback());
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> callbacks.callback(CapturingEntityCallback.class, null));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void errorsOnNullValueReturnedByCallbackEntity() {
|
||||
|
||||
CapturingEntityCallback first = new FirstCallback();
|
||||
CapturingEntityCallback second = new SecondCallback(null);
|
||||
CapturingEntityCallback third = new ThirdCallback();
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks();
|
||||
callbacks.addEntityCallback(first);
|
||||
callbacks.addEntityCallback(second);
|
||||
callbacks.addEntityCallback(third);
|
||||
|
||||
PersonDocument initial = new PersonDocument(null, "Walter", null);
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> callbacks.callback(CapturingEntityCallback.class, initial));
|
||||
|
||||
assertThat(first.capturedValue()).isSameAs(initial);
|
||||
assertThat(second.capturedValue()).isNotNull().isNotSameAs(initial);
|
||||
assertThat(third.capturedValues()).isEmpty();
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void detectsMultipleCallbacksWithinOneClass() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MultipleCallbacksInOneClassConfig.class);
|
||||
|
||||
DefaultEntityCallbacks callbacks = new DefaultEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
callbacks.callback(BeforeSaveCallback.class, personDocument);
|
||||
|
||||
assertThat(ctx.getBean("callbacks", MultipleCallbacks.class).invocations).containsExactly("save");
|
||||
|
||||
callbacks.callback(BeforeConvertCallback.class, personDocument);
|
||||
|
||||
assertThat(ctx.getBean("callbacks", MultipleCallbacks.class).invocations).containsExactly("save", "convert");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MyConfig {
|
||||
|
||||
@Bean
|
||||
MyBeforeSaveCallback callback() {
|
||||
return new MyBeforeSaveCallback();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
Object namedCallback() {
|
||||
return new MyOtherCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class LambdaConfig {
|
||||
|
||||
@Bean
|
||||
BeforeSaveCallback<User> userCallback() {
|
||||
return object -> object;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BeforeSaveCallback<Person> personCallback() {
|
||||
|
||||
return object -> {
|
||||
object.setSsn(object.getFirstName().length());
|
||||
return object;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleCallbacksInOneClassConfig {
|
||||
|
||||
@Bean
|
||||
MultipleCallbacks callbacks() {
|
||||
return new MultipleCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
interface BeforeConvertCallback<T> extends EntityCallback<T>, Ordered {
|
||||
T onBeforeConvert(T object);
|
||||
|
||||
@Override
|
||||
default int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
interface BeforeSaveCallback<T> extends EntityCallback<T> {
|
||||
T onBeforeSave(T object);
|
||||
}
|
||||
|
||||
static class MyBeforeSaveCallback implements BeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
|
||||
object.setSsn(object.getFirstName().length());
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyOtherCallback implements BeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class User {}
|
||||
|
||||
static class GenericPersonCallback implements EntityCallback<Person> {
|
||||
|
||||
public Person onBeforeSave(Person value) {
|
||||
|
||||
value.setSsn(value.getFirstName().length());
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
static class GenericPersonCallbackWithArgs implements EntityCallback<Person> {
|
||||
|
||||
public Person onBeforeSave(Person value, String agr1, Object arg2) {
|
||||
|
||||
value.setSsn(value.getFirstName().length());
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
interface InvalidEntityCallback extends EntityCallback<Person> {
|
||||
|
||||
default Person onBeforeSave(String value, Person entity) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
static class MultipleCallbacks implements BeforeConvertCallback<Person>, BeforeSaveCallback<Person> {
|
||||
|
||||
List<String> invocations = new ArrayList(2);
|
||||
|
||||
@Override
|
||||
public Person onBeforeConvert(Person object) {
|
||||
|
||||
invocations.add("convert");
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
|
||||
invocations.add("save");
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* https://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.data.mapping.callback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.mapping.PersonDocument;
|
||||
import org.springframework.data.mapping.callback.CapturingEntityCallback.FirstCallback;
|
||||
import org.springframework.data.mapping.callback.CapturingEntityCallback.SecondCallback;
|
||||
import org.springframework.data.mapping.callback.CapturingEntityCallback.ThirdCallback;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultReactiveEntityCallbacks}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class DefaultReactiveEntityCallbacksUnitTests {
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void dispatchResolvesOnSubscribe() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
DefaultReactiveEntityCallbacks callbacks = new DefaultReactiveEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
Mono<PersonDocument> afterCallback = callbacks.callback(ReactiveBeforeSaveCallback.class, personDocument);
|
||||
|
||||
assertThat(personDocument.getSsn()).isNull();
|
||||
|
||||
afterCallback.as(StepVerifier::create) //
|
||||
.consumeNextWith(it -> assertThat(it.getSsn()).isEqualTo(6)) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void invokeGenericEvent() {
|
||||
|
||||
DefaultReactiveEntityCallbacks callbacks = new DefaultReactiveEntityCallbacks();
|
||||
callbacks.addEntityCallback(new GenericPersonCallback());
|
||||
|
||||
callbacks.callback(GenericPersonCallback.class, new PersonDocument(null, "Walter", null)) //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(it -> assertThat(it.getSsn()).isEqualTo(6)) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void passesInvocationResultOnAlongTheChain() {
|
||||
|
||||
CapturingEntityCallback first = new FirstCallback();
|
||||
CapturingEntityCallback second = new SecondCallback();
|
||||
|
||||
DefaultReactiveEntityCallbacks callbacks = new DefaultReactiveEntityCallbacks();
|
||||
callbacks.addEntityCallback(first);
|
||||
callbacks.addEntityCallback(second);
|
||||
|
||||
PersonDocument initial = new PersonDocument(null, "Walter", null);
|
||||
|
||||
callbacks.callback(CapturingEntityCallback.class, initial) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextCount(1) //
|
||||
.verifyComplete();
|
||||
|
||||
assertThat(first.capturedValue()).isSameAs(initial);
|
||||
assertThat(first.capturedValues()).hasSize(1);
|
||||
assertThat(second.capturedValue()).isNotSameAs(initial);
|
||||
assertThat(second.capturedValues()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void errorsOnNullEntity() {
|
||||
|
||||
DefaultReactiveEntityCallbacks callbacks = new DefaultReactiveEntityCallbacks();
|
||||
callbacks.addEntityCallback(new CapturingEntityCallback());
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> callbacks.callback(CapturingEntityCallback.class, null));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void errorsOnNullValueReturnedByCallbackEntity() {
|
||||
|
||||
CapturingEntityCallback first = new FirstCallback();
|
||||
CapturingEntityCallback second = new SecondCallback(null);
|
||||
CapturingEntityCallback third = new ThirdCallback();
|
||||
|
||||
DefaultReactiveEntityCallbacks callbacks = new DefaultReactiveEntityCallbacks();
|
||||
callbacks.addEntityCallback(first);
|
||||
callbacks.addEntityCallback(second);
|
||||
callbacks.addEntityCallback(third);
|
||||
|
||||
PersonDocument initial = new PersonDocument(null, "Walter", null);
|
||||
|
||||
callbacks.callback(CapturingEntityCallback.class, initial) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectError(IllegalArgumentException.class) //
|
||||
.verify();
|
||||
|
||||
assertThat(first.capturedValue()).isSameAs(initial);
|
||||
assertThat(second.capturedValue()).isNotNull().isNotSameAs(initial);
|
||||
assertThat(third.capturedValues()).isEmpty();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MyConfig {
|
||||
|
||||
@Bean
|
||||
MyReactiveBeforeSaveCallback callback() {
|
||||
return new MyReactiveBeforeSaveCallback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface ReactiveBeforeSaveCallback<T> extends EntityCallback<T> {
|
||||
Mono<T> onBeforeSave(T object);
|
||||
}
|
||||
|
||||
static class MyReactiveBeforeSaveCallback implements ReactiveBeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Mono<Person> onBeforeSave(Person object) {
|
||||
|
||||
PersonDocument result = new PersonDocument(object.getFirstName().length(), object.getFirstName(),
|
||||
object.getLastName());
|
||||
|
||||
return Mono.just(result);
|
||||
}
|
||||
}
|
||||
|
||||
static class GenericPersonCallback implements EntityCallback<Person> {
|
||||
|
||||
public Person onBeforeSave(Person value) {
|
||||
|
||||
value.setSsn(value.getFirstName().length());
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* https://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.data.mapping.callback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.data.mapping.Child;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.mapping.PersonDocument;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class EntityCallbackDiscovererUnitTests {
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldDiscoverCallbackType() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
EntityCallbackDiscoverer discoverer = new EntityCallbackDiscoverer(ctx);
|
||||
|
||||
Collection<EntityCallback<Person>> entityCallbacks = discoverer.getEntityCallbacks(PersonDocument.class,
|
||||
ResolvableType.forType(BeforeSaveCallback.class));
|
||||
|
||||
assertThat(entityCallbacks).hasSize(1).element(0).isInstanceOf(MyBeforeSaveCallback.class);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldDiscoverCallbackTypeByName() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
EntityCallbackDiscoverer discoverer = new EntityCallbackDiscoverer(ctx);
|
||||
discoverer.clear();
|
||||
discoverer.addEntityCallbackBean("namedCallback");
|
||||
|
||||
Collection<EntityCallback<Person>> entityCallbacks = discoverer.getEntityCallbacks(PersonDocument.class,
|
||||
ResolvableType.forType(BeforeSaveCallback.class));
|
||||
|
||||
assertThat(entityCallbacks).hasSize(1).element(0).isInstanceOf(MyOtherCallback.class);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldSupportCallbackTypes() {
|
||||
|
||||
EntityCallbackDiscoverer discoverer = new EntityCallbackDiscoverer();
|
||||
|
||||
assertThat(discoverer.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(Person.class))).isTrue();
|
||||
assertThat(discoverer.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(Child.class))).isTrue();
|
||||
assertThat(discoverer.supportsEvent(BeforeSaveCallback.class, ResolvableType.forClass(PersonDocument.class)))
|
||||
.isTrue();
|
||||
|
||||
assertThat(discoverer.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(Object.class))).isFalse();
|
||||
assertThat(discoverer.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(User.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldSupportInstanceCallbackTypes() {
|
||||
|
||||
EntityCallbackDiscoverer discoverer = new EntityCallbackDiscoverer();
|
||||
|
||||
MyBeforeSaveCallback callback = new MyBeforeSaveCallback();
|
||||
|
||||
assertThat(discoverer.supportsEvent(callback, ResolvableType.forClass(Person.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
assertThat(discoverer.supportsEvent(callback, ResolvableType.forClass(Child.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
assertThat(discoverer.supportsEvent(callback, ResolvableType.forClass(PersonDocument.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
assertThat(discoverer.supportsEvent(callback, ResolvableType.forClass(PersonDocument.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
|
||||
assertThat(discoverer.supportsEvent(callback, ResolvableType.forClass(User.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1467
|
||||
public void shouldDispatchInOrder() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(OrderedConfig.class);
|
||||
|
||||
EntityCallbackDiscoverer discoverer = new EntityCallbackDiscoverer(ctx);
|
||||
|
||||
Collection<EntityCallback<Person>> entityCallbacks = discoverer.getEntityCallbacks(PersonDocument.class,
|
||||
ResolvableType.forType(EntityCallback.class));
|
||||
|
||||
assertThat(entityCallbacks).containsExactly(ctx.getBean("callback1", EntityCallback.class),
|
||||
ctx.getBean("callback2", EntityCallback.class), ctx.getBean("callback3", EntityCallback.class),
|
||||
ctx.getBean("callback4", EntityCallback.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MyConfig {
|
||||
|
||||
@Bean
|
||||
MyBeforeSaveCallback callback() {
|
||||
return new MyBeforeSaveCallback();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
Object namedCallback() {
|
||||
return new MyOtherCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class OrderedConfig {
|
||||
|
||||
@Bean
|
||||
EntityCallback<Person> callback4() {
|
||||
|
||||
return (BeforeSaveCallback<Person>) object -> object;
|
||||
}
|
||||
|
||||
@Bean
|
||||
EntityCallback<Person> callback2() {
|
||||
return new Second();
|
||||
}
|
||||
|
||||
@Bean
|
||||
EntityCallback<Person> callback3() {
|
||||
return new Third();
|
||||
}
|
||||
|
||||
@Bean
|
||||
EntityCallback<Person> callback1() {
|
||||
return new First();
|
||||
}
|
||||
|
||||
@Order(3)
|
||||
static class Third implements EntityCallback<Person> {
|
||||
|
||||
public Person beforeSave(Person object) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class Second implements EntityCallback<Person>, Ordered {
|
||||
|
||||
public Person beforeSave(Person object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Order(1)
|
||||
static class First implements EntityCallback<Person> {
|
||||
|
||||
public Person beforeSave(Person object) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface BeforeSaveCallback<T> extends EntityCallback<T> {
|
||||
T onBeforeSave(T object);
|
||||
}
|
||||
|
||||
static class MyBeforeSaveCallback implements BeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
|
||||
object.setSsn(object.getFirstName().length());
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyOtherCallback implements BeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class User {}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* https://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.data.mapping.callback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.mapping.PersonDocument;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ReactiveEntityCallbacks}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ReactiveEntityCallbacksUnitTests {
|
||||
|
||||
@Test
|
||||
public void shouldDispatchCallback() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
ReactiveEntityCallbacks callbacks = new ReactiveEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
Mono<PersonDocument> afterCallback = callbacks.callbackLater(personDocument, ReactiveBeforeSaveCallback.class,
|
||||
ReactiveBeforeSaveCallback::onBeforeSave);
|
||||
|
||||
assertThat(personDocument.getSsn()).isNull();
|
||||
assertThat(afterCallback.block().getSsn()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MyConfig {
|
||||
|
||||
@Bean
|
||||
MyReactiveBeforeSaveCallback callback() {
|
||||
return new MyReactiveBeforeSaveCallback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MyReactiveBeforeSaveCallback implements ReactiveBeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Mono<Person> onBeforeSave(Person object) {
|
||||
|
||||
PersonDocument result = new PersonDocument(object.getFirstName().length(), object.getFirstName(),
|
||||
object.getLastName());
|
||||
|
||||
return Mono.just(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* https://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.data.mapping.callback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.data.mapping.Child;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.mapping.PersonDocument;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SimpleEntityCallbacks}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class SimpleEntityCallbacksUnitTests {
|
||||
|
||||
@Test
|
||||
public void shouldDispatchCallback() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
SimpleEntityCallbacks callbacks = new SimpleEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
PersonDocument afterCallback = callbacks.callback(personDocument, BeforeSaveCallback.class,
|
||||
BeforeSaveCallback::onBeforeSave);
|
||||
|
||||
assertThat(afterCallback.getSsn()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDispatchCallsToLambdaReceivers() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(LambdaConfig.class);
|
||||
|
||||
SimpleEntityCallbacks callbacks = new SimpleEntityCallbacks(ctx);
|
||||
|
||||
PersonDocument personDocument = new PersonDocument(null, "Walter", null);
|
||||
PersonDocument afterCallback = callbacks.callback(personDocument, BeforeSaveCallback.class,
|
||||
BeforeSaveCallback::onBeforeSave);
|
||||
|
||||
assertThat(afterCallback.getSsn()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDiscoverCallbackType() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
SimpleEntityCallbacks callbacks = new SimpleEntityCallbacks(ctx);
|
||||
|
||||
Collection<EntityCallback<?>> entityCallbacks = callbacks.getEntityCallbacks(new PersonDocument(null, null, null),
|
||||
ResolvableType.forType(BeforeSaveCallback.class));
|
||||
|
||||
assertThat(entityCallbacks).hasSize(1).element(0).isInstanceOf(MyBeforeSaveCallback.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDiscoverCallbackTypeByName() {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
|
||||
|
||||
SimpleEntityCallbacks callbacks = new SimpleEntityCallbacks(ctx);
|
||||
callbacks.removeAllCallbacks();
|
||||
callbacks.addEntityCallbackBean("namedCallback");
|
||||
|
||||
Collection<EntityCallback<?>> entityCallbacks = callbacks.getEntityCallbacks(new PersonDocument(null, null, null),
|
||||
ResolvableType.forType(BeforeSaveCallback.class));
|
||||
|
||||
assertThat(entityCallbacks).hasSize(1).element(0).isInstanceOf(MyOtherCallback.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSupportCallbackTypes() {
|
||||
|
||||
SimpleEntityCallbacks callbacks = new SimpleEntityCallbacks();
|
||||
|
||||
assertThat(callbacks.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(Person.class))).isTrue();
|
||||
assertThat(callbacks.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(Child.class))).isTrue();
|
||||
assertThat(callbacks.supportsEvent(BeforeSaveCallback.class, ResolvableType.forClass(PersonDocument.class)))
|
||||
.isTrue();
|
||||
|
||||
assertThat(callbacks.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(Object.class))).isFalse();
|
||||
assertThat(callbacks.supportsEvent(MyBeforeSaveCallback.class, ResolvableType.forClass(User.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSupportInstanceCallbackTypes() {
|
||||
|
||||
SimpleEntityCallbacks callbacks = new SimpleEntityCallbacks();
|
||||
|
||||
MyBeforeSaveCallback callback = new MyBeforeSaveCallback();
|
||||
|
||||
assertThat(callbacks.supportsEvent(callback, ResolvableType.forClass(Person.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
assertThat(callbacks.supportsEvent(callback, ResolvableType.forClass(Child.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
assertThat(callbacks.supportsEvent(callback, ResolvableType.forClass(PersonDocument.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
assertThat(callbacks.supportsEvent(callback, ResolvableType.forClass(PersonDocument.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isTrue();
|
||||
|
||||
assertThat(callbacks.supportsEvent(callback, ResolvableType.forClass(User.class),
|
||||
ResolvableType.forClass(BeforeSaveCallback.class))).isFalse();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MyConfig {
|
||||
|
||||
@Bean
|
||||
MyBeforeSaveCallback callback() {
|
||||
return new MyBeforeSaveCallback();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
Object namedCallback() {
|
||||
return new MyOtherCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class LambdaConfig {
|
||||
|
||||
@Bean
|
||||
BeforeSaveCallback<User> userCallback() {
|
||||
return object -> object;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BeforeSaveCallback<Person> personCallback() {
|
||||
return object -> {
|
||||
object.setSsn(object.getFirstName().length());
|
||||
return object;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static class MyBeforeSaveCallback implements BeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
object.setSsn(object.getFirstName().length());
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyOtherCallback implements BeforeSaveCallback<Person> {
|
||||
|
||||
@Override
|
||||
public Person onBeforeSave(Person object) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static class User {}
|
||||
}
|
||||
Reference in New Issue
Block a user