Skip to content

Commit c42f5ef

Browse files
committed
DATACMNS-1547 - Properly remove partially populated PersistentEntity instances from cache.
We now remove partially populated PersistentEntity instances from the cache held in AbstractMappingContext as the creation could fail for other RuntimeExceptions other than a MappingException and we wouldn't want to keep the instances around in any case. Slight refactorings in the unit tests so that we can easily create MappingContext instances that reject certain types with certain exceptions.
1 parent 3e41d93 commit c42f5ef

File tree

2 files changed

+78
-24
lines changed

2 files changed

+78
-24
lines changed

src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ protected Optional<E> addPersistentEntity(TypeInformation<?> typeInformation) {
380380
entity.setPersistentPropertyAccessorFactory(persistentPropertyAccessorFactory);
381381
}
382382

383-
} catch (MappingException e) {
383+
} catch (RuntimeException e) {
384384
persistentEntities.remove(typeInformation);
385385
throw e;
386386
}

src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java

+77-23
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,26 @@
1616
package org.springframework.data.mapping.context;
1717

1818
import static org.assertj.core.api.Assertions.*;
19+
import static org.mockito.ArgumentMatchers.*;
1920
import static org.mockito.Mockito.*;
2021

2122
import groovy.lang.MetaClass;
23+
import lombok.AccessLevel;
24+
import lombok.EqualsAndHashCode;
25+
import lombok.RequiredArgsConstructor;
26+
import lombok.Value;
2227

2328
import java.time.LocalDateTime;
29+
import java.util.Arrays;
30+
import java.util.Collection;
2431
import java.util.Collections;
2532
import java.util.Iterator;
2633
import java.util.List;
2734
import java.util.TreeMap;
35+
import java.util.function.Supplier;
2836

2937
import org.junit.Before;
3038
import org.junit.Test;
31-
3239
import org.springframework.context.ApplicationContext;
3340
import org.springframework.context.ApplicationEvent;
3441
import org.springframework.data.annotation.Id;
@@ -60,29 +67,10 @@ public void setUp() {
6067
@Test // DATACMNS-92
6168
public void doesNotAddInvalidEntity() {
6269

63-
context = new SampleMappingContext() {
64-
@Override
65-
@SuppressWarnings("unchecked")
66-
protected <S> BasicPersistentEntity<Object, SamplePersistentProperty> createPersistentEntity(
67-
TypeInformation<S> typeInformation) {
68-
return new BasicPersistentEntity<Object, SamplePersistentProperty>((TypeInformation<Object>) typeInformation) {
69-
@Override
70-
public void verify() {
71-
if (Unsupported.class.isAssignableFrom(getType())) {
72-
throw new MappingException("Unsupported type!");
73-
}
74-
}
75-
};
76-
}
77-
};
78-
79-
try {
80-
context.getPersistentEntity(Unsupported.class);
81-
} catch (MappingException e) {
82-
// expected
83-
}
70+
context = TypeRejectingMappingContext.rejecting(() -> new MappingException("Not supported!"), Unsupported.class);
8471

85-
assertThatExceptionOfType(MappingException.class).isThrownBy(() -> context.getPersistentEntity(Unsupported.class));
72+
assertThatExceptionOfType(MappingException.class) //
73+
.isThrownBy(() -> context.getPersistentEntity(Unsupported.class));
8674
}
8775

8876
@Test
@@ -213,6 +201,21 @@ public void doesNotReturnPersistentEntityForCustomSimpleTypeProperty() {
213201
assertThat(context.getPersistentEntity(property)).isNull();
214202
}
215203

204+
@Test // DATACMNS-1574
205+
public void cleansUpCacheForRuntimeException() {
206+
207+
TypeRejectingMappingContext context = TypeRejectingMappingContext.rejecting(() -> new RuntimeException(),
208+
Unsupported.class);
209+
210+
assertThatExceptionOfType(RuntimeException.class) //
211+
.isThrownBy(() -> context.getPersistentEntity(Unsupported.class));
212+
213+
// Second lookup still throws the exception as the temporarily created entity was not cached
214+
215+
assertThatExceptionOfType(RuntimeException.class) //
216+
.isThrownBy(() -> context.getPersistentEntity(Unsupported.class));
217+
}
218+
216219
private static void assertHasEntityFor(Class<?> type, SampleMappingContext context, boolean expected) {
217220

218221
boolean found = false;
@@ -252,4 +255,55 @@ static class Base {
252255
static class Extension extends Base {
253256
@Id String foo;
254257
}
258+
259+
/**
260+
* Extension of {@link SampleMappingContext} to reject the creation of certain types with a configurable exception.
261+
*
262+
* @author Oliver Drotbohm
263+
*/
264+
@Value
265+
@EqualsAndHashCode(callSuper = false)
266+
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
267+
private static class TypeRejectingMappingContext extends SampleMappingContext {
268+
269+
Supplier<? extends RuntimeException> exception;
270+
Collection<Class<?>> rejectedTypes;
271+
272+
/**
273+
* Creates a new {@link TypeRejectingMappingContext} producing the given exceptions if any of the given types is
274+
* encountered.
275+
*
276+
* @param <T>
277+
* @param exception must not be {@literal null}.
278+
* @param types must not be {@literal null}.
279+
* @return
280+
*/
281+
public static <T extends RuntimeException> TypeRejectingMappingContext rejecting(Supplier<T> exception,
282+
Class<?>... types) {
283+
return new TypeRejectingMappingContext(exception, Arrays.asList(types));
284+
}
285+
286+
/*
287+
* (non-Javadoc)
288+
* @see org.springframework.data.mapping.context.SampleMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
289+
*/
290+
@Override
291+
protected <S> BasicPersistentEntity<Object, SamplePersistentProperty> createPersistentEntity(
292+
TypeInformation<S> typeInformation) {
293+
294+
return new BasicPersistentEntity<Object, SamplePersistentProperty>((TypeInformation<Object>) typeInformation) {
295+
296+
/*
297+
* (non-Javadoc)
298+
* @see org.springframework.data.mapping.model.BasicPersistentEntity#verify()
299+
*/
300+
@Override
301+
public void verify() {
302+
if (rejectedTypes.stream().anyMatch(it -> it.isAssignableFrom(getType()))) {
303+
throw exception.get();
304+
}
305+
}
306+
};
307+
}
308+
}
255309
}

0 commit comments

Comments
 (0)