From bb89e2bdb64880d1d1763e73fd6cffd059b9163b Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 5 Oct 2015 22:04:16 -0700 Subject: [PATCH] SGF-429 - GemfirePersistentProperty considers a BigDecimal property an entity. Additional changes and refactoring inspired by Spring Data MongoDB custom SimpleTypeHolder. (cherry picked from commit 2344eb521df7326b06740c5196eeea4669c9349e) Signed-off-by: John Blum --- .../mapping/GemfireMappingContext.java | 13 +++ .../mapping/GemfirePersistentProperty.java | 8 +- .../model/GemfireSimpleTypeHolder.java | 11 +++ .../IndexConflictsIntegrationTest.java | 2 +- .../data/gemfire/IndexFactoryBeanTest.java | 4 +- .../mapping/GemfireMappingContextTest.java | 90 +++++++++++++++++++ 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/springframework/data/gemfire/mapping/GemfireMappingContextTest.java diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java index b111c3ef..eeef2a68 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfireMappingContext.java @@ -18,6 +18,7 @@ package org.springframework.data.gemfire.mapping; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; +import org.springframework.data.gemfire.mapping.model.GemfireSimpleTypeHolder; import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; @@ -30,6 +31,18 @@ import org.springframework.data.util.TypeInformation; public class GemfireMappingContext extends AbstractMappingContext, GemfirePersistentProperty> { + /** + * Constructs a GemfireMappingContext with a GemfireSimpleTypeHolder. + * + * @see org.springframework.data.gemfire.mapping.model.GemfireSimpleTypeHolder + */ + public GemfireMappingContext() { + // Technically, the following call is not Thread-safe (the "this" reference escapes), but then MappingContext + // makes no Thread-safety guarantees, even though, most likely, and especially in GemFire's case, + // the MappingContext will be used in a highly concurrent context (modeled after SD MongoDB for consistency)! + setSimpleTypeHolder(new GemfireSimpleTypeHolder()); + } + /* * (non-Javadoc) * @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation) diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java index bb66606d..b554b104 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentProperty.java @@ -32,6 +32,12 @@ import org.springframework.data.mapping.model.SimpleTypeHolder; */ public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty { + /* (non-Javadoc) */ + private static SimpleTypeHolder resolveSimpleTypeHolder(SimpleTypeHolder source) { + return (source instanceof GemfireSimpleTypeHolder ? source + : (source != null ? new GemfireSimpleTypeHolder(source) : new GemfireSimpleTypeHolder())); + } + /** * Constructs an instance of the GemfirePersistentProperty with entity information. * @@ -42,7 +48,7 @@ public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty */ public GemfirePersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { - super(field, propertyDescriptor, owner, new GemfireSimpleTypeHolder(simpleTypeHolder)); + super(field, propertyDescriptor, owner, resolveSimpleTypeHolder(simpleTypeHolder)); } /* diff --git a/src/main/java/org/springframework/data/gemfire/mapping/model/GemfireSimpleTypeHolder.java b/src/main/java/org/springframework/data/gemfire/mapping/model/GemfireSimpleTypeHolder.java index f046a7f4..58286709 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/model/GemfireSimpleTypeHolder.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/model/GemfireSimpleTypeHolder.java @@ -34,6 +34,8 @@ import org.springframework.data.mapping.model.SimpleTypeHolder; @SuppressWarnings("unused") public class GemfireSimpleTypeHolder extends SimpleTypeHolder { + private static final boolean REGISTER_DEFAULTS = true; + protected static final Set> CUSTOM_SIMPLE_TYPES = new HashSet>(2); static { @@ -41,6 +43,15 @@ public class GemfireSimpleTypeHolder extends SimpleTypeHolder { CUSTOM_SIMPLE_TYPES.add(BigInteger.class); } + /** + * Constructs an instance of GemfireSimpleTypeHolder initialized with additional, custom simple types + * handled by GemFire along with register the default simple types. + * @see org.springframework.data.mapping.model.SimpleTypeHolder(Set, boolean) + */ + public GemfireSimpleTypeHolder() { + super(CUSTOM_SIMPLE_TYPES, REGISTER_DEFAULTS); + } + /** * Constructs an instance of the GemfireSimpleTypeHolder initialized with a source {@link SimpleTypeHolder}. * diff --git a/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java index 4b385729..a9b9e2ce 100644 --- a/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/IndexConflictsIntegrationTest.java @@ -89,7 +89,7 @@ public class IndexConflictsIntegrationTest { } catch (BeanCreationException expected) { assertThat(expected.getMessage(), containsString("Error creating bean with name 'customerIdentityIndex'" - + " defined in org.springframework.data.gemfire.IndexConflictsIntegrationTest$IndexDefinitionConflictGemFireConfiguration:" + + " defined in class org.springframework.data.gemfire.IndexConflictsIntegrationTest$IndexDefinitionConflictGemFireConfiguration:" + " Invocation of init method failed")); assertThat(expected.getCause(), is(instanceOf(GemfireIndexException.class))); assertThat(expected.getCause().getMessage(), diff --git a/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java index 94ed59f3..60c941ad 100644 --- a/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/IndexFactoryBeanTest.java @@ -143,7 +143,7 @@ public class IndexFactoryBeanTest { indexFactoryBean.afterPropertiesSet(); } catch (IllegalArgumentException expected) { - assertEquals("A QueryService is required for Index creation!", expected.getMessage()); + assertEquals("QueryService is required to create an Index", expected.getMessage()); throw expected; } } @@ -164,7 +164,7 @@ public class IndexFactoryBeanTest { indexFactoryBean.afterPropertiesSet(); } catch (IllegalArgumentException expected) { - assertEquals("The Index 'expression' is required!", expected.getMessage()); + assertEquals("Index 'expression' is required", expected.getMessage()); throw expected; } } diff --git a/src/test/java/org/springframework/data/gemfire/mapping/GemfireMappingContextTest.java b/src/test/java/org/springframework/data/gemfire/mapping/GemfireMappingContextTest.java new file mode 100644 index 00000000..86f0fa4c --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/mapping/GemfireMappingContextTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2013 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.gemfire.mapping; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.junit.Test; +import org.springframework.data.gemfire.TestUtils; +import org.springframework.data.gemfire.mapping.model.GemfireSimpleTypeHolder; +import org.springframework.data.mapping.PersistentEntity; + +/** + * The GemfireMappingContextTest class is a test suite of test cases testing the contract and functionality + * of the GemfireMappingContext class. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.data.gemfire.mapping.GemfireMappingContext + * @since 1.6.3 + */ +public class GemfireMappingContextTest { + + private GemfireMappingContext mappingContext = new GemfireMappingContext(); + + @Test + @SuppressWarnings("unchecked") + public void getPersistentEntityForPerson() throws Exception { + GemfirePersistentEntity personPersistentEntity = (GemfirePersistentEntity) + mappingContext.getPersistentEntity(Person.class); + + assertThat(personPersistentEntity, is(notNullValue())); + assertThat(personPersistentEntity.getRegionName(), is(equalTo("People"))); + + GemfirePersistentProperty namePersistentProperty = personPersistentEntity.getPersistentProperty("name"); + + assertThat(namePersistentProperty, is(notNullValue())); + assertThat(namePersistentProperty.isEntity(), is(false)); + assertThat(namePersistentProperty.getName(), is(equalTo("name"))); + assertThat(namePersistentProperty.getOwner(), is(equalTo((PersistentEntity) personPersistentEntity))); + assertThat(TestUtils.readField("simpleTypeHolder", namePersistentProperty), is(instanceOf( + GemfireSimpleTypeHolder.class))); + } + + @Test + public void getPersistentEntityForBigDecimal() { + assertThat(mappingContext.getPersistentEntity(BigDecimal.class), is(nullValue())); + } + + @Test + public void getPersistentEntityForBigInteger() { + assertThat(mappingContext.getPersistentEntity(BigInteger.class), is(nullValue())); + } + + @Region("People") + class Person { + + private String name; + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + } + +}