diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java
index 76a74ef2..7cfe532d 100644
--- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java
+++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java
@@ -25,6 +25,7 @@ import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import org.springframework.data.gemfire.mapping.MappingPdxSerializer;
/**
* The {@link EnablePdx} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class}
@@ -61,6 +62,18 @@ public @interface EnablePdx {
*/
boolean ignoreUnreadFields() default PdxConfiguration.DEFAULT_IGNORE_UNREAD_FIELDS;
+ /**
+ * When using the Spring Data Geode's (SDG) {@link MappingPdxSerializer} most application domain {@link Class types}
+ * are included for Apache Geode PDX serialization, by default. However, certain {@link Class types} are excluded
+ * by SDG's {@link MappingPdxSerializer}, such as {@literal java.*}, {@literal javax.*}, {@literal com.gemstone.*},
+ * {@literal org.apache.geode.*} and {@literal org.springframework.*} {@link Class types}. This allows the default
+ * behavior to be overridden when and where necessary.
+ *
+ * @return an array of {@link Class types} to be handled by the {@link MappingPdxSerializer}, possibly overriding
+ * the excluded {@link Class types} by default.
+ */
+ Class>[] includeDomainTypes() default {};
+
/**
* Configures whether the type metadata for PDX objects is persisted to disk.
*
diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/PdxConfiguration.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/PdxConfiguration.java
index bf8fe3bc..21ddd673 100644
--- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/PdxConfiguration.java
+++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/config/annotation/PdxConfiguration.java
@@ -16,7 +16,9 @@
package org.springframework.data.gemfire.config.annotation;
import java.lang.annotation.Annotation;
+import java.util.Objects;
import java.util.Optional;
+import java.util.function.Predicate;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.pdx.PdxSerializer;
@@ -36,6 +38,7 @@ import org.springframework.data.gemfire.config.support.PdxDiskStoreAwareBeanFact
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.MappingPdxSerializer;
import org.springframework.data.gemfire.support.NoOpBeanFactoryPostProcessor;
+import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;
@@ -57,6 +60,7 @@ import org.springframework.util.StringUtils;
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.data.gemfire.config.support.PdxDiskStoreAwareBeanFactoryPostProcessor
+ * @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.gemfire.mapping.MappingPdxSerializer
* @see org.springframework.data.gemfire.support.NoOpBeanFactoryPostProcessor
* @since 2.1.0
@@ -76,6 +80,8 @@ public class PdxConfiguration extends AbstractAnnotationConfigSupport implements
private Boolean persistent;
private Boolean readSerialized;
+ private Class>[] includeDomainTypes = {};
+
private String diskStoreName;
private String serializerBeanName;
@@ -106,6 +112,8 @@ public class PdxConfiguration extends AbstractAnnotationConfigSupport implements
? enablePdxAttributes.getBoolean("ignoreUnreadFields")
: DEFAULT_IGNORE_UNREAD_FIELDS));
+ setIncludeDomainTypes(enablePdxAttributes.getClassArray("includeDomainTypes"));
+
setPersistent(resolveProperty(pdxProperty("persistent"),
enablePdxAttributes.containsKey("persistent")
? enablePdxAttributes.getBoolean("persistent")
@@ -139,6 +147,14 @@ public class PdxConfiguration extends AbstractAnnotationConfigSupport implements
return Boolean.TRUE.equals(this.ignoreUnreadFields);
}
+ void setIncludeDomainTypes(Class>[] includeDomainTypes) {
+ this.includeDomainTypes = includeDomainTypes;
+ }
+
+ protected Class>[] getIncludeDomainTypes() {
+ return ArrayUtils.nullSafeArray(this.includeDomainTypes, Class.class);
+ }
+
void setPersistent(Boolean persistent) {
this.persistent = persistent;
}
@@ -189,7 +205,7 @@ public class PdxConfiguration extends AbstractAnnotationConfigSupport implements
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see Geode PDX Serialization
*/
- protected void configurePdx(CacheFactoryBean cacheFactoryBean) {
+ protected void configurePdx(@NonNull CacheFactoryBean cacheFactoryBean) {
getDiskStoreName().ifPresent(cacheFactoryBean::setPdxDiskStoreName);
@@ -240,15 +256,20 @@ public class PdxConfiguration extends AbstractAnnotationConfigSupport implements
* @see org.apache.geode.pdx.PdxSerializer
* @see #getBeanFactory()
*/
- @NonNull
- protected PdxSerializer resolvePdxSerializer() {
+ protected @NonNull PdxSerializer resolvePdxSerializer() {
BeanFactory beanFactory = getBeanFactory();
- return getSerializerBeanName()
+ PdxSerializer serializer = getSerializerBeanName()
.filter(beanFactory::containsBean)
.map(beanName -> beanFactory.getBean(beanName, PdxSerializer.class))
.orElseGet(this::newPdxSerializer);
+
+ if (serializer instanceof MappingPdxSerializer mappingSerializer) {
+ mappingSerializer.setIncludeTypeFilters(buildIncludeTypeFilters());
+ }
+
+ return serializer;
}
/**
@@ -258,11 +279,23 @@ public class PdxConfiguration extends AbstractAnnotationConfigSupport implements
* @return a new instance of {@link PdxSerializer}.
* @see org.apache.geode.pdx.PdxSerializer
*/
- @NonNull
@SuppressWarnings("unchecked")
- protected T newPdxSerializer() {
+ protected @NonNull T newPdxSerializer() {
return (T) MappingPdxSerializer.create(resolveMappingContext().orElse(null),
resolveConversionService().orElse(null));
}
+
+ private @NonNull Predicate> buildIncludeTypeFilters() {
+
+ Predicate> includeTypeFilter = type -> false;
+
+ for (Class> domainType : getIncludeDomainTypes()) {
+ if (Objects.nonNull(domainType)) {
+ includeTypeFilter = includeTypeFilter.or(type -> domainType.isAssignableFrom(type));
+ }
+ }
+
+ return includeTypeFilter;
+ }
}
diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/EnablePdxConfigurationUnitTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/EnablePdxConfigurationUnitTests.java
index dd67a58a..6b40326c 100644
--- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/EnablePdxConfigurationUnitTests.java
+++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/config/annotation/EnablePdxConfigurationUnitTests.java
@@ -33,6 +33,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import com.gemstone.gemfire.TestGemStoneGemFireType;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
@@ -92,6 +94,7 @@ public class EnablePdxConfigurationUnitTests {
annotationAttributes.put("diskStoreName", "MockDiskStore");
annotationAttributes.put("ignoreUnreadFields", Boolean.TRUE);
+ annotationAttributes.put("includeDomainTypes", new Class[] { TestGemStoneGemFireType.class });
annotationAttributes.put("persistent", Boolean.TRUE);
annotationAttributes.put("readSerialized", Boolean.TRUE);
annotationAttributes.put("serializerBeanName", "MockPdxSerializer");
@@ -106,6 +109,7 @@ public class EnablePdxConfigurationUnitTests {
assertThat(this.pdxConfiguration.getBeanFactory()).isEqualTo(mockBeanFactory);
assertThat(this.pdxConfiguration.getDiskStoreName().orElse(null)).isEqualTo("MockDiskStore");
assertThat(this.pdxConfiguration.isIgnoreUnreadFields()).isTrue();
+ assertThat(this.pdxConfiguration.getIncludeDomainTypes()).containsExactly(TestGemStoneGemFireType.class);
assertThat(this.pdxConfiguration.isPersistent()).isTrue();
assertThat(this.pdxConfiguration.isReadSerialized()).isTrue();
assertThat(this.pdxConfiguration.getSerializerBeanName().orElse(null)).isEqualTo("MockPdxSerializer");
@@ -126,6 +130,7 @@ public class EnablePdxConfigurationUnitTests {
assertThat(this.pdxConfiguration.getDiskStoreName().isPresent()).isFalse();
assertThat(this.pdxConfiguration.isIgnoreUnreadFields()).isFalse();
+ assertThat(this.pdxConfiguration.getIncludeDomainTypes()).isEmpty();
assertThat(this.pdxConfiguration.isPersistent()).isFalse();
assertThat(this.pdxConfiguration.isReadSerialized()).isFalse();
assertThat(this.pdxConfiguration.getSerializerBeanName().isPresent()).isFalse();
@@ -168,6 +173,7 @@ public class EnablePdxConfigurationUnitTests {
verify(this.pdxConfiguration, times(1)).getDiskStoreName();
verify(this.pdxConfiguration, times(1)).isIgnoreUnreadFields();
+ verify(this.pdxConfiguration, never()).getIncludeDomainTypes();
verify(this.pdxConfiguration, times(1)).isPersistent();
verify(this.pdxConfiguration, times(1)).isReadSerialized();
verify(this.pdxConfiguration, times(1)).getSerializerBeanName();