From 758cd2e691950843415515ba6df2295679bd938b Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Thu, 18 Feb 2021 17:15:07 -0500 Subject: Remove duplicate code from type adapters Extracted a common superclass, StringTypeAdapter, out of the gson type adapter classes. Issue-ID: POLICY-2914 Change-Id: I4bbd2a6e8372e7f42c4952ba9ff03eed97473fb2 Signed-off-by: Jim Hahn --- .../policy/common/gson/InstantTypeAdapter.java | 38 ++------- .../common/gson/LocalDateTimeTypeAdapter.java | 39 +-------- .../policy/common/gson/LocalDateTypeAdapter.java | 37 +-------- .../common/gson/OffsetDateTimeTypeAdapter.java | 37 +-------- .../policy/common/gson/OffsetTimeTypeAdapter.java | 37 +-------- .../onap/policy/common/gson/StringTypeAdapter.java | 76 +++++++++++++++++ .../policy/common/gson/ZoneOffsetTypeAdapter.java | 33 +------- .../common/gson/ZonedDateTimeTypeAdapter.java | 43 +--------- .../policy/common/gson/InstantTypeAdapterTest.java | 12 +-- .../policy/common/gson/StringTypeAdapterTest.java | 94 ++++++++++++++++++++++ .../common/gson/ZonedDateTimeTypeAdapterTest.java | 12 +-- 11 files changed, 195 insertions(+), 263 deletions(-) create mode 100644 gson/src/main/java/org/onap/policy/common/gson/StringTypeAdapter.java create mode 100644 gson/src/test/java/org/onap/policy/common/gson/StringTypeAdapterTest.java (limited to 'gson') diff --git a/gson/src/main/java/org/onap/policy/common/gson/InstantTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/InstantTypeAdapter.java index 9ebf2baa..bad66af3 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/InstantTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/InstantTypeAdapter.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2020-2021 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. @@ -20,41 +20,17 @@ package org.onap.policy.common.gson; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.time.Instant; -import java.time.format.DateTimeParseException; /** * GSON Type Adapter for "Instant" fields, that uses the standard ISO_INSTANT formatter. */ -public class InstantTypeAdapter extends TypeAdapter { +public class InstantTypeAdapter extends StringTypeAdapter { - @Override - public void write(JsonWriter out, Instant value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - out.value(value.toString()); - } - } - - @Override - public Instant read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - String text = in.nextString(); - return Instant.parse(text); - } - - } catch (DateTimeParseException e) { - throw new IOException("invalid date", e); - } + /** + * Constructs an adapter. + */ + public InstantTypeAdapter() { + super("date", Instant::parse, Instant::toString); } } diff --git a/gson/src/main/java/org/onap/policy/common/gson/LocalDateTimeTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/LocalDateTimeTypeAdapter.java index 4d87ca46..5dc597e2 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/LocalDateTimeTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/LocalDateTimeTypeAdapter.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2020-2021 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. @@ -20,53 +20,20 @@ package org.onap.policy.common.gson; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; /** * GSON Type Adapter for "LocalDateTime" fields, that uses the standard * ISO_LOCAL_DATE_TIME formatter, by default. */ -public class LocalDateTimeTypeAdapter extends TypeAdapter { - private DateTimeFormatter formatter; +public class LocalDateTimeTypeAdapter extends StringTypeAdapter { public LocalDateTimeTypeAdapter() { this(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } public LocalDateTimeTypeAdapter(DateTimeFormatter formatter) { - this.formatter = formatter; - } - - @Override - public LocalDateTime read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - return LocalDateTime.parse(in.nextString(), formatter); - } - - } catch (DateTimeParseException e) { - throw new JsonParseException("invalid date", e); - } - } - - @Override - public void write(JsonWriter out, LocalDateTime value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - String text = value.format(formatter); - out.value(text); - } + super("date", string -> LocalDateTime.parse(string, formatter), value -> value.format(formatter)); } } diff --git a/gson/src/main/java/org/onap/policy/common/gson/LocalDateTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/LocalDateTypeAdapter.java index 8e33e464..0f666e5e 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/LocalDateTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/LocalDateTypeAdapter.java @@ -20,49 +20,16 @@ package org.onap.policy.common.gson; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -public class LocalDateTypeAdapter extends TypeAdapter { - private DateTimeFormatter formatter; +public class LocalDateTypeAdapter extends StringTypeAdapter { public LocalDateTypeAdapter() { this(DateTimeFormatter.ISO_LOCAL_DATE); } public LocalDateTypeAdapter(DateTimeFormatter formatter) { - this.formatter = formatter; - } - - @Override - public LocalDate read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - return LocalDate.parse(in.nextString(), formatter); - } - - } catch (DateTimeParseException e) { - throw new JsonParseException("invalid date", e); - } - } - - @Override - public void write(JsonWriter out, LocalDate value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - String text = value.format(formatter); - out.value(text); - } + super("date", string -> LocalDate.parse(string, formatter), value -> value.format(formatter)); } } diff --git a/gson/src/main/java/org/onap/policy/common/gson/OffsetDateTimeTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/OffsetDateTimeTypeAdapter.java index faf5ffd1..3f046b01 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/OffsetDateTimeTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/OffsetDateTimeTypeAdapter.java @@ -20,49 +20,16 @@ package org.onap.policy.common.gson; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -public class OffsetDateTimeTypeAdapter extends TypeAdapter { - private DateTimeFormatter formatter; +public class OffsetDateTimeTypeAdapter extends StringTypeAdapter { public OffsetDateTimeTypeAdapter() { this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); } public OffsetDateTimeTypeAdapter(DateTimeFormatter formatter) { - this.formatter = formatter; - } - - @Override - public OffsetDateTime read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - return OffsetDateTime.parse(in.nextString(), formatter); - } - - } catch (DateTimeParseException e) { - throw new JsonParseException("invalid date", e); - } - } - - @Override - public void write(JsonWriter out, OffsetDateTime value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - String text = value.format(formatter); - out.value(text); - } + super("date", string -> OffsetDateTime.parse(string, formatter), value -> value.format(formatter)); } } diff --git a/gson/src/main/java/org/onap/policy/common/gson/OffsetTimeTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/OffsetTimeTypeAdapter.java index 49a7d25d..895b9de6 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/OffsetTimeTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/OffsetTimeTypeAdapter.java @@ -20,49 +20,16 @@ package org.onap.policy.common.gson; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.time.OffsetTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -public class OffsetTimeTypeAdapter extends TypeAdapter { - private DateTimeFormatter formatter; +public class OffsetTimeTypeAdapter extends StringTypeAdapter { public OffsetTimeTypeAdapter() { this(DateTimeFormatter.ISO_OFFSET_TIME); } public OffsetTimeTypeAdapter(DateTimeFormatter formatter) { - this.formatter = formatter; - } - - @Override - public OffsetTime read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - return OffsetTime.parse(in.nextString(), formatter); - } - - } catch (DateTimeParseException e) { - throw new JsonParseException("invalid time", e); - } - } - - @Override - public void write(JsonWriter out, OffsetTime value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - String text = value.format(formatter); - out.value(text); - } + super("time", string -> OffsetTime.parse(string, formatter), value -> value.format(formatter)); } } diff --git a/gson/src/main/java/org/onap/policy/common/gson/StringTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/StringTypeAdapter.java new file mode 100644 index 00000000..22481697 --- /dev/null +++ b/gson/src/main/java/org/onap/policy/common/gson/StringTypeAdapter.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2021 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 com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.function.Function; + +/** + * GSON Type Adapter for fields that are encoded as Strings. + */ +public class StringTypeAdapter extends TypeAdapter { + private final String exMessage; + private final Function deserializer; + private final Function serializer; + + /** + * Constructs an adapter. + * + * @param type type of value, used in exception messages + * @param deserializer function used to deserialize a String into a value + * @param serializer function used to serialize a value into a String + */ + public StringTypeAdapter(String type, Function deserializer, Function serializer) { + this.exMessage = "invalid " + type; + this.deserializer = deserializer; + this.serializer = serializer; + } + + @Override + public T read(JsonReader in) throws IOException { + try { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } else { + return deserializer.apply(in.nextString()); + } + + } catch (RuntimeException e) { + throw new JsonParseException(exMessage, e); + } + } + + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + String text = serializer.apply(value); + out.value(text); + } + } +} diff --git a/gson/src/main/java/org/onap/policy/common/gson/ZoneOffsetTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/ZoneOffsetTypeAdapter.java index eb91ac4f..60758ff3 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/ZoneOffsetTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/ZoneOffsetTypeAdapter.java @@ -20,38 +20,11 @@ package org.onap.policy.common.gson; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; -import java.time.DateTimeException; import java.time.ZoneOffset; -public class ZoneOffsetTypeAdapter extends TypeAdapter { +public class ZoneOffsetTypeAdapter extends StringTypeAdapter { - @Override - public ZoneOffset read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - return ZoneOffset.of(in.nextString()); - } - - } catch (DateTimeException e) { - throw new JsonParseException("invalid zone", e); - } - } - - @Override - public void write(JsonWriter out, ZoneOffset value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - out.value(value.toString()); - } + public ZoneOffsetTypeAdapter() { + super("zone", ZoneOffset::of, ZoneOffset::toString); } } diff --git a/gson/src/main/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapter.java b/gson/src/main/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapter.java index 7777e702..928fae95 100644 --- a/gson/src/main/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapter.java +++ b/gson/src/main/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapter.java @@ -20,63 +20,28 @@ package org.onap.policy.common.gson; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; /** * GSON Type Adapter for "ZonedDateTime" fields, that uses the standard * ISO_ZONED_DATE_TIME formatter. */ -public class ZonedDateTimeTypeAdapter extends TypeAdapter { - private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME; - - private final DateTimeFormatter formatter; - +public class ZonedDateTimeTypeAdapter extends StringTypeAdapter { /** * Constructs an adapter that uses the ISO_ZONED_DATE_TIME formatter. */ public ZonedDateTimeTypeAdapter() { - this(DEFAULT_FORMATTER); + this(DateTimeFormatter.ISO_ZONED_DATE_TIME); } /** * Constructs an adapter that uses the specified formatter for reading and writing. + * * @param formatter date-time formatter */ public ZonedDateTimeTypeAdapter(DateTimeFormatter formatter) { - this.formatter = formatter; - } - - @Override - public ZonedDateTime read(JsonReader in) throws IOException { - try { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } else { - return ZonedDateTime.parse(in.nextString(), formatter); - } - - } catch (DateTimeParseException e) { - throw new JsonParseException("invalid date", e); - } - } - - @Override - public void write(JsonWriter out, ZonedDateTime value) throws IOException { - if (value == null) { - out.nullValue(); - } else { - String text = value.format(formatter); - out.value(text); - } + super("date", string -> ZonedDateTime.parse(string, formatter), value -> value.format(formatter)); } } diff --git a/gson/src/test/java/org/onap/policy/common/gson/InstantTypeAdapterTest.java b/gson/src/test/java/org/onap/policy/common/gson/InstantTypeAdapterTest.java index 97219d0d..68f54ed8 100644 --- a/gson/src/test/java/org/onap/policy/common/gson/InstantTypeAdapterTest.java +++ b/gson/src/test/java/org/onap/policy/common/gson/InstantTypeAdapterTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2020-2021 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. @@ -53,16 +53,6 @@ public class InstantTypeAdapterTest { String json2 = json.replace("2020", "invalid-date"); assertThatThrownBy(() -> gson.fromJson(json2, InterestingFields.class)).isInstanceOf(JsonParseException.class) .hasMessageContaining("invalid date"); - - // null output - data.instant = null; - json = gson.toJson(data); - data2 = gson.fromJson(json, InterestingFields.class); - assertEquals(data.toString(), data2.toString()); - - // null input - data2 = gson.fromJson("{\"instant\":null}", InterestingFields.class); - assertEquals(data.toString(), data2.toString()); } diff --git a/gson/src/test/java/org/onap/policy/common/gson/StringTypeAdapterTest.java b/gson/src/test/java/org/onap/policy/common/gson/StringTypeAdapterTest.java new file mode 100644 index 00000000..f35677cd --- /dev/null +++ b/gson/src/test/java/org/onap/policy/common/gson/StringTypeAdapterTest.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2021 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.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.junit.Test; + +public class StringTypeAdapterTest { + private static Gson gson = new GsonBuilder().registerTypeAdapter(MyData.class, new MyAdapter()).create(); + private static final int TEST_NUM1 = 10; + private static final int TEST_NUM3 = 30; + + @Test + public void test() { + InterestingFields data = new InterestingFields(); + data.data1 = new MyData(TEST_NUM1); + data.data2 = null; + data.data3 = new MyData(TEST_NUM3); + + String json = gson.toJson(data); + + // instant should be encoded as a number, without quotes + assertThat(json).contains("10", "30"); + + InterestingFields data2 = gson.fromJson(json, InterestingFields.class); + assertEquals(data.toString(), data2.toString()); + + // try when the string is invalid + String json2 = json.replace("30", "invalid-value"); + assertThatThrownBy(() -> gson.fromJson(json2, InterestingFields.class)).isInstanceOf(JsonParseException.class) + .hasMessageContaining("invalid data"); + + // null output + data = new InterestingFields(); + json = gson.toJson(data); + data2 = gson.fromJson(json, InterestingFields.class); + assertEquals(data.toString(), data2.toString()); + + // null input + data2 = gson.fromJson("{\"data1\":null, \"data1\":null, \"data1\":null}", InterestingFields.class); + assertEquals(data.toString(), data2.toString()); + + // empty input + data2 = gson.fromJson("{}", InterestingFields.class); + assertEquals(data.toString(), data2.toString()); + } + + @Getter + @ToString + @AllArgsConstructor + private static class MyData { + private int num; + } + + @ToString + private static class InterestingFields { + private MyData data1; + private MyData data2; + private MyData data3; + } + + private static class MyAdapter extends StringTypeAdapter { + public MyAdapter() { + super("data", string -> new MyData(Integer.parseInt(string)), data -> String.valueOf(data.num)); + } + } +} diff --git a/gson/src/test/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapterTest.java b/gson/src/test/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapterTest.java index 766a979d..032533eb 100644 --- a/gson/src/test/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapterTest.java +++ b/gson/src/test/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapterTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * ONAP * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2020-2021 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. @@ -53,16 +53,6 @@ public class ZonedDateTimeTypeAdapterTest { String json2 = json.replace("2020", "invalid-date"); assertThatThrownBy(() -> gson.fromJson(json2, InterestingFields.class)).isInstanceOf(JsonParseException.class) .hasMessageContaining("invalid date"); - - // null output - data.date = null; - json = gson.toJson(data); - data2 = gson.fromJson(json, InterestingFields.class); - assertEquals(data.toString(), data2.toString()); - - // null input - data2 = gson.fromJson("{\"date\":null}", InterestingFields.class); - assertEquals(data.toString(), data2.toString()); } -- cgit 1.2.3-korg