| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You 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.apache.geode.pdx; |
| |
| import static org.apache.geode.distributed.ConfigurationProperties.*; |
| import static org.junit.Assert.*; |
| |
| import java.text.SimpleDateFormat; |
| import java.util.List; |
| |
| import com.fasterxml.jackson.core.JsonProcessingException; |
| import com.fasterxml.jackson.databind.DeserializationFeature; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import org.apache.geode.test.junit.categories.FlakyTest; |
| import org.apache.geode.test.junit.categories.SerializationTest; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| import org.apache.geode.cache.AttributesFactory; |
| import org.apache.geode.cache.Cache; |
| import org.apache.geode.cache.CacheFactory; |
| import org.apache.geode.cache.DataPolicy; |
| import org.apache.geode.cache.Region; |
| import org.apache.geode.cache.RegionAttributes; |
| import org.apache.geode.cache.server.CacheServer; |
| import org.apache.geode.internal.Assert; |
| import org.apache.geode.internal.cache.GemFireCacheImpl; |
| import org.apache.geode.pdx.internal.PdxInstanceImpl; |
| import org.apache.geode.pdx.internal.PeerTypeRegistration; |
| import org.apache.geode.test.junit.categories.IntegrationTest; |
| |
| @Category({IntegrationTest.class, SerializationTest.class}) |
| public class JSONFormatterJUnitTest { |
| |
| private GemFireCacheImpl c; |
| private final String PRIMITIVE_KV_STORE_REGION = "primitiveKVStore"; |
| |
| @Before |
| public void setUp() throws Exception { |
| this.c = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").setPdxReadSerialized(true) |
| .create(); |
| |
| // Create region, primitiveKVStore |
| final AttributesFactory<Object, Object> af1 = new AttributesFactory<Object, Object>(); |
| af1.setDataPolicy(DataPolicy.PARTITION); |
| final RegionAttributes<Object, Object> rAttributes = af1.create(); |
| c.createRegion(PRIMITIVE_KV_STORE_REGION, rAttributes); |
| } |
| |
| @After |
| public void tearDown() { |
| // shutdown and clean up the manager node. |
| this.c.close(); |
| } |
| |
| private void ValidatePdxInstanceToJsonConversion() { |
| |
| Cache c = CacheFactory.getAnyInstance(); |
| Region region = c.getRegion("primitiveKVStore"); |
| |
| TestObjectForJSONFormatter actualTestObject = new TestObjectForJSONFormatter(); |
| actualTestObject.defaultInitialization(); |
| |
| // Testcase-1: PdxInstance to Json conversion |
| // put Object and getvalue as Pdxinstance |
| region.put("201", actualTestObject); |
| Object receivedObject = region.get("201"); |
| |
| // PdxInstance->Json conversion |
| if (receivedObject instanceof PdxInstance) { |
| PdxInstance pi = (PdxInstance) receivedObject; |
| String json = JSONFormatter.toJSON(pi); |
| |
| verifyJsonWithJavaObject(json, actualTestObject); |
| } else { |
| fail("receivedObject is expected to be of type PdxInstance"); |
| } |
| |
| } |
| |
| // Testcase-2: validate Json->PdxInstance-->Java conversion |
| private void verifyJsonToPdxInstanceConversion() { |
| TestObjectForJSONFormatter expectedTestObject = new TestObjectForJSONFormatter(); |
| expectedTestObject.defaultInitialization(); |
| Cache c = CacheFactory.getAnyInstance(); |
| Region region = c.getRegion("primitiveKVStore"); |
| |
| // 1.gets pdxInstance using R.put() and R.get() |
| region.put("501", expectedTestObject); |
| Object receivedObject = region.get("501"); |
| if (receivedObject instanceof PdxInstance) { |
| PdxInstance expectedPI = (PdxInstance) receivedObject; |
| |
| // 2. Get the JSON string from actualTestObject using jackson ObjectMapper. |
| ObjectMapper objectMapper = new ObjectMapper(); |
| objectMapper.setDateFormat(new SimpleDateFormat("MM/dd/yyyy")); |
| objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| |
| String json; |
| try { |
| json = objectMapper.writeValueAsString(expectedTestObject); |
| |
| String jsonWithClassType = expectedTestObject.addClassTypeToJson(json); |
| |
| // 3. Get PdxInstance from the Json String and Validate pi.getObject() API. |
| PdxInstance actualPI = JSONFormatter.fromJSON(jsonWithClassType); |
| // Note: expectedPI will contains those fields that are part of toData() |
| // expectedPI.className = "org.apache.geode.pdx.TestObjectForJSONFormatter" |
| // actualPI will contains all the fields that are member of the class. |
| // actualPI..className = __GEMFIRE_JSON |
| // and hence actualPI.equals(expectedPI) will returns false. |
| |
| Object actualTestObject = actualPI.getObject(); |
| |
| if (actualTestObject instanceof TestObjectForJSONFormatter) { |
| boolean isObjectEqual = actualTestObject.equals(expectedTestObject); |
| Assert.assertTrue(isObjectEqual, |
| "actualTestObject and expectedTestObject should be equal"); |
| } else { |
| fail("actualTestObject is expected to be of type PdxInstance"); |
| } |
| } catch (JsonProcessingException e1) { |
| fail("JsonProcessingException occurred:" + e1.getMessage()); |
| } catch (JSONException e) { |
| fail("JSONException occurred:" + e.getMessage()); |
| } |
| } else { |
| fail("receivedObject is expected to be of type PdxInstance"); |
| } |
| } |
| |
| // Testcase-2: validate Json->PdxInstance-->Java conversion |
| private void verifyJsonToPdxInstanceConversionWithJSONFormatter() { |
| TestObjectForJSONFormatter expectedTestObject = new TestObjectForJSONFormatter(); |
| expectedTestObject.defaultInitialization(); |
| Cache c = CacheFactory.getAnyInstance(); |
| Region region = c.getRegion("primitiveKVStore"); |
| |
| // 1.gets pdxInstance using R.put() and R.get() |
| region.put("501", expectedTestObject); |
| Object receivedObject = region.get("501"); |
| assertEquals("receivedObject is expected to be of type PdxInstance", PdxInstanceImpl.class, |
| receivedObject.getClass()); |
| |
| PdxInstance expectedPI = (PdxInstance) receivedObject; |
| |
| String json; |
| try { |
| json = JSONFormatter.toJSON(expectedPI); |
| |
| String jsonWithClassType = expectedTestObject.addClassTypeToJson(json); |
| |
| // 3. Get PdxInstance from the Json String and Validate pi.getObject() API. |
| PdxInstance actualPI = JSONFormatter.fromJSON(jsonWithClassType); |
| // Note: expectedPI will contains those fields that are part of toData() |
| // expectedPI.className = "org.apache.geode.pdx.TestObjectForJSONFormatter" |
| // actualPI will contains all the fields that are member of the class. |
| // actualPI..className = __GEMFIRE_JSON |
| // and hence actualPI.equals(expectedPI) will returns false. |
| |
| Object actualTestObject = actualPI.getObject(); |
| |
| assertEquals("receivedObject is expected to be of type PdxInstance", |
| TestObjectForJSONFormatter.class, actualTestObject.getClass()); |
| |
| assertEquals("actualTestObject and expectedTestObject should be equal", expectedTestObject, |
| actualTestObject); |
| } catch (JSONException e) { |
| fail("JSONException occurred:" + e.getMessage()); |
| } |
| } |
| |
| private void verifyJsonWithJavaObject(String json, TestObjectForJSONFormatter testObject) { |
| try { |
| JSONObject jsonObject = new JSONObject(json); |
| |
| // Testcase-1: Validate json string against the pdxInstance. |
| // validation for primitive types |
| assertEquals("VerifyPdxInstanceToJson: Int type values are not matched", |
| testObject.getP_int(), jsonObject.getInt(testObject.getP_intFN())); |
| assertEquals("VerifyPdxInstanceToJson: long type values are not matched", |
| testObject.getP_long(), jsonObject.getLong(testObject.getP_longFN())); |
| |
| // validation for wrapper types |
| assertEquals("VerifyPdxInstanceToJson: Boolean type values are not matched", |
| testObject.getW_bool().booleanValue(), jsonObject.getBoolean(testObject.getW_boolFN())); |
| assertEquals("VerifyPdxInstanceToJson: Float type values are not matched", |
| testObject.getW_double().doubleValue(), jsonObject.getDouble(testObject.getW_doubleFN()), |
| 0); |
| assertEquals("VerifyPdxInstanceToJson: bigDec type values are not matched", |
| testObject.getW_bigDec().longValue(), jsonObject.getLong(testObject.getW_bigDecFN())); |
| |
| // vlidation for array types |
| assertEquals("VerifyPdxInstanceToJson: Byte[] type values are not matched", |
| (int) testObject.getW_byteArray()[1], |
| jsonObject.getJSONArray(testObject.getW_byteArrayFN()).getInt(1)); |
| assertEquals("VerifyPdxInstanceToJson: Double[] type values are not matched", |
| testObject.getW_doubleArray()[0], |
| jsonObject.getJSONArray(testObject.getW_doubleArrayFN()).getDouble(0), 0); |
| assertEquals("VerifyPdxInstanceToJson: String[] type values are not matched", |
| testObject.getW_strArray()[2], |
| jsonObject.getJSONArray(testObject.getW_strArrayFN()).getString(2)); |
| |
| // validation for collection types |
| assertEquals("VerifyPdxInstanceToJson: list type values are not matched", |
| testObject.getC_list().get(0), |
| jsonObject.getJSONArray(testObject.getC_listFN()).getString(0)); |
| |
| assertEquals("VerifyPdxInstanceToJson: stack type values are not matched", |
| testObject.getC_stack().get(2), |
| jsonObject.getJSONArray(testObject.getC_stackFN()).getString(2)); |
| |
| // validation for Map |
| assertEquals("VerifyPdxInstanceToJson: Map type values are not matched", |
| testObject.getM_empByCity().get("Ahmedabad").get(0).getFname(), |
| jsonObject.getJSONObject(testObject.getM_empByCityFN()).getJSONArray("Ahmedabad") |
| .getJSONObject(0).getString("fname")); |
| |
| // validation Enum |
| assertEquals("VerifyPdxInstanceToJson: Enum type values are not matched", |
| testObject.getDay().toString(), jsonObject.getString(testObject.getDayFN())); |
| |
| } catch (JSONException e) { |
| throw new AssertionError( |
| "Error in VerifyPdxInstanceToJson, Malformed json, can not create JSONArray from it", e); |
| } |
| } |
| |
| @Test |
| public void testJSONFormatterAPIs() { |
| ValidatePdxInstanceToJsonConversion(); |
| verifyJsonToPdxInstanceConversion(); |
| verifyJsonToPdxInstanceConversionWithJSONFormatter(); |
| } |
| |
| /** |
| * this test validates json document, where field has value and null Then it verifies we create |
| * only one pdx type id for that |
| */ |
| @Test |
| public void testJSONStringAsPdxObject() { |
| |
| Cache c = CacheFactory.getAnyInstance(); |
| |
| int pdxTypes = 0; |
| |
| if (c.getRegion(PeerTypeRegistration.REGION_FULL_PATH) != null) { |
| pdxTypes = c.getRegion(PeerTypeRegistration.REGION_FULL_PATH).keySet().size(); |
| } |
| |
| Region region = c.getRegion("primitiveKVStore"); |
| |
| String js = "{name:\"ValueExist\", age:14}"; |
| |
| region.put(1, JSONFormatter.fromJSON(js)); |
| |
| String js2 = "{name:null, age:14}"; |
| |
| region.put(2, JSONFormatter.fromJSON(js2)); |
| |
| assertEquals(pdxTypes + 1, c.getRegion(PeerTypeRegistration.REGION_FULL_PATH).keySet().size()); |
| } |
| |
| @Test |
| public void testJSONStringSortedFields() { |
| |
| try { |
| System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "true"); |
| |
| Cache c = CacheFactory.getAnyInstance(); |
| |
| Region region = c.getRegion("primitiveKVStore"); |
| |
| String js = "{b:\"b\", age:14, c:\"c' go\", bb:23}"; |
| |
| region.put(1, JSONFormatter.fromJSON(js)); |
| |
| PdxInstance ret = (PdxInstance) region.get(1); |
| List<String> fieldNames = ret.getFieldNames(); |
| |
| assertEquals("There should be four fields", 4, fieldNames.size()); |
| |
| boolean sorted = true; |
| for (int i = 0; i < fieldNames.size() - 1; i++) { |
| if (fieldNames.get(i).compareTo(fieldNames.get(i + 1)) >= 0) { |
| sorted = false; |
| } |
| } |
| |
| assertTrue("Json fields should be sorted", sorted); |
| |
| // Now do put with another jsonstring with same fields but different order |
| // then verify we don't create another pdxtype |
| |
| int pdxTypes = 0; |
| |
| if (c.getRegion(PeerTypeRegistration.REGION_FULL_PATH) != null) { |
| pdxTypes = c.getRegion(PeerTypeRegistration.REGION_FULL_PATH).keySet().size(); |
| } |
| |
| String js2 = "{c:\"c' go\", bb:23, b:\"b\", age:14 }"; |
| region.put(2, JSONFormatter.fromJSON(js2)); |
| |
| assertEquals(pdxTypes, c.getRegion(PeerTypeRegistration.REGION_FULL_PATH).keySet().size()); |
| |
| } finally { |
| System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "false"); |
| } |
| } |
| } |
| |
| |