Completed custom serializers in PdxMappingSerializer, SGF-125, SGF-90, SGF-127

This commit is contained in:
David Turanski
2012-09-27 18:12:03 -04:00
parent 0020362b6e
commit 4c95b7044c
6 changed files with 134 additions and 25 deletions

View File

@@ -193,7 +193,9 @@
com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer</classname>,
however it is common for developers to provide their own implementation.
The value of the attribute is simply a reference to a Spring bean that
implements the required interface. More information on serialization support can be found in <xref linkend="serialization"/> </para>
implements the required interface. More information on serialization
support can be found in <xref linkend="serialization"/></para>
<para/>
</section>
</section>
@@ -264,7 +266,7 @@
instantiators defined declaratively to be fully initialized and
registered before the server starts accepting connections. Keep this in
mind when programmatically configuring these items as the server might
start before your components and thus not be seen by the clients
start after your components and thus not be seen by the clients
connecting right away.</para>
</note>
</section>

View File

@@ -15,7 +15,8 @@
<para>Spring Data GemFire provides support to use the Spring Data
repository abstraction to easily persist entities into GemFire and execute
queries. A general introduction into the repository programming model is
been provided <ulink url="http://static.springsource.org/spring-data/data-commons/docs/current/reference/html/#repositories">here
been provided <ulink
url="http://static.springsource.org/spring-data/data-commons/docs/current/reference/html/#repositories">here
</ulink>.</para>
</section>
@@ -30,14 +31,14 @@
<title>Bootstrap GemFire repositories</title>
<programlisting language="xml">&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gf="http://www.springframework.org/schema/gemfire"
xmlns:gfe-data="http://www.springframework.org/schema/data/gemfire"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/gemfire
http://www.springframework.org/schema/gemfire/spring-gemfire.xsd&gt;
http://www.springframework.org/schema/data/gemfire
http://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd&gt;
&lt;gf:repositories base-package="com.acme.repository" /&gt;
&lt;gfe-data:repositories base-package="com.acme.repository" /&gt;
&lt;/beans&gt;</programlisting>
</example>
@@ -88,11 +89,11 @@ public class Person { … }</programlisting>
<title>Supported keywords for query methods</title>
<tgroup cols="3">
<colspec colwidth="1*" />
<colspec colwidth="1*"/>
<colspec colwidth="2*" />
<colspec colwidth="2*"/>
<colspec colwidth="2*" />
<colspec colwidth="2*"/>
<thead>
<row>

View File

@@ -121,8 +121,6 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
*/
@Override
public Object fromData(Class<?> type, final PdxReader reader) {
// TODO: check for custom serializer (PDX)
final GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
GemfirePropertyValueProvider propertyValueProvider = new GemfirePropertyValueProvider(reader);
@@ -143,9 +141,15 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
if (entity.isConstructorArgument(persistentProperty)) {
return;
}
// TODO: check for custom serializer (Spring Converter - primitives)
Object value = reader.readField(persistentProperty.getName());
PdxSerializer customSerializer = getCustomSerializer(persistentProperty.getType());
Object value = null;
if (customSerializer != null) {
System.out.println("using custom serializer");
value = customSerializer.fromData(persistentProperty.getType(), reader);
} else {
value = reader.readField(persistentProperty.getName());
}
try {
wrapper.setProperty(persistentProperty, value);
}
@@ -166,7 +170,6 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
*/
@Override
public boolean toData(Object value, final PdxWriter writer) {
// TODO: check for custom serializer (PDX)
GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(value.getClass());
final BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(value, conversionService);
@@ -174,10 +177,15 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
// TODO: check for custom serializer (Spring Converter)
try {
Object propertyValue = wrapper.getProperty(persistentProperty);
writer.writeField(persistentProperty.getName(), propertyValue, (Class) persistentProperty.getType());
PdxSerializer customSerializer = getCustomSerializer(persistentProperty.getType());
if (customSerializer != null) {
customSerializer.toData(propertyValue, writer);
} else {
writer.writeField(persistentProperty.getName(), propertyValue, (Class) persistentProperty.getType());
}
}
catch (Exception e) {
throw new MappingException("Could not write value for property " + persistentProperty.toString(), e);
@@ -193,4 +201,8 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
return true;
}
private PdxSerializer getCustomSerializer(Class<?> clazz) {
return customSerializers == null ? null : customSerializers.get(clazz);
}
}

View File

@@ -122,12 +122,12 @@ when the same cache is used in multiple application context/bean factories insid
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="pdx-serializer" type="xsd:string"
<xsd:attribute name="pdx-serializer-ref" type="xsd:string"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Sets the PDX serializer for the cache. If this serializer is set, it will be consulted to see if it can serialize any
domain classes which are added to the cache in portable data exchange format.
domain classes which are added to the cache in portable data exchange (PDX) format.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -18,16 +18,21 @@ package org.springframework.data.gemfire.mapping;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.gemfire.repository.sample.Address;
import org.springframework.data.gemfire.repository.sample.Person;
import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.Instantiator;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.DataPolicy;
@@ -41,12 +46,12 @@ import com.gemstone.gemfire.cache.RegionFactory;
*/
public class MappingPdxSerializerIntegrationTest {
Region<Object, Object> region;
static Region<Object, Object> region;
static Cache cache;
@Before
public void setUp() {
@BeforeClass
public static void setUp() {
MappingPdxSerializer serializer = new MappingPdxSerializer(new GemfireMappingContext(),
new DefaultConversionService());
@@ -81,6 +86,29 @@ public class MappingPdxSerializerIntegrationTest {
assertThat(reference.getLastname(), is(person.getLastname()));
assertThat(reference.address, is(person.address));
}
@Test
public void serializeAndDeserializeCorrectlyWithDataSerializable() {
Address address = new Address();
address.zipCode = "01234";
address.city = "London";
PersonWithDataSerializableProperty person = new PersonWithDataSerializableProperty(2L, "Oliver", "Gierke", new DataSerializableProperty("foo"));
person.address = address;
region.put(2L, person);
Object result = region.get(2L);
assertThat(result instanceof PersonWithDataSerializableProperty, is(true));
PersonWithDataSerializableProperty reference = person;
assertThat(reference.getFirstname(), is(person.getFirstname()));
assertThat(reference.getLastname(), is(person.getLastname()));
assertThat(reference.address, is(person.address));
assertThat(reference.dsProperty.getValue(),is("foo"));
}
@AfterClass
public static void tearDown() {
@@ -99,4 +127,57 @@ public class MappingPdxSerializerIntegrationTest {
new File(name).delete();
}
}
@SuppressWarnings("serial")
public static class PersonWithDataSerializableProperty extends Person {
private DataSerializableProperty dsProperty;
public PersonWithDataSerializableProperty(Long id, String firstname,
String lastname, DataSerializableProperty dsProperty) {
super(id, firstname, lastname);
this.dsProperty = dsProperty;
}
public DataSerializableProperty getDataSerializableProperty() {
return this.dsProperty;
}
}
@SuppressWarnings("serial")
public static class DataSerializableProperty implements DataSerializable {
static {
Instantiator.register(new Instantiator(DataSerializableProperty.class,101) {
public DataSerializable newInstance() {
return new DataSerializableProperty("");
}
});
}
private String value;
public DataSerializableProperty(String value) {
this.value = value;
}
@Override
public void fromData(DataInput dataInput) throws IOException,
ClassNotFoundException {
value = dataInput.readUTF();
}
@Override
public void toData(DataOutput dataOutput) throws IOException {
dataOutput.writeUTF(value);
}
public String getValue() {
return this.value;
}
}
}

View File

@@ -29,10 +29,12 @@ import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.gemfire.repository.sample.Address;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.mapping.model.ParameterValueProvider;
import com.gemstone.gemfire.pdx.PdxReader;
import com.gemstone.gemfire.pdx.PdxSerializer;
/**
* Unit tests for {@link MappingPdxSerializer}.
@@ -50,6 +52,9 @@ public class MappingPdxSerializerUnitTests {
EntityInstantiator instantiator;
@Mock
PdxReader reader;
@Mock
PdxSerializer addressSerializer;
@Before
public void setUp() {
@@ -57,14 +62,21 @@ public class MappingPdxSerializerUnitTests {
context = new GemfireMappingContext();
conversionService = new GenericConversionService();
serializer = new MappingPdxSerializer(context, conversionService);
Map<Class<?>,PdxSerializer> customSerializers = new HashMap<Class<?>, PdxSerializer>();
customSerializers.put(Address.class, addressSerializer);
serializer.setCustomSerializers(customSerializers);
}
@Test
@SuppressWarnings("unchecked")
public void usesRegisteredInstantiator() {
Address address = new Address();
address.zipCode = "01234";
address.city = "London";
Person person = new Person(1L, "Oliver", "Gierke");
person.address = address;
ParameterValueProvider<GemfirePersistentProperty> provider = any(ParameterValueProvider.class);
GemfirePersistentEntity<?> entity = any(GemfirePersistentEntity.class);
when(instantiator.createInstance(entity, provider)).thenReturn(person);
@@ -77,5 +89,6 @@ public class MappingPdxSerializerUnitTests {
verify(instantiator, times(1)).createInstance(eq(context.getPersistentEntity(Person.class)),
any(ParameterValueProvider.class));
verify(addressSerializer,times(1)).fromData(eq(Address.class), any(PdxReader.class));
}
}