Remove duplicate code from type adapters 85/118085/2
authorJim Hahn <jrh3@att.com>
Thu, 18 Feb 2021 22:15:07 +0000 (17:15 -0500)
committerJim Hahn <jrh3@att.com>
Thu, 18 Feb 2021 22:24:26 +0000 (17:24 -0500)
Extracted a common superclass, StringTypeAdapter, out of the gson type
adapter classes.

Issue-ID: POLICY-2914
Change-Id: I4bbd2a6e8372e7f42c4952ba9ff03eed97473fb2
Signed-off-by: Jim Hahn <jrh3@att.com>
gson/src/main/java/org/onap/policy/common/gson/InstantTypeAdapter.java
gson/src/main/java/org/onap/policy/common/gson/LocalDateTimeTypeAdapter.java
gson/src/main/java/org/onap/policy/common/gson/LocalDateTypeAdapter.java
gson/src/main/java/org/onap/policy/common/gson/OffsetDateTimeTypeAdapter.java
gson/src/main/java/org/onap/policy/common/gson/OffsetTimeTypeAdapter.java
gson/src/main/java/org/onap/policy/common/gson/StringTypeAdapter.java [new file with mode: 0644]
gson/src/main/java/org/onap/policy/common/gson/ZoneOffsetTypeAdapter.java
gson/src/main/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapter.java
gson/src/test/java/org/onap/policy/common/gson/InstantTypeAdapterTest.java
gson/src/test/java/org/onap/policy/common/gson/StringTypeAdapterTest.java [new file with mode: 0644]
gson/src/test/java/org/onap/policy/common/gson/ZonedDateTimeTypeAdapterTest.java

index 9ebf2ba..bad66af 100644 (file)
@@ -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.
 
 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<Instant> {
+public class InstantTypeAdapter extends StringTypeAdapter<Instant> {
 
-    @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);
     }
 }
index 4d87ca4..5dc597e 100644 (file)
@@ -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.
 
 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<LocalDateTime> {
-    private DateTimeFormatter formatter;
+public class LocalDateTimeTypeAdapter extends StringTypeAdapter<LocalDateTime> {
 
     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));
     }
 }
index 8e33e46..0f666e5 100644 (file)
 
 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<LocalDate> {
-    private DateTimeFormatter formatter;
+public class LocalDateTypeAdapter extends StringTypeAdapter<LocalDate> {
 
     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));
     }
 }
index faf5ffd..3f046b0 100644 (file)
 
 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<OffsetDateTime> {
-    private DateTimeFormatter formatter;
+public class OffsetDateTimeTypeAdapter extends StringTypeAdapter<OffsetDateTime> {
 
     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));
     }
 }
index 49a7d25..895b9de 100644 (file)
 
 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<OffsetTime> {
-    private DateTimeFormatter formatter;
+public class OffsetTimeTypeAdapter extends StringTypeAdapter<OffsetTime> {
 
     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 (file)
index 0000000..2248169
--- /dev/null
@@ -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<T> extends TypeAdapter<T> {
+    private final String exMessage;
+    private final Function<String, T> deserializer;
+    private final Function<T, String> 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<String, T> deserializer, Function<T, String> 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);
+        }
+    }
+}
index eb91ac4..60758ff 100644 (file)
 
 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<ZoneOffset>  {
+public class ZoneOffsetTypeAdapter extends StringTypeAdapter<ZoneOffset> {
 
-    @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);
     }
 }
index 7777e70..928fae9 100644 (file)
 
 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<ZonedDateTime> {
-    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME;
-
-    private final DateTimeFormatter formatter;
-
+public class ZonedDateTimeTypeAdapter extends StringTypeAdapter<ZonedDateTime> {
 
     /**
      * 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));
     }
 }
index 97219d0..68f54ed 100644 (file)
@@ -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 (file)
index 0000000..f35677c
--- /dev/null
@@ -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<MyData> {
+        public MyAdapter() {
+            super("data", string -> new MyData(Integer.parseInt(string)), data -> String.valueOf(data.num));
+        }
+    }
+}
index 766a979..032533e 100644 (file)
@@ -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());
     }