From d7df51a00c9ec3eca4fa5e6f784ba4d52d4f9f89 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Tue, 12 Feb 2019 11:20:13 -0500 Subject: Add jackson behavior for fields Added classes to make gson treat fields as jackson does. Added check for input OR output fields. Corrected comment about annotation names. Removed trailing spaces. Extracted some string constants. Fixed checkstyle issue. Change-Id: I665b31774086d72a5a95bee6cf3486a019b72402 Issue-ID: POLICY-1428 Signed-off-by: Jim Hahn --- .../gson/JacksonFieldAdapterFactoryTest.java | 214 +++++++++++++++++++++ .../gson/internal/FieldDeserializerTest.java | 109 +++++++++++ .../common/gson/internal/FieldSerializerTest.java | 96 +++++++++ 3 files changed, 419 insertions(+) create mode 100644 gson/src/test/java/org/onap/policy/common/gson/JacksonFieldAdapterFactoryTest.java create mode 100644 gson/src/test/java/org/onap/policy/common/gson/internal/FieldDeserializerTest.java create mode 100644 gson/src/test/java/org/onap/policy/common/gson/internal/FieldSerializerTest.java (limited to 'gson/src/test') diff --git a/gson/src/test/java/org/onap/policy/common/gson/JacksonFieldAdapterFactoryTest.java b/gson/src/test/java/org/onap/policy/common/gson/JacksonFieldAdapterFactoryTest.java new file mode 100644 index 00000000..9d4b4388 --- /dev/null +++ b/gson/src/test/java/org/onap/policy/common/gson/JacksonFieldAdapterFactoryTest.java @@ -0,0 +1,214 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.gson; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.onap.policy.common.gson.JacksonExclusionStrategy; +import org.onap.policy.common.gson.JacksonFieldAdapterFactory; +import org.onap.policy.common.gson.annotation.GsonJsonIgnore; +import org.onap.policy.common.gson.annotation.GsonJsonProperty; + +public class JacksonFieldAdapterFactoryTest { + + private static JacksonFieldAdapterFactory factory = new JacksonFieldAdapterFactory(); + + private static Gson gson = new GsonBuilder().setExclusionStrategies(new JacksonExclusionStrategy()) + .registerTypeAdapterFactory(factory).create(); + + @Test + public void testCreate() { + // unhandled types + assertNull(factory.create(gson, TypeToken.get(JsonElement.class))); + assertNull(factory.create(gson, TypeToken.get(NothingToSerialize.class))); + + assertNotNull(factory.create(gson, TypeToken.get(Data.class))); + assertNotNull(factory.create(gson, TypeToken.get(Derived.class))); + + Data data = new Data(); + + // deserialize using fields that aren't in the Data object + Data data2 = gson.fromJson("{\"abc\":100}", Data.class); + assertEquals(data.toString(), data2.toString()); + + // now work with valid fields + data.id = 10; + data.text = "hello"; + + String result = gson.toJson(data); + data2 = gson.fromJson(result, Data.class); + assertEquals(data.toString(), data2.toString()); + + // should also work with derived types + Derived der = new Derived(); + der.setId(20); + der.text = "world"; + der.unserialized = "abc"; + + result = gson.toJson(der); + + // should not contain the unserialized field + assertFalse(result.contains("abc")); + + Derived der2 = gson.fromJson(result, Derived.class); + der.unserialized = null; + assertEquals(der.toString(), der2.toString()); + } + + @Test + public void testCreate_Lists() { + DataList lst = new DataList(); + lst.theList = new ArrayList<>(); + lst.theList.add(new Data(200, "text 20")); + lst.theList.add(new Data(210, "text 21")); + + String result = gson.toJson(lst); + assertEquals("{'theList':[{'my-id':200,'text':'text 20'},{'my-id':210,'text':'text 21'}]}".replace('\'', '"'), + result); + + DataList lst2 = gson.fromJson(result, DataList.class); + assertEquals(stripIdent(lst.toString()), stripIdent(lst2.toString())); + assertEquals(Data.class, lst2.theList.get(0).getClass()); + } + + @Test + public void testCreate_OnlyOutProps() { + InFieldIgnored data = new InFieldIgnored(); + data.value = "out only"; + + // field should be serialized + String result = gson.toJson(data); + assertEquals("{'value':'out only'}".replace('\'', '"'), result); + + // field should NOT be deserialized + data = gson.fromJson(result, InFieldIgnored.class); + assertNull(data.value); + } + + @Test + public void testCreate_OnlyInProps() { + OutFieldIgnored data = new OutFieldIgnored(); + data.value = "in only"; + + // field should NOT be serialized + String result = gson.toJson(data); + assertEquals("{}", result); + + // field should NOT be deserialized + data = gson.fromJson("{'value':'in only'}".replace('\'', '"'), OutFieldIgnored.class); + assertEquals("in only", data.value); + } + + /** + * Object identifiers may change with each execution, so this method is used to strip + * the identifier from the text string so that the strings will still match across + * different runs. + * + * @param text text from which to strip the identifier + * @return the text, without the identifier + */ + private String stripIdent(String text) { + return text.replaceFirst("@\\w+", "@"); + } + + private static class Data { + @GsonJsonProperty("my-id") + private int id; + + public String text; + + public Data() { + super(); + } + + public Data(int id, String text) { + this.id = id; + this.text = text; + } + + public void setId(int id) { + this.id = id; + } + + @Override + public String toString() { + return "Data [id=" + id + ", text=" + text + "]"; + } + } + + private static class Derived extends Data { + // not serialized + private String unserialized; + + @Override + public String toString() { + return "Derived [unserialized=" + unserialized + ", toString()=" + super.toString() + "]"; + } + } + + private static class DataList { + @GsonJsonProperty + private List theList; + } + + protected static class NothingToSerialize { + // not serialized + protected String unserialized; + } + + /** + * This has a field that should show up in the "output" list, but not in the "input" + * list, because the method will override it. + */ + private static class InFieldIgnored { + @GsonJsonProperty("value") + private String value; + + @GsonJsonIgnore + public void setValue(String value) { + this.value = value; + } + } + + /** + * This has a field that should show up in the "input" list, but not in the "output" + * list, because the method will override it. + */ + private static class OutFieldIgnored { + @GsonJsonProperty("value") + private String value; + + @GsonJsonIgnore + public String getValue() { + return value; + } + } +} diff --git a/gson/src/test/java/org/onap/policy/common/gson/internal/FieldDeserializerTest.java b/gson/src/test/java/org/onap/policy/common/gson/internal/FieldDeserializerTest.java new file mode 100644 index 00000000..62bab231 --- /dev/null +++ b/gson/src/test/java/org/onap/policy/common/gson/internal/FieldDeserializerTest.java @@ -0,0 +1,109 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.gson.internal; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import java.util.List; +import org.junit.Test; +import org.onap.policy.common.gson.JacksonExclusionStrategy; +import org.onap.policy.common.gson.internal.DataAdapterFactory.Data; +import org.onap.policy.common.gson.internal.FieldDeserializer; + +public class FieldDeserializerTest { + private static final String TEXT_FIELD_NAME = "text"; + private static final String LIST_FIELD_NAME = "listField"; + private static final String INITIAL_VALUE = "initial value"; + private static final String NEW_VALUE = "new value"; + + private static DataAdapterFactory dataAdapter = new DataAdapterFactory(); + + private static Gson gson = new GsonBuilder().registerTypeAdapterFactory(dataAdapter) + .setExclusionStrategies(new JacksonExclusionStrategy()).create(); + + private FieldDeserializer deser; + + private String text; + + private List listField; + + @Test + public void testGetFromTree() throws Exception { + deser = new FieldDeserializer(gson, FieldDeserializerTest.class.getDeclaredField(TEXT_FIELD_NAME)); + + JsonObject json = new JsonObject(); + + // no value in tree - text remains unchanged + text = INITIAL_VALUE; + deser.getFromTree(json, this); + assertEquals(text, INITIAL_VALUE); + + // null value in tree - text remains unchanged + json.add(TEXT_FIELD_NAME, JsonNull.INSTANCE); + deser.getFromTree(json, this); + assertEquals(text, INITIAL_VALUE); + + // now assign a value - text should be changed now + json.addProperty(TEXT_FIELD_NAME, NEW_VALUE); + + deser.getFromTree(json, this); + assertEquals(text, NEW_VALUE); + + /* + * check list field + */ + deser = new FieldDeserializer(gson, FieldDeserializerTest.class.getDeclaredField(LIST_FIELD_NAME)); + + json.add(LIST_FIELD_NAME, DataAdapterFactory.makeArray()); + + dataAdapter.reset(); + listField = null; + deser.getFromTree(json, this); + + assertTrue(dataAdapter.isDataRead()); + assertEquals(DataAdapterFactory.makeList().toString(), listField.toString()); + } + + @Test + public void testGetFromTree_SetEx() throws Exception { + deser = new FieldDeserializer(gson, FieldDeserializerTest.class.getDeclaredField(TEXT_FIELD_NAME)) { + @Override + public Object fromJsonTree(JsonElement tree) { + // return an int, which won't fit in a String - cause an exception + return 10; + } + }; + + JsonObject json = new JsonObject(); + json.addProperty(TEXT_FIELD_NAME, NEW_VALUE); + + assertThatThrownBy(() -> deser.getFromTree(json, this)).isInstanceOf(JsonParseException.class) + .hasMessage(FieldDeserializer.SET_ERR + FieldDeserializerTest.class.getName() + ".text"); + } +} diff --git a/gson/src/test/java/org/onap/policy/common/gson/internal/FieldSerializerTest.java b/gson/src/test/java/org/onap/policy/common/gson/internal/FieldSerializerTest.java new file mode 100644 index 00000000..18167fc0 --- /dev/null +++ b/gson/src/test/java/org/onap/policy/common/gson/internal/FieldSerializerTest.java @@ -0,0 +1,96 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.common.gson.internal; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import java.util.List; +import org.junit.Test; +import org.onap.policy.common.gson.JacksonExclusionStrategy; +import org.onap.policy.common.gson.internal.DataAdapterFactory.Data; +import org.onap.policy.common.gson.internal.FieldSerializer; + +public class FieldSerializerTest { + private static final String TEXT_FIELD_NAME = "text"; + private static final String LIST_FIELD_NAME = "listField"; + + private static DataAdapterFactory dataAdapter = new DataAdapterFactory(); + + private static Gson gson = new GsonBuilder().registerTypeAdapterFactory(dataAdapter) + .setExclusionStrategies(new JacksonExclusionStrategy()).create(); + + private FieldSerializer ser; + + protected String text; + + private List listField; + + @Test + public void testAddToTree() throws Exception { + ser = new FieldSerializer(gson, FieldSerializerTest.class.getDeclaredField(TEXT_FIELD_NAME)); + + // serialize null value first + text = null; + + JsonObject json = new JsonObject(); + ser.addToTree(this, json); + assertTrue(json.get(TEXT_FIELD_NAME).isJsonNull()); + + // serialize an actual value + text = "hello"; + ser.addToTree(this, json); + assertEquals("hello", json.get(TEXT_FIELD_NAME).getAsString()); + + /* + * check list field + */ + listField = DataAdapterFactory.makeList(); + + ser = new FieldSerializer(gson, FieldSerializerTest.class.getDeclaredField(LIST_FIELD_NAME)); + + dataAdapter.reset(); + JsonElement tree = ser.toJsonTree(listField); + assertTrue(dataAdapter.isDataWritten()); + assertEquals(DataAdapterFactory.ENCODED_LIST, tree.toString()); + } + + @Test + public void testAddToTree_GetEx() throws Exception { + ser = new FieldSerializer(gson, FieldSerializerTest.class.getDeclaredField(TEXT_FIELD_NAME)) { + @Override + protected Object getFromObject(Object source) throws IllegalAccessException { + throw new IllegalAccessException("expected exception"); + } + }; + + text = "world"; + + assertThatThrownBy(() -> ser.addToTree(this, new JsonObject())).isInstanceOf(JsonParseException.class) + .hasMessage(FieldSerializer.GET_ERR + FieldSerializerTest.class.getName() + ".text"); + } +} -- cgit 1.2.3-korg