diff --git a/spring-geode-autoconfigure/src/test/java/org/springframework/geode/boot/autoconfigure/data/LocalClientCacheDataImportAutoConfigurationIntegrationTests.java b/spring-geode-autoconfigure/src/test/java/org/springframework/geode/boot/autoconfigure/data/LocalClientCacheDataImportAutoConfigurationIntegrationTests.java new file mode 100644 index 00000000..d4bc963b --- /dev/null +++ b/spring-geode-autoconfigure/src/test/java/org/springframework/geode/boot/autoconfigure/data/LocalClientCacheDataImportAutoConfigurationIntegrationTests.java @@ -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 { } + +} diff --git a/spring-geode-autoconfigure/src/test/resources/data-golfers.json b/spring-geode-autoconfigure/src/test/resources/data-golfers.json new file mode 100644 index 00000000..1200391b --- /dev/null +++ b/spring-geode-autoconfigure/src/test/resources/data-golfers.json @@ -0,0 +1,6 @@ +{ + "@type" : "example.app.golf.model.Golfer", + "id" : 1, + "name" : "John Blum", + "handicap" : 9 +} diff --git a/spring-geode/src/main/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverter.java b/spring-geode/src/main/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverter.java index bdefcbba..42f9fe08 100644 --- a/spring-geode/src/main/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverter.java +++ b/spring-geode/src/main/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverter.java @@ -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 */ diff --git a/spring-geode/src/test/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverterUnitTests.java b/spring-geode/src/test/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverterUnitTests.java index cf1084d5..dfe7c3ba 100644 --- a/spring-geode/src/test/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverterUnitTests.java +++ b/spring-geode/src/test/java/org/springframework/geode/data/json/converter/support/JSONFormatterJsonToPdxConverterUnitTests.java @@ -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)); + } }