Fix bug to handle cache data import into client LOCAL Regions when no PDX type registry exists.

Resolves gh-91.
This commit is contained in:
John Blum
2020-06-10 23:16:11 -07:00
parent 98ee687a78
commit 5318782bfb
4 changed files with 183 additions and 3 deletions

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2020 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
*
* https://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.geode.boot.autoconfigure.data;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Profile;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
import org.springframework.geode.boot.autoconfigure.DataImportExportAutoConfiguration;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import example.app.golf.model.Golfer;
/**
* Integration Tests for {@link DataImportExportAutoConfiguration}.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.boot.autoconfigure.SpringBootApplication
* @see org.springframework.boot.test.context.SpringBootTest
* @see org.springframework.context.annotation.Profile
* @see org.springframework.data.gemfire.GemfireTemplate
* @see org.springframework.geode.boot.autoconfigure.DataImportExportAutoConfiguration
* @see org.springframework.test.context.ActiveProfiles
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.3.0
*/
@ActiveProfiles("IMPORT-LOCAL")
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = LocalClientCacheDataImportAutoConfigurationIntegrationTests.TestGeodeClientConfiguration.class,
properties = "spring.boot.data.gemfire.cache.data.import.active-profiles=IMPORT-LOCAL"
)
public class LocalClientCacheDataImportAutoConfigurationIntegrationTests {
@Autowired
@SuppressWarnings("unused")
private GemfireTemplate golfersTemplate;
@Test
public void golfersWereLoaded() {
assertThat(this.golfersTemplate).isNotNull();
assertThat(this.golfersTemplate.getRegion()).isNotNull();
assertThat(this.golfersTemplate.getRegion().getName()).isEqualTo("Golfers");
assertThat(this.golfersTemplate.getRegion()).hasSize(1);
Object value = this.golfersTemplate.get(1L);
assertThat(value).isInstanceOf(Golfer.class);
Golfer golfer = (Golfer) value;
assertThat(golfer).isNotNull();
assertThat(golfer.getId()).isEqualTo(1L);
assertThat(golfer.getName()).isEqualTo("John Blum");
assertThat(golfer.getHandicap()).isEqualTo(9);
}
@Profile("IMPORT-LOCAL")
@SpringBootApplication
@EnableEntityDefinedRegions(basePackageClasses = Golfer.class, clientRegionShortcut = ClientRegionShortcut.LOCAL)
static class TestGeodeClientConfiguration { }
}

View File

@@ -0,0 +1,6 @@
{
"@type" : "example.app.golf.model.Golfer",
"id" : 1,
"name" : "John Blum",
"handicap" : 9
}

View File

@@ -16,9 +16,12 @@
package org.springframework.geode.data.json.converter.support;
import org.apache.geode.pdx.JSONFormatter;
import org.apache.geode.pdx.JSONFormatterException;
import org.apache.geode.pdx.PdxInstance;
import org.springframework.geode.data.json.converter.JsonToObjectConverter;
import org.springframework.geode.data.json.converter.JsonToPdxConverter;
import org.springframework.geode.pdx.ObjectPdxInstanceAdapter;
import org.springframework.geode.pdx.PdxInstanceWrapper;
import org.springframework.lang.NonNull;
@@ -34,12 +37,62 @@ import org.springframework.lang.NonNull;
*/
public class JSONFormatterJsonToPdxConverter implements JsonToPdxConverter {
private JsonToObjectConverter converter = newJsonToObjectConverter();
// TODO configure via an SPIs
private JsonToObjectConverter newJsonToObjectConverter() {
return new JacksonJsonToObjectConverter();
}
/**
* Returns a reference to the configured {@link JsonToObjectConverter} used to convert from {@link String JSON}
* to an {@link Object}.
*
* @return a reference to the configured {@link JsonToObjectConverter}; never {@literal null}.
* @see org.springframework.geode.data.json.converter.JsonToObjectConverter
*/
protected @NonNull JsonToObjectConverter getJsonToObjectConverter() {
return this.converter;
}
/**
* @inheritDoc
*/
@Override
public final @NonNull PdxInstance convert(@NonNull String json) {
return convertJsonToPdx(json);
try {
return convertJsonToPdx(json);
}
catch (JSONFormatterException cause) {
return convertJsonToObjectToPdx(json);
}
}
/**
* Adapts the given {@link Object} as a {@link PdxInstance}.
*
* @param target {@link Object} to adapt as PDX; must not be {@literal null}.
* @return a {@link PdxInstance} representing the given {@link Object}.
* @see org.springframework.geode.pdx.ObjectPdxInstanceAdapter#from(Object)
* @see org.apache.geode.pdx.PdxInstance
*/
protected @NonNull PdxInstance adapt(@NonNull Object target) {
return ObjectPdxInstanceAdapter.from(target);
}
/**
* Converts the given {@link String JSON} into a {@link Object} and then adapts the {@link Object}
* as a {@link PdxInstance}.
*
* @param json {@link String JSON} to convert into an {@link Object} into PDX.
* @return a {@link PdxInstance} converted from the given {@link String JSON}.
* @see org.apache.geode.pdx.PdxInstance
* @see #getJsonToObjectConverter()
* @see #adapt(Object)
*/
protected @NonNull PdxInstance convertJsonToObjectToPdx(@NonNull String json) {
return adapt(getJsonToObjectConverter().convert(json));
}
/**
@@ -47,8 +100,6 @@ public class JSONFormatterJsonToPdxConverter implements JsonToPdxConverter {
*
* @param json {@link String} containing JSON to convert to PDX; must not be {@literal null}.
* @return JSON for the given {@link PdxInstance PDX}.
* @see org.springframework.geode.pdx.PdxInstanceWrapper#from(PdxInstance)
* @see org.apache.geode.pdx.JSONFormatter#fromJSON(String)
* @see org.apache.geode.pdx.PdxInstance
* @see #jsonFormatterFromJson(String)
* @see #wrap(PdxInstance)
@@ -74,6 +125,7 @@ public class JSONFormatterJsonToPdxConverter implements JsonToPdxConverter {
*
* @param pdxInstance {@link PdxInstance} to wrap.
* @return a new instance of {@link PdxInstanceWrapper} wrapping the given {@link PdxInstance}.
* @see org.springframework.geode.pdx.PdxInstanceWrapper#from(PdxInstance)
* @see org.springframework.geode.pdx.PdxInstanceWrapper
* @see org.apache.geode.pdx.PdxInstance
*/

View File

@@ -18,6 +18,7 @@ package org.springframework.geode.data.json.converter.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -25,10 +26,15 @@ import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.apache.geode.pdx.JSONFormatterException;
import org.apache.geode.pdx.PdxInstance;
import org.springframework.geode.data.json.converter.JsonToObjectConverter;
import org.springframework.geode.pdx.ObjectPdxInstanceAdapter;
import org.springframework.geode.pdx.PdxInstanceWrapper;
import example.app.crm.model.Customer;
/**
* Unit Tests for {@link JSONFormatterJsonToPdxConverter}.
*
@@ -36,7 +42,9 @@ import org.springframework.geode.pdx.PdxInstanceWrapper;
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.apache.geode.pdx.PdxInstance
* @see org.springframework.geode.data.json.converter.JsonToObjectConverter
* @see org.springframework.geode.data.json.converter.support.JSONFormatterJsonToPdxConverter
* @see org.springframework.geode.pdx.ObjectPdxInstanceAdapter
* @see org.springframework.geode.pdx.PdxInstanceWrapper
* @since 1.3.0
*/
@@ -62,4 +70,30 @@ public class JSONFormatterJsonToPdxConverterUnitTests {
verify(converter, times(1)).jsonFormatterFromJson(eq(json));
verify(converter, times(1)).wrap(eq(mockPdxInstance));
}
@Test
public void convertCallsConvertJsonToObjectToPdx() {
String json = "{ \"name\": \"Jon Doe\" }";
JsonToObjectConverter mockJsonToObjectConverter = mock(JsonToObjectConverter.class);
Customer jonDoe = Customer.newCustomer(1L, "Jon Doe");
JSONFormatterJsonToPdxConverter converter = spy(new JSONFormatterJsonToPdxConverter());
doThrow(new JSONFormatterException("TEST")).when(converter).convertJsonToPdx(eq(json));
doReturn(mockJsonToObjectConverter).when(converter).getJsonToObjectConverter();
doReturn(jonDoe).when(mockJsonToObjectConverter).convert(eq(json));
PdxInstance pdx = converter.convert(json);
assertThat(pdx).isInstanceOf(ObjectPdxInstanceAdapter.class);
assertThat(pdx.getObject()).isSameAs(jonDoe);
verify(converter, times(1)).convertJsonToPdx(eq(json));
verify(converter, times(1)).convertJsonToObjectToPdx(eq(json));
verify(converter, times(1)).getJsonToObjectConverter();
verify(mockJsonToObjectConverter, times(1)).convert(eq(json));
}
}