From 02578a016877f6cbcadd25fa27fa4b2f0ecd2a20 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 19 Jun 2015 11:50:35 +0200 Subject: [PATCH] DATAMONGO-1157 - Throw meaningful exception when @DbRef is used with unsupported types. We now eagerly check DBRef properties for invalid definitions such as final class or array. In that case we throw a MappingException when verify is called. --- .../mapping/BasicMongoPersistentEntity.java | 30 +++++-- .../BasicMongoPersistentEntityUnitTests.java | 83 +++++++++++++++++++ 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java index 6d814d871..7c56c8c28 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.core.mapping; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -305,28 +306,44 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity { + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PropertyHandler#doWithPersistentProperty(org.springframework.data.mapping.PersistentProperty) + */ @Override public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) { potentiallyAssertTextScoreType(persistentProperty); potentiallyAssertLanguageType(persistentProperty); + potentiallyAssertDBRefTargetType(persistentProperty); } - private void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) { + private static void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) { if (persistentProperty.isExplicitLanguageProperty()) { assertPropertyType(persistentProperty, String.class); } } - private void potentiallyAssertTextScoreType(MongoPersistentProperty persistentProperty) { + private static void potentiallyAssertTextScoreType(MongoPersistentProperty persistentProperty) { if (persistentProperty.isTextScoreProperty()) { assertPropertyType(persistentProperty, Float.class, Double.class); } } - private void assertPropertyType(MongoPersistentProperty persistentProperty, Class... validMatches) { + private static void potentiallyAssertDBRefTargetType(MongoPersistentProperty persistentProperty) { + + if (persistentProperty.isDbReference() && persistentProperty.getDBRef().lazy()) { + if (persistentProperty.isArray() || Modifier.isFinal(persistentProperty.getActualType().getModifiers())) { + throw new MappingException(String.format( + "Invalid lazy DBRef property for %s. Found %s which must not be an array nor a final class.", + persistentProperty.getField(), persistentProperty.getActualType())); + } + } + } + + private static void assertPropertyType(MongoPersistentProperty persistentProperty, Class... validMatches) { for (Class potentialMatch : validMatches) { if (ClassUtils.isAssignable(potentialMatch, persistentProperty.getActualType())) { @@ -334,10 +351,9 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity entity = new BasicMongoPersistentEntity( + ClassTypeInformation.from(AnyDocument.class)); + org.springframework.data.mongodb.core.mapping.DBRef dbRefMock = mock( + org.springframework.data.mongodb.core.mapping.DBRef.class); + when(propertyMock.isDbReference()).thenReturn(true); + when(propertyMock.getDBRef()).thenReturn(dbRefMock); + when(dbRefMock.lazy()).thenReturn(true); + when(propertyMock.getActualType()).thenReturn((Class) Class.class); + entity.addPersistentProperty(propertyMock); + + entity.verify(); + } + + /** + * @see DATAMONGO-1157 + */ + @Test(expected = MappingException.class) + public void verifyShouldThrowErrorForLazyDBRefArray() { + + BasicMongoPersistentEntity entity = new BasicMongoPersistentEntity( + ClassTypeInformation.from(AnyDocument.class)); + org.springframework.data.mongodb.core.mapping.DBRef dbRefMock = mock( + org.springframework.data.mongodb.core.mapping.DBRef.class); + when(propertyMock.isDbReference()).thenReturn(true); + when(propertyMock.getDBRef()).thenReturn(dbRefMock); + when(dbRefMock.lazy()).thenReturn(true); + when(propertyMock.isArray()).thenReturn(true); + entity.addPersistentProperty(propertyMock); + + entity.verify(); + } + + /** + * @see DATAMONGO-1157 + */ + @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void verifyShouldPassForLazyDBRefOnNonArrayNonFinalClass() { + + BasicMongoPersistentEntity entity = new BasicMongoPersistentEntity( + ClassTypeInformation.from(AnyDocument.class)); + org.springframework.data.mongodb.core.mapping.DBRef dbRefMock = mock( + org.springframework.data.mongodb.core.mapping.DBRef.class); + when(propertyMock.isDbReference()).thenReturn(true); + when(propertyMock.getDBRef()).thenReturn(dbRefMock); + when(dbRefMock.lazy()).thenReturn(true); + when(propertyMock.getActualType()).thenReturn((Class) Object.class); + entity.addPersistentProperty(propertyMock); + + entity.verify(); + + verify(propertyMock, times(1)).isDbReference(); + } + + /** + * @see DATAMONGO-1157 + */ + @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void verifyShouldPassForNonLazyDBRefOnFinalClass() { + + BasicMongoPersistentEntity entity = new BasicMongoPersistentEntity( + ClassTypeInformation.from(AnyDocument.class)); + org.springframework.data.mongodb.core.mapping.DBRef dbRefMock = mock( + org.springframework.data.mongodb.core.mapping.DBRef.class); + when(propertyMock.isDbReference()).thenReturn(true); + when(propertyMock.getDBRef()).thenReturn(dbRefMock); + when(dbRefMock.lazy()).thenReturn(false); + when(propertyMock.getActualType()).thenReturn((Class) Class.class); + entity.addPersistentProperty(propertyMock); + + entity.verify(); + + verify(dbRefMock, times(1)).lazy(); + } + @Document(collection = "contacts") class Contact {