From c42f5efe0185ce30d2ff79c1de2d01002bb00f28 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 30 Aug 2019 12:11:55 +0200 Subject: [PATCH] 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. --- .../context/AbstractMappingContext.java | 2 +- .../AbstractMappingContextUnitTests.java | 100 ++++++++++++++---- 2 files changed, 78 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java index fb2c92600..806179ada 100644 --- a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -380,7 +380,7 @@ public abstract class AbstractMappingContext BasicPersistentEntity createPersistentEntity( - TypeInformation typeInformation) { - return new BasicPersistentEntity((TypeInformation) typeInformation) { - @Override - public void verify() { - if (Unsupported.class.isAssignableFrom(getType())) { - throw new MappingException("Unsupported type!"); - } - } - }; - } - }; + context = TypeRejectingMappingContext.rejecting(() -> new MappingException("Not supported!"), Unsupported.class); - try { - context.getPersistentEntity(Unsupported.class); - } catch (MappingException e) { - // expected - } - - assertThatExceptionOfType(MappingException.class).isThrownBy(() -> context.getPersistentEntity(Unsupported.class)); + assertThatExceptionOfType(MappingException.class) // + .isThrownBy(() -> context.getPersistentEntity(Unsupported.class)); } @Test @@ -213,6 +201,21 @@ public class AbstractMappingContextUnitTests { assertThat(context.getPersistentEntity(property)).isNull(); } + @Test // DATACMNS-1574 + public void cleansUpCacheForRuntimeException() { + + TypeRejectingMappingContext context = TypeRejectingMappingContext.rejecting(() -> new RuntimeException(), + Unsupported.class); + + assertThatExceptionOfType(RuntimeException.class) // + .isThrownBy(() -> context.getPersistentEntity(Unsupported.class)); + + // Second lookup still throws the exception as the temporarily created entity was not cached + + assertThatExceptionOfType(RuntimeException.class) // + .isThrownBy(() -> context.getPersistentEntity(Unsupported.class)); + } + private static void assertHasEntityFor(Class type, SampleMappingContext context, boolean expected) { boolean found = false; @@ -252,4 +255,55 @@ public class AbstractMappingContextUnitTests { static class Extension extends Base { @Id String foo; } + + /** + * Extension of {@link SampleMappingContext} to reject the creation of certain types with a configurable exception. + * + * @author Oliver Drotbohm + */ + @Value + @EqualsAndHashCode(callSuper = false) + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + private static class TypeRejectingMappingContext extends SampleMappingContext { + + Supplier exception; + Collection> rejectedTypes; + + /** + * Creates a new {@link TypeRejectingMappingContext} producing the given exceptions if any of the given types is + * encountered. + * + * @param + * @param exception must not be {@literal null}. + * @param types must not be {@literal null}. + * @return + */ + public static TypeRejectingMappingContext rejecting(Supplier exception, + Class... types) { + return new TypeRejectingMappingContext(exception, Arrays.asList(types)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.context.SampleMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation) + */ + @Override + protected BasicPersistentEntity createPersistentEntity( + TypeInformation typeInformation) { + + return new BasicPersistentEntity((TypeInformation) typeInformation) { + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.model.BasicPersistentEntity#verify() + */ + @Override + public void verify() { + if (rejectedTypes.stream().anyMatch(it -> it.isAssignableFrom(getType()))) { + throw exception.get(); + } + } + }; + } + } }