SGF-582 - Add support for using bean property "id" as a Region key if @Id annotation is not present.

(cherry picked from commit 3bc7d2e711)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
Gregory Green
2017-01-05 08:50:17 -05:00
committed by John Blum
parent 4da08b04fd
commit 41b335000f
2 changed files with 129 additions and 20 deletions

View File

@@ -19,13 +19,18 @@ package org.springframework.data.gemfire.mapping;
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.IdPropertyIdentifierAccessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
/**
* {@link PersistentEntity} implementation adding custom GemFire persistent entity related metadata, such as the
@@ -33,6 +38,7 @@ import org.springframework.data.util.TypeInformation;
*
* @author Oliver Gierke
* @author John Blum
* @author Gregory Green
* @see org.springframework.data.gemfire.mapping.GemfirePersistentProperty
* @see org.springframework.data.mapping.model.BasicPersistentEntity
*/
@@ -43,12 +49,67 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
private final String regionName;
/**
* GET_ID_METHOD_NAME = "getId" Used to support getting the region key when the @Id annotation does not exist.
*/
private static final String GET_ID_METHOD_NAME = "getId";
/**
* Get the identifier access strategy object that determines the region key to use
*
* @return implementation of the Identifier access strategy with support to use the getId bean method.
*/
@Override
public IdentifierAccessor getIdentifierAccessor(final Object bean) {
Assert.notNull(bean, "Target bean must not be null!");
Assert.isTrue(getType().isInstance(bean), "Target bean is not of type of the persistent entity!");
// Check if @Id access
if (hasIdProperty()) {
return new IdPropertyIdentifierAccessor(this, bean);
}
// use getId() method via a lamba function implementation of IdentifierAccessor
IdentifierAccessor getIdAccessor = new IdentifierAccessor() {
@Override public Object getIdentifier() {
try {
Method getMethod = bean.getClass().getMethod(GET_ID_METHOD_NAME);
if (getMethod == null) {
return null; // getId method not found
}
return getMethod.invoke(bean);
}
catch (NoSuchMethodException e) {
return null;
}
catch (SecurityException e) {
return null;
}
catch (IllegalAccessException e) {
return null;
}
catch (IllegalArgumentException e) {
return null;
}
catch (InvocationTargetException e) {
return null;
}
}
};
return getIdAccessor;
}
/* (non-Javadoc) */
protected static Annotation resolveRegionAnnotation(Class<?> persistentEntityType) {
for (Class<? extends Annotation> regionAnnotationType : Region.REGION_ANNOTATION_TYPES) {
Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation(
persistentEntityType, regionAnnotationType);
Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation(persistentEntityType,
regionAnnotationType);
if (regionAnnotation != null) {
return regionAnnotation;
@@ -61,8 +122,9 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
/* (non-Javadoc) */
protected static String resolveRegionName(Class<?> persistentEntityType, Annotation regionAnnotation) {
String regionName = (regionAnnotation != null ? AnnotationAttributes.fromMap(
AnnotationUtils.getAnnotationAttributes(regionAnnotation)).getString("value") : null);
String regionName = (regionAnnotation != null
? AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(regionAnnotation)).getString("value")
: null);
return defaultIfEmpty(regionName, persistentEntityType.getSimpleName());
}
@@ -82,10 +144,11 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
}
/**
* Returns the {@link Region} annotation used to annotate this {@link PersistentEntity} or {@literal null}
* if this {@link PersistentEntity} was not annotated with a {@link Region} annotation.
* Returns the {@link Region} annotation used to annotate this {@link PersistentEntity} or {@literal null} if this
* {@link PersistentEntity} was not annotated with a {@link Region} annotation.
*
* @param <T> concrete {@link Class} type of the Region {@link Annotation}.
<<<<<<< HEAD
* @return the {@link Region} annotation used to annotate this {@link PersistentEntity} or {@literal null}
* if this {@link PersistentEntity} was not annotated with a {@link Region} annotation.
* @see org.springframework.data.gemfire.mapping.ClientRegion
@@ -93,6 +156,15 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
* @see org.springframework.data.gemfire.mapping.PartitionRegion
* @see org.springframework.data.gemfire.mapping.ReplicateRegion
* @see org.springframework.data.gemfire.mapping.Region
=======
* @return the {@link Region} annotation used to annotate this {@link PersistentEntity} or {@literal null} if this
* {@link PersistentEntity} was not annotated with a {@link Region} annotation.
* @see ClientRegion
* @see LocalRegion
* @see PartitionRegion
* @see ReplicateRegion
* @see Region
>>>>>>> 3bc7d2e... SGF-582 - Add support for using bean property "id" as a Region key if @Id annotation is not present.
* @see java.lang.annotation.Annotation
*/
@SuppressWarnings("unchecked")
@@ -101,11 +173,11 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
}
/**
* Returns the {@link Class} type of the Region {@link Annotation} or {@literal null}
* if this {@link PersistentEntity} was not annotated with a Region {@link Annotation}.
* Returns the {@link Class} type of the Region {@link Annotation} or {@literal null} if this {@link PersistentEntity}
* was not annotated with a Region {@link Annotation}.
*
* @return the {@link Class} type of the Region {@link Annotation} or {@literal null}
* if this {@link PersistentEntity} was not annotated with a Region {@link Annotation}.
* @return the {@link Class} type of the Region {@link Annotation} or {@literal null} if this {@link PersistentEntity}
* was not annotated with a Region {@link Annotation}.
* @see java.lang.annotation.Annotation#annotationType()
* @see #getRegionAnnotation()
*/

View File

@@ -23,13 +23,17 @@ import static org.junit.Assert.assertThat;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.util.ClassTypeInformation;
import lombok.Data;
/**
* Unit tests for {@link GemfirePersistentEntity}.
*
*
* @author Oliver Gierke
* @author John Blum
*/
@@ -39,6 +43,36 @@ public class GemfirePersistentEntityUnitTests {
return new GemfireMappingContext();
}
/**
* JIRA ticket SGF-582
*
* Used an object's getId method if the @Id does not exists
*/
@Test
public void supportsGetId() {
GemfirePersistentEntity<UnannotatedRegion> unnamedRegionEntity = new GemfirePersistentEntity<UnannotatedRegion>(
ClassTypeInformation.from(UnannotatedRegion.class));
IdentifierAccessor accessor = unnamedRegionEntity.getIdentifierAccessor(new UnannotatedRegion());
Assert.assertNull(accessor.getIdentifier());
GemfirePersistentEntity<NotAnnotationIdRegion> entity = new GemfirePersistentEntity<NotAnnotationIdRegion>(
ClassTypeInformation.from(NotAnnotationIdRegion.class));
NotAnnotationIdRegion region = new NotAnnotationIdRegion();
region.setId("id");
region.setValue("value");
accessor = entity.getIdentifierAccessor(region);
Assert.assertNotNull(accessor.getIdentifier());
Assert.assertEquals("id", accessor.getIdentifier());
}
@Test
public void defaultsRegionNameToClassName() {
GemfirePersistentEntity<UnannotatedRegion> entity = new GemfirePersistentEntity<UnannotatedRegion>(
@@ -64,8 +98,8 @@ public class GemfirePersistentEntityUnitTests {
@Test
@SuppressWarnings("unchecked")
public void bigDecimalPersistentPropertyIsNotEntity() {
GemfirePersistentEntity<ExampleDomainObject> entity = (GemfirePersistentEntity<ExampleDomainObject>)
getMappingContext().getPersistentEntity(ExampleDomainObject.class);
GemfirePersistentEntity<ExampleDomainObject> entity = (GemfirePersistentEntity<ExampleDomainObject>) getMappingContext()
.getPersistentEntity(ExampleDomainObject.class);
assertThat(entity.getRegionName(), is(equalTo("Example")));
@@ -78,8 +112,8 @@ public class GemfirePersistentEntityUnitTests {
@Test
@SuppressWarnings("unchecked")
public void bigIntegerPersistentPropertyIsNotEntity() {
GemfirePersistentEntity<ExampleDomainObject> entity = (GemfirePersistentEntity<ExampleDomainObject>)
getMappingContext().getPersistentEntity(ExampleDomainObject.class);
GemfirePersistentEntity<ExampleDomainObject> entity = (GemfirePersistentEntity<ExampleDomainObject>) getMappingContext()
.getPersistentEntity(ExampleDomainObject.class);
assertThat(entity.getRegionName(), is(equalTo("Example")));
@@ -89,15 +123,18 @@ public class GemfirePersistentEntityUnitTests {
assertThat(bigNumber.isEntity(), is(false));
}
static class UnannotatedRegion {
}
static class UnannotatedRegion {}
@Region("Foo")
static class AnnotatedRegion {
}
static class AnnotatedRegion {}
@Region
static class UnnamedRegion {
static class UnnamedRegion {}
static @Data class NotAnnotationIdRegion {
private String value;
private String id;
}
@Region("Example")