From bca6ca8a7a970db3c9bc4b9f19fa6e5a3a9a4ede Mon Sep 17 00:00:00 2001 From: John Blum Date: Fri, 8 Jun 2018 13:14:03 -0700 Subject: [PATCH] SGF-756 - Add ability to declare include filters in addition to exclude filters on o.s.d.g.mapping.MappingPdxSerializer. Additionally, o.s.d.g.mapping.MappingPdxSerializer will filter Null types, Apache Geode types, GemStone GemFire types, Java types and Spring Framework types by default. --- .../gemfire/mapping/MappingPdxSerializer.java | 209 ++++++++++++++---- .../gemfire/TestGemStoneGemFireType.java | 31 +++ .../MappingPdxSerializerUnitTests.java | 201 ++++++++++++----- 3 files changed, 334 insertions(+), 107 deletions(-) create mode 100644 src/test/java/com/gemstone/gemfire/TestGemStoneGemFireType.java diff --git a/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java b/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java index 47265b7c..e02113b0 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/MappingPdxSerializer.java @@ -15,9 +15,14 @@ */ package org.springframework.data.gemfire.mapping; +import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import org.apache.geode.pdx.PdxReader; @@ -61,6 +66,7 @@ import org.springframework.util.ObjectUtils; * @see org.springframework.core.convert.ConversionService * @see org.springframework.data.convert.EntityInstantiator * @see org.springframework.data.convert.EntityInstantiators + * @see org.springframework.data.gemfire.util.Filter * @see org.springframework.data.mapping.PersistentEntity * @see org.springframework.data.mapping.PersistentProperty * @see org.springframework.data.mapping.PersistentPropertyAccessor @@ -70,8 +76,10 @@ import org.springframework.util.ObjectUtils; */ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAware { + protected static final String JAVA_PACKAGE_NAME = "java"; protected static final String COM_GEMSTONE_GEMFIRE_PACKAGE_NAME = "com.gemstone.gemfire"; protected static final String ORG_APACHE_GEODE_PACKAGE_NAME = "org.apache.geode"; + protected static final String ORG_SPRINGFRAMEWORK_PACKAGE_NAME = "org.springframework"; /** * Factory method used to construct a new instance of {@link MappingPdxSerializer} initialized with @@ -190,15 +198,21 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw private final GemfireMappingContext mappingContext; + private final List pdxSerializerResolvers = new CopyOnWriteArrayList<>(); + private final Logger logger = LoggerFactory.getLogger(getClass()); - private Map customPdxSerializers; + private final Map customPdxSerializers = new ConcurrentHashMap<>(); - private Predicate> typeFilters = TypeFilters.EXCLUDE_NULL_TYPES + private Predicate> excludeTypeFilters = TypeFilters.EXCLUDE_NULL_TYPES + .and(TypeFilters.EXCLUDE_JAVA_TYPES) .and(TypeFilters.EXCLUDE_COM_GEMSTONE_GEMFIRE_TYPES) - .and(TypeFilters.EXCLUDE_ORG_APACHE_GEODE_TYPES); + .and(TypeFilters.EXCLUDE_ORG_APACHE_GEODE_TYPES) + .and(TypeFilters.EXCLUDE_ORG_SPRINGFRAMEWORK_TYPES); - // TODO: decide what to do with this; SpELContext is not used + private Predicate> includeTypeFilters = TypeFilters.EXCLUDE_ALL_TYPES; + + // TODO remove? SpELContext is not used private SpELContext spelContext; /** @@ -233,7 +247,13 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw this.mappingContext = mappingContext; this.conversionService = conversionService; this.entityInstantiators = new EntityInstantiators(); - this.customPdxSerializers = Collections.emptyMap(); + + this.pdxSerializerResolvers.addAll(Arrays.asList( + PdxSerializerResolvers.PROPERTY, + PdxSerializerResolvers.PROPERTY_NAME, + PdxSerializerResolvers.PROPERTY_TYPE + )); + this.spelContext = new SpELContext(PdxReaderPropertyAccessor.INSTANCE); } @@ -270,11 +290,8 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw * @see org.apache.geode.pdx.PdxSerializer * @see java.util.Map */ - public void setCustomPdxSerializers(@NonNull Map customPdxSerializers) { - - Assert.notNull(customPdxSerializers, "Custom PdxSerializers must not be null"); - - this.customPdxSerializers = customPdxSerializers; + public void setCustomPdxSerializers(Map customPdxSerializers) { + Optional.ofNullable(customPdxSerializers).ifPresent(this.customPdxSerializers::putAll); } /** @@ -322,27 +339,11 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw Map customPdxSerializers = getCustomPdxSerializers(); - PdxSerializer customPdxSerializer = customPdxSerializers.get(property); - - customPdxSerializer = customPdxSerializer != null ? customPdxSerializer - : customPdxSerializers.get(toFullyQualifiedPropertyName(property)); - - customPdxSerializer = customPdxSerializer != null ? customPdxSerializer - : customPdxSerializers.get(property.getType()); - - return customPdxSerializer; - } - - /** - * Converts the entity {@link PersistentProperty} to a {@link String fully-qualified property name}. - * - * @param property {@link PersistentProperty} of the entity. - * @return the {@link String fully-qualified property name of the entity {@link PersistentProperty}. - * @see org.springframework.data.mapping.PersistentProperty - */ - @NonNull - String toFullyQualifiedPropertyName(@NonNull PersistentProperty property) { - return property.getOwner().getType().getName().concat(".").concat(property.getName()); + return this.pdxSerializerResolvers.stream() + .map(it -> it.resolve(customPdxSerializers, property)) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); } /** @@ -454,19 +455,41 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw } /** - * Sets the {@link Predicate type filters} used to filter {@link Class types} serializable + * Sets the {@link Predicate type filters} used to exclude (a.k.a. filter) {@link Class types} serializable * by this {@link MappingPdxSerializer PDX serializer}. * - * This operation is null-safe and rather than overriding the existing {@link Predicate type filters}, - * this set operation combines the given {@link Predicate type filters} with - * the exiting {@link Predicate type filters} joined by {@literal and}. + * This operation is null-safe and rather than overriding the existing {@link Predicate excluded type filters}, + * this set operation combines the given {@link Predicate exclude type filters} with + * the exiting {@link Predicate excluded type filters} joined by {@literal and}. * - * @param typeFilters {@link Predicate type filters} used to to filter {@link Class type} serializable + * @param excludeTypeFilters {@link Predicate type filters} used to exclude/filter {@link Class types} serializable * by this {@link MappingPdxSerializer PDX serializer}. * @see java.util.function.Predicate */ - public void setTypeFilters(@Nullable Predicate> typeFilters) { - this.typeFilters = typeFilters != null ? this.typeFilters.and(typeFilters) : this.typeFilters; + public void setExcludeTypeFilters(@Nullable Predicate> excludeTypeFilters) { + + this.excludeTypeFilters = excludeTypeFilters != null + ? this.excludeTypeFilters.and(excludeTypeFilters) + : this.excludeTypeFilters; + } + + /** + * Sets the {@link Predicate type filters} used to include {@link Class types} serializable + * by this {@link MappingPdxSerializer PDX serializer}. + * + * This operation is null-safe and rather than overriding the existing {@link Predicate included type filters}, + * this set operation combines the given {@link Predicate include type filters} with + * the exiting {@link Predicate included type filters} joined by {@literal or}. + * + * @param includeTypeFilters {@link Predicate type filters} used to include {@link Class types} serializable + * by this {@link MappingPdxSerializer PDX serializer}. + * @see java.util.function.Predicate + */ + public void setIncludeTypeFilters(@Nullable Predicate> includeTypeFilters) { + + this.includeTypeFilters = includeTypeFilters != null + ? this.includeTypeFilters.or(includeTypeFilters) + : this.includeTypeFilters; } /** @@ -477,7 +500,21 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw * @see java.util.function.Predicate */ protected Predicate> getTypeFilters() { - return this.typeFilters; + return this.excludeTypeFilters.or(TypeFilters.EXCLUDE_NULL_TYPES.and(this.includeTypeFilters)); + } + + /** + * Registers the given {@link PdxSerializerResolver}, which will be used to resolve a custom {@link PdxSerializer} + * for a entity property. + * + * The strategy, or criteria used to resolve the custom {@link PdxSerializer} is up to the individual resolve + * and can be based on things like the property type, or fully-qualified property name, etc. + * + * @param pdxSerializerResolver {@link PdxSerializerResolver} used to resolve a custom {@link PdxSerializer} + * for a entity property. + */ + public void register(PdxSerializerResolver pdxSerializerResolver) { + Optional.ofNullable(pdxSerializerResolver).ifPresent(it -> this.pdxSerializerResolvers.add(0, it)); } @Override @@ -517,8 +554,8 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw try { if (getLogger().isDebugEnabled()) { getLogger().debug(String.format("Setting property [%1$s] for entity [%2$s] of type [%3$s] from PDX%4$s", - persistentProperty.getName(), instance, type, (customPdxSerializer != null ? - String.format(" using custom PdxSerializer [%1$s]", customPdxSerializer) : ""))); + persistentProperty.getName(), instance, type, (customPdxSerializer != null + ? String.format(" using custom PdxSerializer [%s]", customPdxSerializer) : ""))); } value = (customPdxSerializer != null @@ -532,10 +569,10 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw propertyAccessor.setProperty(persistentProperty, value); } catch (Exception cause) { - throw new MappingException(String.format( - "While setting value [%1$s] of property [%2$s] for entity of type [%3$s] from PDX%4$s", - value, persistentProperty.getName(), type, (customPdxSerializer != null ? - String.format(" using custom PdxSerializer [%1$s]", customPdxSerializer) : "")), cause); + throw new MappingException( + String.format("While setting value [%1$s] of property [%2$s] for entity of type [%3$s] from PDX%4$s", + value, persistentProperty.getName(), type, (customPdxSerializer != null + ? String.format(" using custom PdxSerializer [%s]", customPdxSerializer) : "")), cause); } } }); @@ -668,15 +705,71 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw return obj != null ? obj.getClass() : null; } + @FunctionalInterface + public interface PdxSerializerResolver { + + @Nullable + PdxSerializer resolve(@NonNull Map customPdxSerializers, + @NonNull PersistentProperty property); + + } + + public enum PdxSerializerResolvers implements PdxSerializerResolver { + + PROPERTY { + + @Override + public PdxSerializer resolve(Map customPdxSerializers, PersistentProperty property) { + return customPdxSerializers.get(property); + } + }, + + PROPERTY_NAME { + + @Override + public PdxSerializer resolve(Map customPdxSerializers, PersistentProperty property) { + return customPdxSerializers.get(toFullyQualifiedPropertyName(property)); + } + }, + + PROPERTY_TYPE { + + @Override + public PdxSerializer resolve(Map customPdxSerializers, PersistentProperty property) { + return customPdxSerializers.get(property.getType()); + } + }; + + /** + * Converts the entity {@link PersistentProperty} to a {@link String fully-qualified property name}. + * + * @param property {@link PersistentProperty} of the entity. + * @return the {@link String fully-qualified property name of the entity {@link PersistentProperty}. + * @see org.springframework.data.mapping.PersistentProperty + */ + @NonNull + static String toFullyQualifiedPropertyName(@NonNull PersistentProperty property) { + return property.getOwner().getType().getName().concat(".").concat(property.getName()); + } + } + public enum TypeFilters implements Filter> { - EXCLUDE_COM_GEMSTONE_GEMFIRE_TYPES { + EXCLUDE_ALL_TYPES { + + @Override + public boolean accept(@Nullable Class type) { + return false; + } + }, + + EXCLUDE_JAVA_TYPES { @Override public boolean accept(@Nullable Class type) { return Optional.ofNullable(type) - .filter(it -> !it.getPackage().getName().startsWith(COM_GEMSTONE_GEMFIRE_PACKAGE_NAME)) + .filter(it -> !it.getPackage().getName().startsWith(JAVA_PACKAGE_NAME)) .isPresent(); } }, @@ -689,6 +782,17 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw } }, + EXCLUDE_COM_GEMSTONE_GEMFIRE_TYPES { + + @Override + public boolean accept(@Nullable Class type) { + + return Optional.ofNullable(type) + .filter(it -> !it.getPackage().getName().startsWith(COM_GEMSTONE_GEMFIRE_PACKAGE_NAME)) + .isPresent(); + } + }, + EXCLUDE_ORG_APACHE_GEODE_TYPES { @Override @@ -699,5 +803,16 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw .isPresent(); } }, + + EXCLUDE_ORG_SPRINGFRAMEWORK_TYPES { + + @Override + public boolean accept(@Nullable Class type) { + + return Optional.ofNullable(type) + .filter(it -> !it.getPackage().getName().startsWith(ORG_SPRINGFRAMEWORK_PACKAGE_NAME)) + .isPresent(); + } + }, } } diff --git a/src/test/java/com/gemstone/gemfire/TestGemStoneGemFireType.java b/src/test/java/com/gemstone/gemfire/TestGemStoneGemFireType.java new file mode 100644 index 00000000..04bae604 --- /dev/null +++ b/src/test/java/com/gemstone/gemfire/TestGemStoneGemFireType.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 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 com.gemstone.gemfire; + +import org.springframework.data.gemfire.mapping.MappingPdxSerializerUnitTests; + +/** + * The {@link TestGemStoneGemFireType} class is a test {@link Class type} used by + * the {@link MappingPdxSerializerUnitTests}. + * + * @author John Blum + * @see org.springframework.data.gemfire.mapping.MappingPdxSerializerUnitTests + * @since 1.0.0 + */ +public class TestGemStoneGemFireType { + +} diff --git a/src/test/java/org/springframework/data/gemfire/mapping/MappingPdxSerializerUnitTests.java b/src/test/java/org/springframework/data/gemfire/mapping/MappingPdxSerializerUnitTests.java index 497dbb1b..f86fd083 100644 --- a/src/test/java/org/springframework/data/gemfire/mapping/MappingPdxSerializerUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/mapping/MappingPdxSerializerUnitTests.java @@ -34,11 +34,14 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; +import java.security.Principal; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import com.gemstone.gemfire.TestGemStoneGemFireType; + import org.apache.geode.pdx.PdxReader; import org.apache.geode.pdx.PdxSerializer; import org.apache.geode.pdx.PdxWriter; @@ -47,15 +50,22 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.core.SpringVersion; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.core.type.ClassMetadata; import org.springframework.data.convert.EntityInstantiator; import org.springframework.data.convert.EntityInstantiators; +import org.springframework.data.domain.Page; +import org.springframework.data.gemfire.GemfireTemplate; import org.springframework.data.gemfire.repository.sample.Account; import org.springframework.data.gemfire.repository.sample.Address; +import org.springframework.data.gemfire.repository.sample.Algorithm; +import org.springframework.data.gemfire.repository.sample.Animal; import org.springframework.data.gemfire.repository.sample.Customer; import org.springframework.data.gemfire.repository.sample.Person; +import org.springframework.data.gemfire.repository.sample.Plant; import org.springframework.data.gemfire.repository.sample.Programmer; import org.springframework.data.gemfire.repository.sample.RootUser; import org.springframework.data.gemfire.repository.sample.User; @@ -109,8 +119,8 @@ public class MappingPdxSerializerUnitTests { this.pdxSerializer = spy(new MappingPdxSerializer(this.mappingContext, this.conversionService)); } - private String toFullyQualifiedPropertyName(PersistentProperty persistentProperty) { - return this.pdxSerializer.toFullyQualifiedPropertyName(persistentProperty); + private String toFullyQualifiedPropertyName(PersistentProperty property) { + return MappingPdxSerializer.PdxSerializerResolvers.toFullyQualifiedPropertyName(property); } @Test @@ -228,24 +238,31 @@ public class MappingPdxSerializerUnitTests { assertThat(this.pdxSerializer.getCustomPdxSerializers()).isEqualTo(customPdxSerializers); } - @Test(expected = IllegalArgumentException.class) - public void setCustomPdxSerializersToNull() { + @Test + public void setCustomPdxSerializersIsNullSafe() { - try { - this.pdxSerializer.setCustomPdxSerializers(null); - } - catch (IllegalArgumentException expected) { + assertThat(this.pdxSerializer.getCustomPdxSerializers()).isEmpty(); - assertThat(expected).hasMessage("Custom PdxSerializers must not be null"); - assertThat(expected).hasNoCause(); + this.pdxSerializer.setCustomPdxSerializers(null); - throw expected; - } + assertThat(this.pdxSerializer.getCustomPdxSerializers()).isEmpty(); } @Test @SuppressWarnings("all") - public void getCustomPdxSerializerForMappedPersistentPropertyReturnsPdxSerializerForProperty() { + public void getCustomPdxSerializerReturnsNull() { + + PersistentEntity personEntity = this.mappingContext.getPersistentEntity(Person.class); + + PersistentProperty addressProperty = personEntity.getPersistentProperty("address"); + + assertThat(this.pdxSerializer.getCustomPdxSerializers()).isEmpty(); + assertThat(this.pdxSerializer.getCustomPdxSerializer(addressProperty)).isNull(); + } + + @Test + @SuppressWarnings("all") + public void getCustomPdxSerializerReturnsPdxSerializerForProperty() { PdxSerializer mockNamedSerializer = mock(PdxSerializer.class); PdxSerializer mockPropertySerializer = mock(PdxSerializer.class); @@ -266,7 +283,7 @@ public class MappingPdxSerializerUnitTests { @Test @SuppressWarnings("all") - public void getCustomPdxSerializerForMappedPersistentPropertyReturnsPdxSerializerForPropertyName() { + public void getCustomPdxSerializerReturnsPdxSerializerForPropertyName() { PdxSerializer mockNamedSerializer = mock(PdxSerializer.class); PdxSerializer mockTypedSerializer = mock(PdxSerializer.class); @@ -285,7 +302,7 @@ public class MappingPdxSerializerUnitTests { @Test @SuppressWarnings("all") - public void getCustomPdxSerializerForMappedPersistentPropertyReturnsPdxSerializerForPropertyType() { + public void getCustomPdxSerializerReturnsPdxSerializerForPropertyType() { PdxSerializer mockNamedSerializer = mock(PdxSerializer.class); PdxSerializer mockTypedSerializer = mock(PdxSerializer.class); @@ -305,18 +322,7 @@ public class MappingPdxSerializerUnitTests { } @Test - @SuppressWarnings("all") - public void getCustomPdxSerializerForUnmappedPersistentPropertyReturnsNull() { - - PersistentEntity personEntity = this.mappingContext.getPersistentEntity(Person.class); - - PersistentProperty addressProperty = personEntity.getPersistentProperty("address"); - - assertThat(this.pdxSerializer.getCustomPdxSerializers()).isEmpty(); - assertThat(this.pdxSerializer.getCustomPdxSerializer(addressProperty)).isNull(); - } - - @Test + // TODO remove! @SuppressWarnings("deprecation") public void getCustomSerializerForMappedTypeReturnsPdxSerializer() { @@ -328,6 +334,7 @@ public class MappingPdxSerializerUnitTests { } @Test + // TODO remove! @SuppressWarnings("deprecation") public void getCustomSerializerForUnmappedTypeReturnsNull() { assertThat(this.pdxSerializer.getCustomPdxSerializers()).isEmpty(); @@ -344,7 +351,7 @@ public class MappingPdxSerializerUnitTests { when(mockProperty.getOwner()).thenReturn(mockEntity); when(mockEntity.getType()).thenReturn(Person.class); - assertThat(this.pdxSerializer.toFullyQualifiedPropertyName(mockProperty)) + assertThat(MappingPdxSerializer.PdxSerializerResolvers.toFullyQualifiedPropertyName(mockProperty)) .isEqualTo(Person.class.getName().concat(".mockProperty")); verify(mockEntity, times(1)).getType(); @@ -353,7 +360,7 @@ public class MappingPdxSerializerUnitTests { } @Test - public void setGemfireInstantiatorsWithEntityInstantiators() { + public void setGemfireInstantiatorsWithNonNullEntityInstantiators() { EntityInstantiators mockEntityInstantiators = mock(EntityInstantiators.class); @@ -378,7 +385,7 @@ public class MappingPdxSerializerUnitTests { } @Test - public void setGemfireInstantiatorsWithMappingOfClassTypesToEntityInstantiators() { + public void setGemfireInstantiatorsWithNonNullMappingOfClassTypesToEntityInstantiators() { Map, EntityInstantiator> entityInstantiators = Collections.singletonMap(Person.class, mock(EntityInstantiator.class)); @@ -404,7 +411,7 @@ public class MappingPdxSerializerUnitTests { } @Test - public void getInstantiatorForManagedPersistentEntityWithInstantiator() { + public void getInstantiatorForManagedPersistentEntityWithEntityInstantiator() { EntityInstantiator mockEntityInstantiator = mock(EntityInstantiator.class); @@ -421,7 +428,7 @@ public class MappingPdxSerializerUnitTests { } @Test - public void getInstantiatorForNonManagedPersistentEntityWithNoInstantiator() { + public void getInstantiatorForNonManagedPersistentEntityWithNoEntityInstantiator() { EntityInstantiator mockEntityInstantiator = mock(EntityInstantiator.class); @@ -561,6 +568,8 @@ public class MappingPdxSerializerUnitTests { this.pdxSerializer.setCustomPdxSerializers(Collections.singletonMap(Address.class, mockAddressSerializer)); this.pdxSerializer.setGemfireInstantiators(Collections.singletonMap(Person.class, this.mockInstantiator)); + this.pdxSerializer.setIncludeTypeFilters(type -> Address.class.isAssignableFrom(type)); + this.pdxSerializer.setIncludeTypeFilters(type -> Person.class.isAssignableFrom(type)); Object obj = this.pdxSerializer.fromData(Person.class, this.mockReader); @@ -593,6 +602,7 @@ public class MappingPdxSerializerUnitTests { try { this.pdxSerializer.setGemfireInstantiators(Collections.singletonMap(Person.class, this.mockInstantiator)); + this.pdxSerializer.setIncludeTypeFilters(type -> Person.class.equals(type)); this.pdxSerializer.fromData(Person.class, this.mockReader); } catch (MappingException expected) { @@ -614,7 +624,7 @@ public class MappingPdxSerializerUnitTests { @Test @SuppressWarnings("unchecked") - public void fromDataUsesRegisteredInstantiator() { + public void fromDataUsesRegisteredEntityInstantiator() { Address address = new Address(); @@ -633,6 +643,7 @@ public class MappingPdxSerializerUnitTests { this.pdxSerializer.setCustomPdxSerializers(Collections.singletonMap(Address.class, mockAddressSerializer)); this.pdxSerializer.setGemfireInstantiators(Collections.singletonMap(Person.class, this.mockInstantiator)); + this.pdxSerializer.setIncludeTypeFilters(type -> Person.class.equals(type)); this.pdxSerializer.fromData(Person.class, this.mockReader); GemfirePersistentEntity persistentEntity = @@ -648,41 +659,75 @@ public class MappingPdxSerializerUnitTests { @Test public void fromDataWithTypeFilterAcceptsDeclaredEntityTypes() { - this.pdxSerializer.setTypeFilters(type -> User.class.getPackage().equals(type.getPackage())); + this.pdxSerializer.setIncludeTypeFilters(type -> User.class.getPackage().equals(type.getPackage())); doReturn("test").when(this.pdxSerializer).doFromData(any(Class.class), any(PdxReader.class)); assertThat(this.pdxSerializer.fromData(Account.class, this.mockReader)).isEqualTo("test"); + assertThat(this.pdxSerializer.fromData(Algorithm.class, this.mockReader)).isEqualTo("test"); + assertThat(this.pdxSerializer.fromData(Animal.class, this.mockReader)).isEqualTo("test"); assertThat(this.pdxSerializer.fromData(Customer.class, this.mockReader)).isEqualTo("test"); + assertThat(this.pdxSerializer.fromData(Plant.class, this.mockReader)).isEqualTo("test"); assertThat(this.pdxSerializer.fromData(Programmer.class, this.mockReader)).isEqualTo("test"); assertThat(this.pdxSerializer.fromData(User.class, this.mockReader)).isEqualTo("test"); assertThat(this.pdxSerializer.fromData(org.springframework.data.gemfire.test.model.Person.class, this.mockReader)).isNull(); assertThat(this.pdxSerializer.fromData(null, this.mockReader)).isNull(); verify(this.pdxSerializer, times(1)).doFromData(eq(Account.class), eq(this.mockReader)); + verify(this.pdxSerializer, times(1)).doFromData(eq(Algorithm.class), eq(this.mockReader)); + verify(this.pdxSerializer, times(1)).doFromData(eq(Animal.class), eq(this.mockReader)); verify(this.pdxSerializer, times(1)).doFromData(eq(Customer.class), eq(this.mockReader)); + verify(this.pdxSerializer, times(1)).doFromData(eq(Plant.class), eq(this.mockReader)); verify(this.pdxSerializer, times(1)).doFromData(eq(Programmer.class), eq(this.mockReader)); verify(this.pdxSerializer, times(1)).doFromData(eq(User.class), eq(this.mockReader)); verify(this.pdxSerializer, never()).doFromData(isNull(), eq(this.mockReader)); - verify(this.pdxSerializer, never()) - .doFromData(eq(org.springframework.data.gemfire.test.model.Person.class), eq(this.mockReader)); + verify(this.pdxSerializer, never()).doFromData(eq(org.springframework.data.gemfire.test.model.Person.class), + eq(this.mockReader)); } @Test - public void fromDataWithTypeFilterFiltersApacheGeodeTypeReturnsNull() { + public void fromDataWithTypeFilterAcceptsIncludedTypesOverridingExcludedTypes() { + + this.pdxSerializer.setIncludeTypeFilters(type -> type.getPackage().getName().startsWith("java.security")); + + doReturn("test").when(this.pdxSerializer).doFromData(any(Class.class), any(PdxReader.class)); + + assertThat(this.pdxSerializer.fromData(Principal.class, this.mockReader)).isEqualTo("test"); + + verify(this.pdxSerializer, times(1)) + .doFromData(eq(Principal.class), eq(this.mockReader)); + } + + @Test + public void fromDataWithTypeFilterFiltersApacheGeodeTypesReturnsNull() { assertThat(this.pdxSerializer.fromData(org.apache.geode.cache.EntryEvent.class, this.mockReader)).isNull(); } @Test - public void fromDataWithTypeFilterFiltersNullTypeReturnsNull() { + public void fromDataWithTypeFilterFiltersGemStoneTypesReturnsNull() { + assertThat(this.pdxSerializer.fromData(TestGemStoneGemFireType.class, this.mockReader)).isNull(); + } + + @Test + public void fromDataWithTypeFilterFiltersJavaTypesReturnsNull() { + assertThat(this.pdxSerializer.fromData(java.security.Principal.class, this.mockReader)).isNull(); + } + + @Test + public void fromDataWithTypeFilterFiltersNullTypesReturnsNull() { assertThat(this.pdxSerializer.fromData(null, this.mockReader)).isNull(); } + @Test + public void fromDataWithTypeFilterFiltersSpringFrameworkTypesReturnsNull() { + + assertThat(this.pdxSerializer.fromData(ClassMetadata.class, this.mockReader)).isNull(); + assertThat(this.pdxSerializer.fromData(Page.class, this.mockReader)).isNull(); + assertThat(this.pdxSerializer.fromData(GemfireTemplate.class, this.mockReader)).isNull(); + } + @Test public void fromDataWithTypeFilterFiltersUndeclaredEntityTypesReturnsNull() { - - this.pdxSerializer.setTypeFilters(type -> !ApplicationDomainType.class.equals(type)); - assertThat(this.pdxSerializer.fromData(ApplicationDomainType.class, this.mockReader)).isNull(); } @@ -701,6 +746,8 @@ public class MappingPdxSerializerUnitTests { jonDoe.address = address; + this.pdxSerializer.setIncludeTypeFilters(type -> Address.class.equals(type)); + this.pdxSerializer.setIncludeTypeFilters(type -> Person.class.equals(type)); this.pdxSerializer.setCustomPdxSerializers(Collections.singletonMap(Address.class, mockAddressSerializer)); assertThat(this.pdxSerializer.toData(jonDoe, this.mockWriter)).isTrue(); @@ -736,6 +783,8 @@ public class MappingPdxSerializerUnitTests { .thenThrow(newIllegalArgumentException("test")); try { + this.pdxSerializer.setIncludeTypeFilters(type -> Address.class.equals(type)); + this.pdxSerializer.setIncludeTypeFilters(type -> Person.class.equals(type)); this.pdxSerializer.setCustomPdxSerializers(Collections.emptyMap()); this.pdxSerializer.toData(jonDoe, this.mockWriter); } @@ -769,24 +818,6 @@ public class MappingPdxSerializerUnitTests { } } - @Test - public void toDataFiltersUndeclaredEntityTypeReturnsFalse() { - - this.pdxSerializer.setTypeFilters(type -> !ApplicationDomainType.class.equals(type)); - - assertThat(this.pdxSerializer.toData(new ApplicationDomainType(), this.mockWriter)).isFalse(); - } - - @Test - public void toDataFiltersNullTypeReturnsFalse() { - assertThat(this.pdxSerializer.toData(null, this.mockWriter)).isFalse(); - } - - @Test - public void toDataFiltersApacheGeodeTypeReturnsFalse() { - assertThat(this.pdxSerializer.toData(mock(org.apache.geode.cache.EntryEvent.class), this.mockWriter)).isFalse(); - } - @Test public void toDataAcceptsDeclaredEntityTypeReturnsTrue() { @@ -794,25 +825,75 @@ public class MappingPdxSerializerUnitTests { new org.springframework.data.gemfire.test.model.Person("Jon", "Doe", null, Gender.MALE); - this.pdxSerializer.setTypeFilters(type -> User.class.getPackage().equals(type.getPackage())); + this.pdxSerializer.setIncludeTypeFilters(type -> User.class.getPackage().equals(type.getPackage())); doReturn(true).when(this.pdxSerializer).doToData(any(), any(PdxWriter.class)); assertThat(this.pdxSerializer.toData(new Account(1L), this.mockWriter)).isTrue(); + assertThat(this.pdxSerializer.toData(new Animal(), this.mockWriter)).isTrue(); assertThat(this.pdxSerializer.toData(new Customer(1L), this.mockWriter)).isTrue(); assertThat(this.pdxSerializer.toData(new Programmer("jxblum"), this.mockWriter)).isTrue(); + assertThat(this.pdxSerializer.toData(new Plant(), this.mockWriter)).isTrue(); assertThat(this.pdxSerializer.toData(new RootUser("jxblum"), this.mockWriter)).isTrue(); assertThat(this.pdxSerializer.toData(null, this.mockWriter)).isFalse(); assertThat(this.pdxSerializer.toData(jonDoe, this.mockWriter)).isFalse(); verify(this.pdxSerializer, times(1)).doToData(isA(Account.class), eq(this.mockWriter)); + verify(this.pdxSerializer, times(1)).doToData(isA(Animal.class), eq(this.mockWriter)); verify(this.pdxSerializer, times(1)).doToData(isA(Customer.class), eq(this.mockWriter)); + verify(this.pdxSerializer, times(1)).doToData(isA(Plant.class), eq(this.mockWriter)); verify(this.pdxSerializer, times(1)).doToData(isA(Programmer.class), eq(this.mockWriter)); verify(this.pdxSerializer, times(1)).doToData(isA(RootUser.class), eq(this.mockWriter)); verify(this.pdxSerializer, never()).doToData(isNull(), eq(this.mockWriter)); verify(this.pdxSerializer, never()).doToData(isA(jonDoe.getClass()), eq(this.mockWriter)); } + @Test + public void toDataAcceptsIncludedEntityTypesOverridingExcludedEntityTypes() { + + this.pdxSerializer.setIncludeTypeFilters(type -> type.getPackage().getName().startsWith("org.springframework")); + + doReturn(true).when(this.pdxSerializer).doToData(any(), any(PdxWriter.class)); + + assertThat(this.pdxSerializer.toData(new SpringVersion(), this.mockWriter)).isTrue(); + + verify(this.pdxSerializer, times(1)) + .doToData(isA(SpringVersion.class), eq(this.mockWriter)); + } + + @Test + public void toDataFiltersApacheGeodeTypesReturnsFalse() { + assertThat(this.pdxSerializer.toData(mock(org.apache.geode.cache.EntryEvent.class), this.mockWriter)).isFalse(); + } + + @Test + public void toDataFiltersGemStoneTypesReturnsFalse() { + assertThat(this.pdxSerializer.toData(TestGemStoneGemFireType.class, this.mockWriter)).isFalse(); + } + + @Test + public void toDataFiltersJavaTypesReturnsFalse() { + assertThat(this.pdxSerializer.toData(java.security.Principal.class, this.mockWriter)).isFalse(); + } + + @Test + public void toDataFiltersNullTypesReturnsFalse() { + assertThat(this.pdxSerializer.toData(null, this.mockWriter)).isFalse(); + } + + @Test + public void toDataFiltersSpringFrameworkTypesReturnsFalse() { + + assertThat(this.pdxSerializer.toData(ClassMetadata.class, this. mockWriter)).isFalse(); + assertThat(this.pdxSerializer.toData(Page.class, this.mockWriter)).isFalse(); + assertThat(this.pdxSerializer.toData(GemfireTemplate.class, this.mockWriter)).isFalse(); + } + + @Test + public void toDataFiltersUndeclaredEntityTypeReturnsFalse() { + assertThat(this.pdxSerializer.toData(new ApplicationDomainType(), this.mockWriter)).isFalse(); + } + private static class ApplicationDomainType { } }