/* * 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).keys().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).keys().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).keys().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).keys().size()); } finally { System.setProperty(JSONFormatter.SORT_JSON_FIELD_NAMES_PROPERTY, "false"); } } }