SGF-358 - Enhance SDG's Function annotation support to allow strongly-typed arguments in the context of PDX even when read-serialized is set to true.
This commit is contained in:
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* 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.function;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.gemfire.ForkUtil;
|
||||
import org.springframework.data.gemfire.fork.SpringCacheServerProcess;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
import org.springframework.data.gemfire.function.sample.ApplicationDomainFunctionExecutions;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.client.ClientCache;
|
||||
import com.gemstone.gemfire.pdx.PdxInstance;
|
||||
import com.gemstone.gemfire.pdx.PdxInstanceFactory;
|
||||
import com.gemstone.gemfire.pdx.PdxReader;
|
||||
import com.gemstone.gemfire.pdx.PdxSerializer;
|
||||
import com.gemstone.gemfire.pdx.PdxWriter;
|
||||
import com.gemstone.gemfire.pdx.internal.PdxInstanceEnum;
|
||||
|
||||
/**
|
||||
* The ClientCacheFunctionExecutionWithPdxIntegrationTest class is a test suite of test cases testing Spring Data
|
||||
* GemFire's Function annotation support and interaction between a GemFire client and server Cache
|
||||
* when PDX is configured and read-serialized is set to true.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.runner.RunWith
|
||||
* @see org.springframework.data.gemfire.fork.SpringCacheServerProcess
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see org.springframework.data.gemfire.function.sample.ApplicationDomainFunctionExecutions
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||
* @see com.gemstone.gemfire.cache.client.ClientCache
|
||||
* @see com.gemstone.gemfire.pdx.PdxInstance
|
||||
* @see com.gemstone.gemfire.pdx.PdxSerializer
|
||||
* @see com.gemstone.gemfire.pdx.internal.PdxInstanceEnum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientCacheFunctionExecutionWithPdxIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private ClientCache gemfireClientCache;
|
||||
|
||||
@Autowired
|
||||
private ApplicationDomainFunctionExecutions functionExecutions;
|
||||
|
||||
@BeforeClass
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void setupSpringGemFireServer() throws IOException {
|
||||
ForkUtil.startCacheServer(SpringCacheServerProcess.class.getName() + " "
|
||||
+ toPathname(ClientCacheFunctionExecutionWithPdxIntegrationTest.class).concat("-server-context.xml"));
|
||||
}
|
||||
|
||||
protected static String toPathname(final Class type) {
|
||||
return File.separator.concat(type.getName().replaceAll("\\.", File.separator));
|
||||
}
|
||||
|
||||
protected PdxInstance toPdxInstance(final Map<String, Object> pdxData) {
|
||||
PdxInstanceFactory pdxInstanceFactory = gemfireClientCache.createPdxInstanceFactory(pdxData.get("@type").toString());
|
||||
|
||||
for (Map.Entry<String, Object> entry : pdxData.entrySet()) {
|
||||
pdxInstanceFactory.writeObject(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return pdxInstanceFactory.create();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertedFunctionArgumentTypes() {
|
||||
Class[] argumentTypes = functionExecutions.captureConvertedArgumentTypes("test", 1, Boolean.TRUE,
|
||||
new Person("Jon", "Doe"), Gender.MALE);
|
||||
|
||||
assertNotNull(argumentTypes);
|
||||
assertEquals(5, argumentTypes.length);
|
||||
assertEquals(String.class, argumentTypes[0]);
|
||||
assertEquals(Integer.class, argumentTypes[1]);
|
||||
assertEquals(Boolean.class, argumentTypes[2]);
|
||||
assertEquals(Person.class, argumentTypes[3]);
|
||||
assertEquals(Gender.class, argumentTypes[4]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnconvertedFunctionArgumentTypes() {
|
||||
Class[] argumentTypes = functionExecutions.captureUnconvertedArgumentTypes("test", 2, Boolean.FALSE,
|
||||
new Person("Jane", "Doe"), Gender.FEMALE);
|
||||
|
||||
assertNotNull(argumentTypes);
|
||||
assertEquals(5, argumentTypes.length);
|
||||
assertEquals(String.class, argumentTypes[0]);
|
||||
assertEquals(Integer.class, argumentTypes[1]);
|
||||
assertEquals(Boolean.class, argumentTypes[2]);
|
||||
assertTrue(PdxInstance.class.isAssignableFrom(argumentTypes[3]));
|
||||
assertEquals(PdxInstanceEnum.class, argumentTypes[4]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddressFieldValue() {
|
||||
assertEquals("Portland", functionExecutions.getAddressField(new Address(
|
||||
"100 Main St.", "Portland", "OR", "97205"), "city"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPdxDataFieldValue() {
|
||||
Map<String, Object> pdxData = new HashMap<String, Object>(3);
|
||||
|
||||
pdxData.put("@type", "x.y.z.domain.MyApplicationDomainType");
|
||||
pdxData.put("booleanField", Boolean.TRUE);
|
||||
pdxData.put("integerField", 123);
|
||||
pdxData.put("stringField", "test");
|
||||
|
||||
Integer value = (Integer) functionExecutions.getDataField(toPdxInstance(pdxData), "integerField");
|
||||
|
||||
assertEquals(pdxData.get("integerField"), value);
|
||||
}
|
||||
|
||||
public static class ApplicationDomainFunctions {
|
||||
|
||||
private Class[] getArgumentTypes(final Object... arguments) {
|
||||
Class[] argumentTypes = new Class[arguments.length];
|
||||
int index = 0;
|
||||
|
||||
for (Object argument : arguments) {
|
||||
argumentTypes[index] = arguments[index].getClass();
|
||||
index++;
|
||||
}
|
||||
|
||||
return argumentTypes;
|
||||
}
|
||||
|
||||
@GemfireFunction
|
||||
public Class[] captureConvertedArgumentTypes(final String stringValue, final Integer integerValue,
|
||||
final Boolean booleanValue, final Person person, final Gender gender) {
|
||||
return getArgumentTypes(stringValue, integerValue, booleanValue, person, gender);
|
||||
}
|
||||
|
||||
@GemfireFunction
|
||||
public Class[] captureUnconvertedArgumentTypes(final String stringValue, final Integer integerValue,
|
||||
final Boolean booleanValue, final Object domainObject, final Object enumValue) {
|
||||
return getArgumentTypes(stringValue, integerValue, booleanValue, domainObject, enumValue);
|
||||
}
|
||||
|
||||
@GemfireFunction
|
||||
public String getAddressField(final PdxInstance address, final String fieldName) {
|
||||
Assert.isTrue(Address.class.getName().equals(address.getClassName()));
|
||||
return String.valueOf(address.getField(fieldName));
|
||||
}
|
||||
|
||||
@GemfireFunction
|
||||
public Object getDataField(final PdxInstance data, final String fieldName) {
|
||||
return data.getField(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Address {
|
||||
|
||||
private final String street;
|
||||
private final String city;
|
||||
private final String state; // refactor; use Enum!
|
||||
private final String zipCode;
|
||||
|
||||
public Address(final String street, final String city, final String state, final String zipCode) {
|
||||
Assert.hasText("The Address 'street' must be specified", street);
|
||||
Assert.hasText("The Address 'city' must be specified", city);
|
||||
Assert.hasText("The Address 'state' must be specified", state);
|
||||
Assert.hasText("The Address 'zipCode' must be specified", zipCode);
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Address that = (Address) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.getStreet(), that.getStreet())
|
||||
&& ObjectUtils.nullSafeEquals(this.getCity(), that.getCity())
|
||||
&& ObjectUtils.nullSafeEquals(this.getState(), that.getState())
|
||||
&& ObjectUtils.nullSafeEquals(this.getZipCode(), that.getZipCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashValue = 17;
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getStreet());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getCity());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getState());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getZipCode());
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%1$s %2$s, %3$s %4$s", getStreet(), getCity(), getState(), getZipCode());
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Gender {
|
||||
FEMALE,
|
||||
MALE
|
||||
}
|
||||
|
||||
public static class Person {
|
||||
|
||||
private final String firstName;
|
||||
private final String lastName;
|
||||
|
||||
public Person(final String firstName, final String lastName) {
|
||||
Assert.hasText(firstName, "The person's first name must be specified!");
|
||||
Assert.hasText(lastName, "The person's last name must be specified!");
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Person)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Person that = (Person) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.getFirstName(), that.getFirstName())
|
||||
&& ObjectUtils.nullSafeEquals(this.getLastName(), that.getLastName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashValue = 17;
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getFirstName());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getLastName());
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%1$s %2$s", getFirstName(), getLastName());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ComposablePdxSerializer implements PdxSerializer {
|
||||
|
||||
private final PdxSerializer[] pdxSerializers;
|
||||
|
||||
private ComposablePdxSerializer(final PdxSerializer[] pdxSerializers) {
|
||||
this.pdxSerializers = pdxSerializers;
|
||||
}
|
||||
|
||||
public static PdxSerializer compose(final PdxSerializer... pdxSerializers) {
|
||||
return (pdxSerializers == null ? null : (pdxSerializers.length == 1 ? pdxSerializers[0]
|
||||
: new ComposablePdxSerializer(pdxSerializers)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toData(final Object obj, final PdxWriter out) {
|
||||
for (PdxSerializer pdxSerializer : pdxSerializers) {
|
||||
if (pdxSerializer.toData(obj, out)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromData(final Class<?> type, final PdxReader in) {
|
||||
for (PdxSerializer pdxSerializer : pdxSerializers) {
|
||||
Object obj = pdxSerializer.fromData(type, in);
|
||||
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ComposablePdxSerializerFactoryBean implements FactoryBean<PdxSerializer>, InitializingBean {
|
||||
|
||||
private List<PdxSerializer> pdxSerializers = Collections.emptyList();
|
||||
|
||||
private PdxSerializer pdxSerializer;
|
||||
|
||||
public void setPdxSerializers(final List<PdxSerializer> pdxSerializers) {
|
||||
this.pdxSerializers = pdxSerializers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
pdxSerializer = ComposablePdxSerializer.compose(pdxSerializers.toArray(
|
||||
new PdxSerializer[pdxSerializers.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PdxSerializer getObject() throws Exception {
|
||||
return pdxSerializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return (pdxSerializer != null ? pdxSerializer.getClass() : PdxSerializer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AddressPdxSerializer implements PdxSerializer {
|
||||
|
||||
@Override
|
||||
public boolean toData(final Object obj, final PdxWriter out) {
|
||||
if (obj instanceof Address) {
|
||||
Address address = (Address) obj;
|
||||
out.writeString("street", address.getStreet());
|
||||
out.writeString("city", address.getCity());
|
||||
out.writeString("state", address.getState());
|
||||
out.writeString("zipCode", address.getZipCode());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromData(final Class<?> type, final PdxReader in) {
|
||||
if (Address.class.isAssignableFrom(type)) {
|
||||
return new Address(in.readString("street"), in.readString("city"), in.readString("state"),
|
||||
in.readString("zipCode"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static class PersonPdxSerializer implements PdxSerializer {
|
||||
|
||||
@Override
|
||||
public boolean toData(final Object obj, final PdxWriter out) {
|
||||
if (obj instanceof Person) {
|
||||
Person person = (Person) obj;
|
||||
out.writeString("firstName", person.getFirstName());
|
||||
out.writeString("lastName", person.getLastName());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromData(final Class<?> type, final PdxReader in) {
|
||||
if (Person.class.isAssignableFrom(type)) {
|
||||
return new Person(in.readString("firstName"), in.readString("lastName"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* 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.function;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.CacheFactory;
|
||||
import com.gemstone.gemfire.cache.execute.FunctionContext;
|
||||
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
|
||||
import com.gemstone.gemfire.pdx.PdxInstance;
|
||||
import com.gemstone.gemfire.pdx.PdxInstanceFactory;
|
||||
import com.gemstone.gemfire.pdx.PdxReader;
|
||||
import com.gemstone.gemfire.pdx.PdxSerializer;
|
||||
import com.gemstone.gemfire.pdx.PdxWriter;
|
||||
import com.gemstone.gemfire.pdx.internal.PdxInstanceEnum;
|
||||
import com.gemstone.gemfire.pdx.internal.PdxInstanceFactoryImpl;
|
||||
|
||||
/**
|
||||
* The PdxFunctionArgumentResolverTest class is a test suite of test cases testing the contract and functionality
|
||||
* of the PdxFunctionArgumentResolver class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.function.PdxFunctionArgumentResolver
|
||||
* @see com.gemstone.gemfire.cache.Cache
|
||||
* @see com.gemstone.gemfire.cache.execute.FunctionContext
|
||||
* @see com.gemstone.gemfire.pdx.PdxInstance
|
||||
* @see com.gemstone.gemfire.pdx.PdxSerializer
|
||||
* @see com.gemstone.gemfire.pdx.internal.PdxInstanceEnum
|
||||
* @since 1.5.2
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PdxFunctionArgumentResolverTest {
|
||||
|
||||
private static Cache gemfireCache;
|
||||
|
||||
private PdxFunctionArgumentResolver functionArgumentResolver;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupGemFire() {
|
||||
gemfireCache = new CacheFactory()
|
||||
.setPdxSerializer(new PersonPdxSerializer())
|
||||
.setPdxReadSerialized(true)
|
||||
.set("name", PdxFunctionArgumentResolverTest.class.getSimpleName())
|
||||
.set("mcast-port", "0")
|
||||
.set("log-level", "warning")
|
||||
.create();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
gemfireCache.close();
|
||||
gemfireCache = null;
|
||||
}
|
||||
|
||||
protected Method getMethod(final Class<?> type, final String methodName, final Class<?>... parameterTypes) {
|
||||
try {
|
||||
return type.getDeclaredMethod(methodName, parameterTypes);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to get method (%1$s) with signature (%2$s) on Class type (%3$s)!", methodName,
|
||||
getMethodSignature(methodName, parameterTypes), type.getClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
protected Object getMethodSignature(final String methodName, final Class<?>... parameterTypes) {
|
||||
StringBuilder methodSignature = new StringBuilder(methodName);
|
||||
int count = 0;
|
||||
|
||||
methodSignature.append("(");
|
||||
|
||||
for (Class parameterType : parameterTypes) {
|
||||
methodSignature.append(count++ > 0 ? ", :" : ":").append(parameterType.getSimpleName());
|
||||
}
|
||||
|
||||
methodSignature.append("):Void");
|
||||
|
||||
return methodSignature.toString();
|
||||
}
|
||||
|
||||
protected void assertArguments(final Object[] expectedArguments, final Object[] actualArguments) {
|
||||
assertNotNull(actualArguments);
|
||||
assertNotSame(expectedArguments, actualArguments);
|
||||
assertEquals(expectedArguments.length, actualArguments.length);
|
||||
|
||||
for (int index = 0; index < expectedArguments.length; index++) {
|
||||
assertEquals(expectedArguments[index], actualArguments[index]);
|
||||
}
|
||||
}
|
||||
|
||||
protected Person createPerson(final String firstName, final String lastName, final Gender gender) {
|
||||
return new Person(firstName, lastName, gender);
|
||||
}
|
||||
|
||||
protected PdxInstance toPdxInstance(final Person person) {
|
||||
PdxInstanceFactory pdxInstanceFactory = gemfireCache.createPdxInstanceFactory(person.getClass().getName());
|
||||
pdxInstanceFactory.writeString("firstName", person.getFirstName());
|
||||
pdxInstanceFactory.writeString("lastName", person.getLastName());
|
||||
pdxInstanceFactory.writeObject("gender", person.getGender());
|
||||
return pdxInstanceFactory.create();
|
||||
}
|
||||
|
||||
protected PdxInstance toPdxInstance(final Map<String, Object> objectData) {
|
||||
PdxInstanceFactory pdxInstanceFactory = gemfireCache.createPdxInstanceFactory(objectData.get("@type").toString());
|
||||
|
||||
for (Map.Entry<String, Object> entry : objectData.entrySet()) {
|
||||
if (!"@type".equals(entry.getKey())) {
|
||||
pdxInstanceFactory.writeObject(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return pdxInstanceFactory.create();
|
||||
}
|
||||
|
||||
protected PdxInstance toPdxInstance(final Enum enumeratedType) {
|
||||
return PdxInstanceFactoryImpl.createPdxEnum(enumeratedType.getClass().getName(), enumeratedType.name(),
|
||||
enumeratedType.ordinal(), (GemFireCacheImpl) gemfireCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveSimpleFunctionArguments() {
|
||||
functionArgumentResolver = new PdxFunctionArgumentResolver() {
|
||||
@Override public Method getFunctionAnnotatedMethod() {
|
||||
return getMethod(FunctionExecutions.class, "simpleMethod", Boolean.class, Character.class,
|
||||
Integer.class, Double.class, String.class);
|
||||
}
|
||||
};
|
||||
|
||||
Object[] expectedArguments = { Boolean.TRUE, 'C', 123, Math.PI, "TEST" };
|
||||
|
||||
FunctionContext mockFunctionContext = mock(FunctionContext.class, "testResolveSimpleFunctionArguments");
|
||||
|
||||
when(mockFunctionContext.getArguments()).thenReturn(expectedArguments);
|
||||
|
||||
Object[] actualArguments = functionArgumentResolver.resolveFunctionArguments(mockFunctionContext);
|
||||
|
||||
assertArguments(expectedArguments, actualArguments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNonSerializedApplicationDomainTypeFunctionArguments() {
|
||||
functionArgumentResolver = new PdxFunctionArgumentResolver() {
|
||||
@Override public Method getFunctionAnnotatedMethod() {
|
||||
return getMethod(FunctionExecutions.class, "nonSerializedMethod", Boolean.class, Person.class,
|
||||
Character.class, Person.class, Integer.class, Double.class, Gender.class, String.class);
|
||||
}
|
||||
};
|
||||
|
||||
Object[] expectedArguments = { Boolean.TRUE, createPerson("Jon", "Doe", Gender.MALE), 'C',
|
||||
createPerson("Jane", "Doe", Gender.FEMALE), 123, Math.PI, Gender.FEMALE, "test" };
|
||||
|
||||
FunctionContext mockFunctionContext = mock(FunctionContext.class, "testResolveNonSerializedApplicationDomainTypeFunctionArguments");
|
||||
|
||||
when(mockFunctionContext.getArguments()).thenReturn(expectedArguments);
|
||||
|
||||
Object[] actualArguments = functionArgumentResolver.resolveFunctionArguments(mockFunctionContext);
|
||||
|
||||
assertArguments(expectedArguments, actualArguments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveSerializedApplicationDomainTypeFunctionArguments() {
|
||||
functionArgumentResolver = new PdxFunctionArgumentResolver() {
|
||||
@Override public Method getFunctionAnnotatedMethod() {
|
||||
return getMethod(FunctionExecutions.class, "serializedMethod", Boolean.class, Person.class,
|
||||
String.class, Gender.class);
|
||||
}
|
||||
};
|
||||
|
||||
Person jackHandy = createPerson("Jack", "Handy", Gender.MALE);
|
||||
|
||||
Object[] serializedArguments = { Boolean.TRUE, toPdxInstance(jackHandy), "test", toPdxInstance(Gender.MALE) };
|
||||
Object[] expectedArguments = { Boolean.TRUE, jackHandy, "test", Gender.MALE };
|
||||
|
||||
FunctionContext mockFunctionContext = mock(FunctionContext.class, "testResolveSerializedApplicationDomainTypeFunctionArguments");
|
||||
|
||||
when(mockFunctionContext.getArguments()).thenReturn(serializedArguments);
|
||||
|
||||
Object[] actualArguments = functionArgumentResolver.resolveFunctionArguments(mockFunctionContext);
|
||||
|
||||
assertArguments(expectedArguments, actualArguments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveUnnecessaryDeserializationFunctionArguments() {
|
||||
functionArgumentResolver = new PdxFunctionArgumentResolver() {
|
||||
@Override public Method getFunctionAnnotatedMethod() {
|
||||
return getMethod(FunctionExecutions.class, "unnecessaryDeserializationMethod", Boolean.class,
|
||||
Object.class, String.class, PdxInstanceEnum.class);
|
||||
}
|
||||
};
|
||||
|
||||
Person sandyHandy = createPerson("Sandy", "Handy", Gender.FEMALE);
|
||||
|
||||
Object[] expectedArguments = { Boolean.TRUE, toPdxInstance(sandyHandy), "test", toPdxInstance(Gender.FEMALE) };
|
||||
|
||||
FunctionContext mockFunctionContext = mock(FunctionContext.class, "testResolveUnnecessaryDeserializationFunctionArguments");
|
||||
|
||||
when(mockFunctionContext.getArguments()).thenReturn(expectedArguments);
|
||||
|
||||
Object[] actualArguments = functionArgumentResolver.resolveFunctionArguments(mockFunctionContext);
|
||||
|
||||
assertArguments(expectedArguments, actualArguments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveUnresolvableApplicationDomainTypeFunctionArguments() {
|
||||
functionArgumentResolver = new PdxFunctionArgumentResolver() {
|
||||
@Override public Method getFunctionAnnotatedMethod() {
|
||||
return getMethod(FunctionExecutions.class, "unresolvableMethod", String.class, Object.class);
|
||||
}
|
||||
};
|
||||
|
||||
Map<String, Object> addressData = new HashMap<String, Object>(5);
|
||||
|
||||
addressData.put("@type", "org.example.Address");
|
||||
addressData.put("street", "100 Main St.");
|
||||
addressData.put("city", "Portland");
|
||||
addressData.put("state", "OR");
|
||||
addressData.put("zip", "12345");
|
||||
|
||||
Object[] expectedArguments = { "test", toPdxInstance(addressData) };
|
||||
|
||||
FunctionContext mockFunctionContext = mock(FunctionContext.class, "testResolveUnresolvableApplicationDomainTypeFunctionArguments");
|
||||
|
||||
when(mockFunctionContext.getArguments()).thenReturn(expectedArguments);
|
||||
|
||||
Object[] actualArguments = functionArgumentResolver.resolveFunctionArguments(mockFunctionContext);
|
||||
|
||||
assertArguments(expectedArguments, actualArguments);
|
||||
}
|
||||
|
||||
public static interface FunctionExecutions {
|
||||
|
||||
void simpleMethod(Boolean value1, Character value2, Integer value3, Double value4, String value5);
|
||||
|
||||
void nonSerializedMethod(Boolean value1, Person person1, Character value2, Integer value3, Person person2, Double value4, Gender gender, String value5);
|
||||
|
||||
void serializedMethod(Boolean value1, Person person, String value2, Gender gender);
|
||||
|
||||
void unnecessaryDeserializationMethod(Boolean value1, Object person, String value2, PdxInstanceEnum gender);
|
||||
|
||||
void unresolvableMethod(String value, Object pdxInstance);
|
||||
}
|
||||
|
||||
public static enum Gender {
|
||||
FEMALE,
|
||||
MALE
|
||||
}
|
||||
|
||||
public static class Person {
|
||||
|
||||
private final Gender gender;
|
||||
|
||||
private final String firstName;
|
||||
private final String lastName;
|
||||
|
||||
public Person(final String firstName, final String lastName, final Gender gender) {
|
||||
Assert.hasText(firstName, "The person's first name must be specified!");
|
||||
Assert.hasText(lastName, "The person's last name must be specified!");
|
||||
Assert.notNull(gender, "The person's gender must be specified!");
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public Gender getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Person)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Person that = (Person) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.getFirstName(), that.getFirstName())
|
||||
&& ObjectUtils.nullSafeEquals(this.getLastName(), that.getLastName())
|
||||
&& ObjectUtils.nullSafeEquals(this.getGender(), that.getGender());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashValue = 17;
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getFirstName());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getLastName());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getGender());
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%1$s %2$s is a %3$s", getFirstName(), getLastName(), getGender());
|
||||
}
|
||||
}
|
||||
|
||||
public static class PersonPdxSerializer implements PdxSerializer {
|
||||
|
||||
@Override
|
||||
public boolean toData(final Object obj, final PdxWriter out) {
|
||||
if (obj instanceof Person) {
|
||||
Person person = (Person) obj;
|
||||
out.writeString("firstName", person.getFirstName());
|
||||
out.writeString("lastName", person.getLastName());
|
||||
out.writeObject("gender", person.getGender());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromData(final Class<?> type, final PdxReader in) {
|
||||
if (Person.class.isAssignableFrom(type)) {
|
||||
return new Person(in.readString("firstName"), in.readString("lastName"),
|
||||
(Gender) in.readObject("gender"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.function.sample;
|
||||
|
||||
import org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest;
|
||||
import org.springframework.data.gemfire.function.annotation.OnServer;
|
||||
|
||||
import com.gemstone.gemfire.pdx.PdxInstance;
|
||||
|
||||
/**
|
||||
* The ApplicationDomainFunctionExecutions class defines a GemFire Client Cache Function execution targeted at a
|
||||
* GemFire Server.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest
|
||||
* @see org.springframework.data.gemfire.function.annotation.OnServer
|
||||
* @see com.gemstone.gemfire.pdx.PdxInstance
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@OnServer
|
||||
@SuppressWarnings("unused")
|
||||
public interface ApplicationDomainFunctionExecutions {
|
||||
|
||||
Class[] captureConvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
|
||||
ClientCacheFunctionExecutionWithPdxIntegrationTest.Person person,
|
||||
ClientCacheFunctionExecutionWithPdxIntegrationTest.Gender gender);
|
||||
|
||||
Class[] captureUnconvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
|
||||
Object person, Object gender);
|
||||
|
||||
String getAddressField(ClientCacheFunctionExecutionWithPdxIntegrationTest.Address address, String fieldName);
|
||||
|
||||
Object getDataField(PdxInstance data, String fieldName);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user