diff --git a/src/main/java/org/springframework/data/annotation/AccessType.java b/src/main/java/org/springframework/data/annotation/AccessType.java new file mode 100644 index 000000000..f73619913 --- /dev/null +++ b/src/main/java/org/springframework/data/annotation/AccessType.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to define how Spring Data shall access values of persistent properties. Can either be {@link Type#FIELD} + * or {@link Type#PROPERTY}. Default is field access. + * + * @author Oliver Gierke + */ +@Documented +@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, }) +@Retention(RetentionPolicy.RUNTIME) +public @interface AccessType { + + /** + * The access type to be used. + * + * @return + */ + Type value(); + + enum Type { + FIELD, PROPERTY; + } +} diff --git a/src/main/java/org/springframework/data/mapping/PersistentEntity.java b/src/main/java/org/springframework/data/mapping/PersistentEntity.java index 3bc2024f4..bb033b218 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/PersistentEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012 the original author or authors. + * Copyright 2011-2014 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. @@ -15,6 +15,8 @@ */ package org.springframework.data.mapping; +import java.lang.annotation.Annotation; + import org.springframework.data.convert.EntityInstantiator; import org.springframework.data.util.TypeInformation; @@ -150,4 +152,12 @@ public interface PersistentEntity> { void doWithAssociations(AssociationHandler

handler); void doWithAssociations(SimpleAssociationHandler handler); + + /** + * Looks up the annotation of the given type on the {@link PersistentEntity}. + * + * @param annotationType must not be {@literal null}. + * @return + */ + A findAnnotation(Class annotationType); } diff --git a/src/main/java/org/springframework/data/mapping/PersistentProperty.java b/src/main/java/org/springframework/data/mapping/PersistentProperty.java index b3b52015e..164b82ac2 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/PersistentProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -31,6 +31,11 @@ import org.springframework.data.util.TypeInformation; */ public interface PersistentProperty

> { + /** + * Returns the {@link PersistentEntity} owning the current {@link PersistentProperty}. + * + * @return + */ PersistentEntity getOwner(); /** @@ -192,6 +197,15 @@ public interface PersistentProperty

> { */ A findAnnotation(Class annotationType); + /** + * Looks up the annotation of the given type on the property and the owning type if no annotation can be found on it. + * Usefull to lookup annotations that can be configured on the type but overridden on an individual property. + * + * @param annotationType must not be {@literal null}. + * @return + */ + A findPropertyOrOwnerAnnotation(Class annotationType); + /** * Returns whether the {@link PersistentProperty} has an annotation of the given type. * @@ -199,4 +213,12 @@ public interface PersistentProperty

> { * @return whether the {@link PersistentProperty} has an annotation of the given type. */ boolean isAnnotationPresent(Class annotationType); + + /** + * Returns whether property access shall be used for reading the property value. This means it will use the getter + * instead of field access. + * + * @return + */ + boolean usePropertyAccess(); } 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 ae8cbef2c..bc05971f0 100644 --- a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -291,8 +291,10 @@ public abstract class AbstractMappingContext descriptors; + private final Map remainingDescriptors; /** * Creates a new {@link PersistentPropertyCreator} for the given {@link PersistentEntity} and * {@link PropertyDescriptor}s. * - * @param entity - * @param descriptors + * @param entity must not be {@literal null}. + * @param descriptors must not be {@literal null}. */ private PersistentPropertyCreator(E entity, Map descriptors) { + + Assert.notNull(entity, "PersistentEntity must not be null!"); + Assert.notNull(descriptors, "PropertyDescriptors must not be null!"); + this.entity = entity; this.descriptors = descriptors; + this.remainingDescriptors = new HashMap(descriptors); } + /* + * (non-Javadoc) + * @see org.springframework.util.ReflectionUtils.FieldCallback#doWith(java.lang.reflect.Field) + */ public void doWith(Field field) { - PropertyDescriptor descriptor = descriptors.get(field.getName()); + String fieldName = field.getName(); ReflectionUtils.makeAccessible(field); + createAndRegisterProperty(field, descriptors.get(fieldName)); + + this.remainingDescriptors.remove(fieldName); + } + + /** + * Adds {@link PersistentProperty} instances for all suitable {@link PropertyDescriptor}s without a backing + * {@link Field}. + * + * @see PersistentPropertyFilter + */ + public void addPropertiesForRemainingDescriptors() { + + for (PropertyDescriptor descriptor : remainingDescriptors.values()) { + if (PersistentPropertyFilter.INSTANCE.matches(descriptor)) { + createAndRegisterProperty(null, descriptor); + } + } + } + + private void createAndRegisterProperty(Field field, PropertyDescriptor descriptor) { + P property = createPersistentProperty(field, descriptor, entity, simpleTypeHolder); if (property.isTransient()) { return; } + if (field == null && !property.usePropertyAccess()) { + return; + } + entity.addPersistentProperty(property); if (property.isAssociation()) { @@ -439,25 +477,25 @@ public abstract class AbstractMappingContext UNMAPPED_FIELDS; + private static final Iterable UNMAPPED_PROPERTIES; static { - Set matches = new HashSet(); - matches.add(new FieldMatch("class", null)); - matches.add(new FieldMatch("this\\$.*", null)); - matches.add(new FieldMatch("metaClass", "groovy.lang.MetaClass")); + Set matches = new HashSet(); + matches.add(new PropertyMatch("class", null)); + matches.add(new PropertyMatch("this\\$.*", null)); + matches.add(new PropertyMatch("metaClass", "groovy.lang.MetaClass")); - UNMAPPED_FIELDS = Collections.unmodifiableCollection(matches); + UNMAPPED_PROPERTIES = Collections.unmodifiableCollection(matches); } /* @@ -470,59 +508,82 @@ public abstract class AbstractMappingContext type) { + + if (namePattern != null && !name.matches(namePattern)) { + return false; + } + + if (typeName != null && !type.getName().equals(typeName)) { + return false; + } + + return true; + } + } } } diff --git a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java index c4b7a1176..f94dd38a4 100644 --- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -16,19 +16,20 @@ package org.springframework.data.mapping.model; import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.annotation.Reference; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; /** * Simple impementation of {@link PersistentProperty}. @@ -38,6 +39,12 @@ import org.springframework.util.Assert; */ public abstract class AbstractPersistentProperty

> implements PersistentProperty

{ + private static final Field CAUSE_FIELD; + + static { + CAUSE_FIELD = ReflectionUtils.findField(Throwable.class, "cause"); + } + protected final String name; protected final PropertyDescriptor propertyDescriptor; protected final TypeInformation information; @@ -50,12 +57,11 @@ public abstract class AbstractPersistentProperty

public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { - Assert.notNull(field); Assert.notNull(simpleTypeHolder); Assert.notNull(owner); - this.name = field.getName(); - this.rawType = field.getType(); + this.name = field == null ? propertyDescriptor.getName() : field.getName(); + this.rawType = field == null ? propertyDescriptor.getPropertyType() : field.getType(); this.information = owner.getTypeInformation().getProperty(this.name); this.propertyDescriptor = propertyDescriptor; this.field = field; @@ -113,18 +119,15 @@ public abstract class AbstractPersistentProperty

public Iterable> getPersistentEntityType() { List> result = new ArrayList>(); - TypeInformation type = getTypeInformation(); - if (isEntity()) { - result.add(type); - } - if (type.isCollectionLike() || isMap()) { TypeInformation nestedType = getTypeInformationIfNotSimpleType(getTypeInformation().getActualType()); if (nestedType != null) { result.add(nestedType); } + } else { + result.add(type); } return result; @@ -209,16 +212,7 @@ public abstract class AbstractPersistentProperty

* @see org.springframework.data.mapping.PersistentProperty#isAssociation() */ public boolean isAssociation() { - if (field.isAnnotationPresent(Reference.class)) { - return true; - } - for (Annotation annotation : field.getDeclaredAnnotations()) { - if (annotation.annotationType().isAnnotationPresent(Reference.class)) { - return true; - } - } - - return false; + return field == null ? false : AnnotationUtils.getAnnotation(field, Reference.class) != null; } public Association

getAssociation() { @@ -291,6 +285,14 @@ public abstract class AbstractPersistentProperty

return information.getActualType().getType(); } + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#usePropertyAccess() + */ + public boolean usePropertyAccess() { + return owner.getType().isInterface() || CAUSE_FIELD.equals(getField()); + } + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) @@ -307,7 +309,8 @@ public abstract class AbstractPersistentProperty

} AbstractPersistentProperty that = (AbstractPersistentProperty) obj; - return this.field.equals(that.field); + + return this.field == null ? this.propertyDescriptor.equals(that.propertyDescriptor) : this.field.equals(that.field); } /* @@ -316,7 +319,7 @@ public abstract class AbstractPersistentProperty

*/ @Override public int hashCode() { - return this.field.hashCode(); + return this.field == null ? this.propertyDescriptor.hashCode() : this.field.hashCode(); } /* @@ -325,6 +328,6 @@ public abstract class AbstractPersistentProperty

*/ @Override public String toString() { - return this.field.toString(); + return this.field == null ? this.propertyDescriptor.toString() : this.field.toString(); } } diff --git a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java index e2233380b..871344c93 100644 --- a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -26,6 +26,8 @@ import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.data.annotation.AccessType; +import org.springframework.data.annotation.AccessType.Type; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Reference; import org.springframework.data.annotation.Transient; @@ -47,6 +49,7 @@ public abstract class AnnotationBasedPersistentProperty

, Annotation> annotationCache = new HashMap, Annotation>(); private Boolean isTransient; + private boolean usePropertyAccess; /** * Creates a new {@link AnnotationBasedPersistentProperty}. @@ -59,7 +62,11 @@ public abstract class AnnotationBasedPersistentProperty

owner, SimpleTypeHolder simpleTypeHolder) { super(field, propertyDescriptor, owner, simpleTypeHolder); + populateAnnotationCache(field); + + AccessType accessType = findPropertyOrOwnerAnnotation(AccessType.class); + this.usePropertyAccess = accessType == null ? false : Type.PROPERTY.equals(accessType.value()); this.value = findAnnotation(Value.class); } @@ -84,21 +91,29 @@ public abstract class AnnotationBasedPersistentProperty

annotationType = annotation.annotationType(); - if (!annotationCache.containsKey(annotationType)) { - annotationCache.put(annotationType, annotation); + if (annotationCache.containsKey(annotationType)) { + throw new MappingException(String.format("Ambiguous mapping! Annotation %s configured " + + "on field %s and one of its accessor methods in class %s!", annotationType.getSimpleName(), + field.getName(), getOwner().getType().getSimpleName())); } + + annotationCache.put(annotationType, annotation); } } @@ -183,7 +198,18 @@ public abstract class AnnotationBasedPersistentProperty

A findPropertyOrOwnerAnnotation(Class annotationType) { + + A annotation = findAnnotation(annotationType); + return annotation == null ? owner.findAnnotation(annotationType) : annotation; } /** @@ -211,6 +237,15 @@ public abstract class AnnotationBasedPersistentProperty

> implement private final Set

properties; private final Set> associations; - private final Map propertyCache = new HashMap(); + private final Map propertyCache; + private final Map, Annotation> annotationCache; private P idProperty; private P versionProperty; @@ -70,8 +73,8 @@ public class BasicPersistentEntity> implement * {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the * entity. * - * @param information must not be {@literal null} - * @param comparator + * @param information must not be {@literal null}. + * @param comparator can be {@literal null}. */ public BasicPersistentEntity(TypeInformation information, Comparator

comparator) { @@ -82,6 +85,9 @@ public class BasicPersistentEntity> implement this.constructor = new PreferredConstructorDiscoverer(information, this).getConstructor(); this.associations = comparator == null ? new HashSet>() : new TreeSet>( new AssociationComparator

(comparator)); + + this.propertyCache = new HashMap(); + this.annotationCache = new HashMap, Annotation>(); } /* @@ -305,6 +311,25 @@ public class BasicPersistentEntity> implement } } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentEntity#findAnnotation(java.lang.Class) + */ + @Override + public A findAnnotation(Class annotationType) { + + A annotation = annotationType.getAnnotation(annotationType); + + if (annotation != null) { + return annotation; + } + + annotation = AnnotationUtils.findAnnotation(getType(), annotationType); + annotationCache.put(annotationType, annotation); + + return annotation; + } + /* (non-Javadoc) * @see org.springframework.data.mapping.MutablePersistentEntity#verify() */ diff --git a/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java b/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java index ad013e2b3..f86576d35 100644 --- a/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java +++ b/src/main/java/org/springframework/data/mapping/model/BeanWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012 by the original author(s). + * Copyright 2011-2014 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. @@ -41,33 +41,24 @@ public class BeanWrapper, T> { * * @param * @param - * @param bean must not be {@literal null} - * @param conversionService + * @param bean must not be {@literal null}. + * @param conversionService can be {@literal null}. * @return */ public static , T> BeanWrapper create(T bean, ConversionService conversionService) { + + Assert.notNull(bean, "Wrapped instance must not be null!"); + return new BeanWrapper(bean, conversionService); } private BeanWrapper(T bean, ConversionService conversionService) { - Assert.notNull(bean); + this.bean = bean; this.conversionService = conversionService; } - /** - * Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a - * {@link ConversionService} is configured. Will use the accessor method of the given {@link PersistentProperty} if it - * has one or field access otherwise. - * - * @param property must not be {@literal null}. - * @param value - */ - public void setProperty(PersistentProperty property, Object value) { - setProperty(property, value, false); - } - /** * Sets the given {@link PersistentProperty} to the given value. Will do type conversion if a * {@link ConversionService} is configured. @@ -78,23 +69,25 @@ public class BeanWrapper, T> { * @throws IllegalAccessException * @throws InvocationTargetException */ - public void setProperty(PersistentProperty property, Object value, boolean fieldAccessOnly) { + public void setProperty(PersistentProperty property, Object value) { Method setter = property.getSetter(); try { - if (fieldAccessOnly || null == setter) { + if (!property.usePropertyAccess()) { + Object valueToSet = getPotentiallyConvertedValue(value, property.getType()); ReflectionUtils.makeAccessible(property.getField()); ReflectionUtils.setField(property.getField(), bean, valueToSet); - return; - } - Class[] paramTypes = setter.getParameterTypes(); - Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]); - ReflectionUtils.makeAccessible(setter); - ReflectionUtils.invokeMethod(setter, bean, valueToSet); + } else if (property.usePropertyAccess() && setter != null) { + + Class[] paramTypes = setter.getParameterTypes(); + Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]); + ReflectionUtils.makeAccessible(setter); + ReflectionUtils.invokeMethod(setter, bean, valueToSet); + } } catch (IllegalStateException e) { throw new MappingException("Could not set object property!", e); @@ -109,7 +102,7 @@ public class BeanWrapper, T> { * @return */ public Object getProperty(PersistentProperty property) { - return getProperty(property, property.getType(), false); + return getProperty(property, property.getType()); } /** @@ -118,20 +111,23 @@ public class BeanWrapper, T> { * @param * @param property must not be {@literal null}. * @param type - * @param fieldAccessOnly * @return */ - public S getProperty(PersistentProperty property, Class type, boolean fieldAccessOnly) { + public S getProperty(PersistentProperty property, Class type) { try { - Object obj; - Field field = property.getField(); + + Object obj = null; Method getter = property.getGetter(); - if (fieldAccessOnly || null == getter) { + if (!property.usePropertyAccess()) { + + Field field = property.getField(); ReflectionUtils.makeAccessible(field); obj = ReflectionUtils.getField(field, bean); - } else { + + } else if (property.usePropertyAccess() && getter != null) { + ReflectionUtils.makeAccessible(getter); obj = ReflectionUtils.invokeMethod(getter, bean); } diff --git a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java index 75b16ca36..bbf1e0a56 100644 --- a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java +++ b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java @@ -24,6 +24,7 @@ import java.lang.reflect.Field; import java.util.Collections; import org.junit.Test; +import org.springframework.data.annotation.Id; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PropertyHandler; @@ -65,6 +66,18 @@ public class AbstractMappingContextIntegrationTests entity = context.getPersistentEntity(InterfaceOnly.class); + + assertThat(entity.getIdProperty(), is(notNullValue())); + } + /** * @see DATACMNS-65 */ @@ -121,7 +134,7 @@ public class AbstractMappingContextIntegrationTests createAssociation() { return null; @@ -381,6 +386,11 @@ public class AbstractPersistentPropertyUnitTests { public boolean isAnnotationPresent(Class annotationType) { return false; } + + @Override + public A findPropertyOrOwnerAnnotation(Class annotationType) { + return null; + } } static class Sample { diff --git a/src/test/java/org/springframework/data/mapping/model/AbstractAnnotationBasedPropertyUnitTests.java b/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java similarity index 68% rename from src/test/java/org/springframework/data/mapping/model/AbstractAnnotationBasedPropertyUnitTests.java rename to src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java index 31a6724f7..2dc0cea8d 100644 --- a/src/test/java/org/springframework/data/mapping/model/AbstractAnnotationBasedPropertyUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2014 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. @@ -27,17 +27,19 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.springframework.data.annotation.AccessType; +import org.springframework.data.annotation.AccessType.Type; import org.springframework.data.annotation.Id; import org.springframework.data.mapping.context.SampleMappingContext; import org.springframework.data.mapping.context.SamplePersistentProperty; -import org.springframework.data.util.ClassTypeInformation; -import org.springframework.data.util.TypeInformation; import org.springframework.test.util.ReflectionTestUtils; /** + * Unit tests for {@link AnnotationBasedPersistentProperty}. + * * @author Oliver Gierke */ -public class AbstractAnnotationBasedPropertyUnitTests

> { +public class AnnotationBasedPersistentPropertyUnitTests

> { BasicPersistentEntity entity; SampleMappingContext context; @@ -49,27 +51,33 @@ public class AbstractAnnotationBasedPropertyUnitTests

, ?> entities = (Map, ?>) ReflectionTestUtils.getField(context, - "persistentEntities"); - assertThat(entities.containsKey(ClassTypeInformation.from(InvalidSample.class)), is(false)); + assertThat(context.hasPersistentEntityFor(InvalidSample.class), is(false)); } } + /** + * @see DATACMNS-243 + */ + @Test + public void defaultsToFieldAccess() { + assertThat(getProperty(FieldAccess.class, "name").usePropertyAccess(), is(false)); + } + + /** + * @see DATACMNS-243 + */ + @Test + public void usesAccessTypeDeclaredOnTypeAsDefault() { + assertThat(getProperty(PropertyAccess.class, "firstname").usePropertyAccess(), is(true)); + } + + /** + * @see DATACMNS-243 + */ + @Test + public void propertyAnnotationOverridesTypeConfiguration() { + assertThat(getProperty(PropertyAccess.class, "lastname").usePropertyAccess(), is(false)); + } + + /** + * @see DATACMNS-243 + */ + @Test + public void fieldAnnotationOverridesTypeConfiguration() { + assertThat(getProperty(PropertyAccess.class, "emailAddress").usePropertyAccess(), is(false)); + } + + /** + * @see DATACMNS-243 + */ + @Test(expected = MappingException.class) + public void detectsAmbiguityCausedByFieldAnAccessorAnnotation() { + context.getPersistentEntity(AnotherInvalidSample.class); + } + @SuppressWarnings("unchecked") private Map, Annotation> getAnnotationCache(SamplePersistentProperty property) { return (Map, Annotation>) ReflectionTestUtils.getField(property, "annotationCache"); @@ -126,22 +171,20 @@ public class AbstractAnnotationBasedPropertyUnitTests

type, String name) { + return context.getPersistentEntity(type).getPersistentProperty(name); + } + static class Sample { - @MyId - String id; + @MyId String id; - @MyAnnotation - String field; + @MyAnnotation String field; String getter; String setter; String doubleMapping; - @MyAnnotationAsMeta - String meta; - - @MyAnnotation("field") - String override; + @MyAnnotationAsMeta String meta; @MyAnnotation public String getGetter() { @@ -153,11 +196,6 @@ public class AbstractAnnotationBasedPropertyUnitTests