/*
* Copyright 2011-2017 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.mapping.context;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import groovy.lang.MetaClass;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.data.annotation.Id;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.StringUtils;
/**
* Unit test for {@link AbstractMappingContext}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class AbstractMappingContextUnitTests {
final SimpleTypeHolder holder = SimpleTypeHolder.DEFAULT;
SampleMappingContext context;
@Before
public void setUp() {
context = new SampleMappingContext();
context.setSimpleTypeHolder(holder);
}
@Test
public void doesNotTryToLookupPersistentEntityForLeafProperty() {
PersistentPropertyPath<SamplePersistentProperty> path = context
.getPersistentPropertyPath(PropertyPath.from("name", Person.class));
assertThat(path).isNotNull();
}
@Test(expected = MappingException.class) // DATACMNS-92
public void doesNotAddInvalidEntity() {
context = new SampleMappingContext() {
@Override
@SuppressWarnings("unchecked")
protected <S> BasicPersistentEntity<Object, SamplePersistentProperty> createPersistentEntity(
TypeInformation<S> typeInformation) {
return new BasicPersistentEntity<Object, SamplePersistentProperty>((TypeInformation<Object>) typeInformation) {
@Override
public void verify() {
if (Unsupported.class.isAssignableFrom(getType())) {
throw new MappingException("Unsupported type!");
}
}
};
}
};
try {
context.getPersistentEntity(Unsupported.class);
} catch (MappingException e) {
// expected
}
context.getPersistentEntity(Unsupported.class);
}
@Test
public void registersEntitiesOnInitialization() {
ApplicationContext context = mock(ApplicationContext.class);
SampleMappingContext mappingContext = new SampleMappingContext();
mappingContext.setInitialEntitySet(Collections.singleton(Person.class));
mappingContext.setApplicationEventPublisher(context);
verify(context, times(0)).publishEvent(Mockito.any(ApplicationEvent.class));
mappingContext.afterPropertiesSet();
verify(context, times(1)).publishEvent(Mockito.any(ApplicationEvent.class));
}
@Test // DATACMNS-214
public void returnsNullPersistentEntityForSimpleTypes() {
SampleMappingContext context = new SampleMappingContext();
assertThat(context.getPersistentEntity(String.class)).isEmpty();
}
@Test(expected = IllegalArgumentException.class) // DATACMNS-214
public void rejectsNullValueForGetPersistentEntityOfClass() {
context.getPersistentEntity((Class<?>) null);
}
@Test(expected = IllegalArgumentException.class) // DATACMNS-214
public void rejectsNullValueForGetPersistentEntityOfTypeInformation() {
context.getPersistentEntity((TypeInformation<?>) null);
}
@Test // DATACMNS-228
public void doesNotCreatePersistentPropertyForGroovyMetaClass() {
SampleMappingContext mappingContext = new SampleMappingContext();
mappingContext.initialize();
PersistentEntity<Object, SamplePersistentProperty> entity = mappingContext
.getRequiredPersistentEntity(Sample.class);
assertThat(entity.getPersistentProperty("metaClass")).isNotPresent();
}
@Test // DATACMNS-332
public void usesMostConcreteProperty() {
SampleMappingContext mappingContext = new SampleMappingContext();
PersistentEntity<Object, SamplePersistentProperty> entity = mappingContext
.getRequiredPersistentEntity(Extension.class);
assertThat(entity.getPersistentProperty("foo")).hasValueSatisfying(it -> assertThat(it.isIdProperty()).isTrue());
}
@Test // DATACMNS-345
@SuppressWarnings("rawtypes")
public void returnsEntityForComponentType() {
SampleMappingContext mappingContext = new SampleMappingContext();
PersistentEntity<Object, SamplePersistentProperty> entity = mappingContext
.getRequiredPersistentEntity(Sample.class);
assertThat(entity.getPersistentProperty("persons"))
.hasValueSatisfying(it -> assertThat(mappingContext.getPersistentEntity(it))
.hasValueSatisfying(inner -> assertThat(inner.getType()).isEqualTo(Person.class)));
}
@Test // DATACMNS-380
public void returnsPersistentPropertyPathForDotPath() {
PersistentPropertyPath<SamplePersistentProperty> path = context.getPersistentPropertyPath("persons.name",
Sample.class);
assertThat(path.getLength()).isEqualTo(2);
assertThat(path.getBaseProperty().getName()).isEqualTo("persons");
assertThat(path.getLeafProperty().getName()).isEqualTo("name");
}
@Test(expected = MappingException.class) // DATACMNS-380
public void rejectsInvalidPropertyReferenceWithMappingException() {
context.getPersistentPropertyPath("foo", Sample.class);
}
@Test // DATACMNS-390
public void exposesCopyOfPersistentEntitiesToAvoidConcurrentModificationException() {
SampleMappingContext context = new SampleMappingContext();
context.getPersistentEntity(ClassTypeInformation.MAP);
Iterator<BasicPersistentEntity<Object, SamplePersistentProperty>> iterator = context.getPersistentEntities()
.iterator();
while (iterator.hasNext()) {
context.getPersistentEntity(ClassTypeInformation.SET);
iterator.next();
}
}
@Test // DATACMNS-447
public void shouldReturnNullForSimpleTypesIfInStrictIsEnabled() {
context.setStrict(true);
assertThat(context.getPersistentEntity(Integer.class)).isEmpty();
}
@Test // DATACMNS-462
public void hasPersistentEntityForCollectionPropertiesAfterInitialization() {
context.getPersistentEntity(Sample.class);
assertHasEntityFor(Person.class, context, true);
}
@Test // DATACMNS-479
public void doesNotAddMapImplementationClassesAsPersistentEntity() {
context.getPersistentEntity(Sample.class);
assertHasEntityFor(TreeMap.class, context, false);
}
@Test // DATACMNS-695
public void persistentPropertyPathTraversesGenericTypesCorrectly() {
assertThat(context.getPersistentPropertyPath("field.wrapped.field", Outer.class)).hasSize(3);
}
@Test // DATACMNS-727
public void exposesContextForFailingPropertyPathLookup() {
assertThatExceptionOfType(InvalidPersistentPropertyPath.class)//
.isThrownBy(() -> context.getPersistentPropertyPath("persons.firstname", Sample.class))//
.matches(e -> StringUtils.hasText(e.getMessage()))//
.matches(e -> e.getResolvedPath().equals("persons"))//
.matches(e -> e.getUnresolvableSegment().equals("firstname"))//
.matches(e -> context.getPersistentPropertyPath(e) != null);
}
private static void assertHasEntityFor(Class<?> type, SampleMappingContext context, boolean expected) {
boolean found = false;
for (BasicPersistentEntity<Object, SamplePersistentProperty> entity : context.getPersistentEntities()) {
if (entity.getType().equals(type)) {
found = true;
break;
}
}
if (found != expected) {
fail(String.format("%s to find persistent entity for %s!", expected ? "Expected" : "Did not expect", type));
}
}
class Person {
String name;
}
class Unsupported {
}
class Sample {
MetaClass metaClass;
List<Person> persons;
TreeMap<String, Person> personMap;
}
static class Base {
String foo;
}
static class Extension extends Base {
@Id String foo;
}
static class Outer {
Wrapper<Inner> field;
}
static class Wrapper<T> {
T wrapped;
}
static class Inner {
String field;
}
}