From b4df737d20e10ee31a8ff25235d976c952d5273f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Rasi=C5=84ski?= Date: Mon, 19 Jan 2015 16:34:22 +0100 Subject: [PATCH] DATAMONGO-1142 - Subclass Repository returns also Superclass objects. Fixed return type of the find methods used by Repositories. Superclass objects are now not returned from the Subclass repository. --- .../data/mongodb/core/MongoTemplate.java | 8 +- .../core/convert/MappingMongoConverter.java | 23 +++++- .../data/mongodb/repository/Candidate.java | 50 +++++++++++++ .../repository/CandidateRepository.java | 25 +++++++ .../CandidateRepositoryIntegrationTests.java | 75 +++++++++++++++++++ ...rsonRepositoryIntegrationTests-context.xml | 7 +- 6 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Candidate.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepository.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepositoryIntegrationTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index f8f391c3da..61c393d19b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2014 the original author or authors. + * Copyright 2010-2015 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. @@ -131,6 +131,7 @@ * @author Thomas Darimont * @author Chuong Ngo * @author Christoph Strobl + * @author Mateusz Rasiñski */ @SuppressWarnings("deprecation") public class MongoTemplate implements MongoOperations, ApplicationContextAware { @@ -1809,7 +1810,10 @@ private List executeFindMultiInternal(CollectionCallback collec while (cursor.hasNext()) { DBObject object = cursor.next(); - result.add(objectCallback.doWith(object)); + T instantiatedObject = objectCallback.doWith(object); + if (instantiatedObject != null) { + result.add(instantiatedObject); + } } return result; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 876e289a7c..7f46df1006 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 by the original author(s). + * Copyright 2011-2015 by the original author(s). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,6 +74,7 @@ * @author Patrik Wasik * @author Thomas Darimont * @author Christoph Strobl + * @author Mateusz Rasiñski */ public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware, ValueResolver { @@ -221,6 +222,10 @@ private S read(TypeInformation type, DBObject dbo, ObjectP throw new MappingException(String.format(INCOMPATIBLE_TYPES, dbo, BasicDBList.class, typeToUse.getType(), path)); } + if (isTypeSubclassOfDbo(type.getType(), dbo)) { + return null; + } + // Retrieve persistent entity info MongoPersistentEntity persistentEntity = (MongoPersistentEntity) mappingContext .getPersistentEntity(typeToUse); @@ -231,6 +236,22 @@ private S read(TypeInformation type, DBObject dbo, ObjectP return read(persistentEntity, dbo, path); } + private boolean isTypeSubclassOfDbo(Class type, DBObject object) { + TypeInformation typeInformation = typeMapper.readType(object); + if (typeInformation == null) { + return false; + } + Class objectType = typeInformation.getType(); + if (objectType == null) { + return false; + } + return isSubclass(type, objectType); + } + + private boolean isSubclass(Class testedClass, Class possibleSuperclass) { + return !possibleSuperclass.equals(testedClass) && possibleSuperclass.isAssignableFrom(testedClass); + } + private ParameterValueProvider getParameterProvider(MongoPersistentEntity entity, DBObject source, DefaultSpELExpressionEvaluator evaluator, ObjectPath path) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Candidate.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Candidate.java new file mode 100644 index 0000000000..ff6f03a287 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Candidate.java @@ -0,0 +1,50 @@ +/* + * Copyright 2015 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 + * + * http://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.mongodb.repository; + +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * Sample Candidate domain class extending {@link Person}. + * Candidate objects are stored in the {@link Person} collection. + * + * @author Mateusz Rasiñski + */ +@Document(collection = "person") +public class Candidate extends Person { + + private String title; + + public Candidate() { + } + + public Candidate(String firstName, String lastName) { + super(firstName, lastName); + } + + public Candidate(String firstName, String lastName, String title) { + super(firstName, lastName); + this.title = title; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepository.java new file mode 100644 index 0000000000..4a20e7087c --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 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 + * + * http://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.mongodb.repository; + +/** + * Simple repository interface managing {@link Candidate}s. + * + * @author Mateusz Rasiñski + */ +public interface CandidateRepository extends MongoRepository { + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepositoryIntegrationTests.java new file mode 100644 index 0000000000..3d37b90300 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/CandidateRepositoryIntegrationTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2015 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 + * + * http://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.mongodb.repository; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Integration tests for {@link CandidateRepository}. + * + * @author Mateusz Rasiñski + */ +public class CandidateRepositoryIntegrationTests extends PersonRepositoryIntegrationTests { + + @Autowired protected CandidateRepository candidateRepository; + + /** + * @see DATAMONGO-1142 + */ + @Test + public void personRepositoryCanSaveAndFindCandidate() { + Candidate candidate = repository.save(new Candidate("Jan", "Kowalski", "Mr.")); + + Person result = repository.findOne(candidate.getId()); + + assertThat(result, notNullValue()); + assertThat(result, equalTo((Person) candidate)); + assertThat(result, instanceOf(Candidate.class)); + assertThat(((Candidate) result).getTitle(), is("Mr.")); + } + + /** + * @see DATAMONGO-1142 + */ + @Test + public void personRepositoryReturnsAlsoCandidates() { + Candidate candidate = candidateRepository.save(new Candidate("Jan", "Kowalski")); + + List persons = repository.findAll(); + + assertThat(persons, hasSize(greaterThan(1))); + assertThat(persons.contains(candidate), is(true)); + } + + /** + * @see DATAMONGO-1142 + */ + @Test + public void candidateRepositoryReturnsOnlyCandidates() { + Candidate candidate = candidateRepository.save(new Candidate("Jan", "Kowalski")); + + List candidates = candidateRepository.findAll(); + + assertThat(candidates, hasSize(1)); + assertThat(candidates, contains(candidate)); + } +} diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml index 06032c18d1..06488baed7 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml @@ -8,7 +8,7 @@ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - + @@ -28,4 +28,9 @@ + + + + +