summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2019-02-27 17:42:52 -0500
committerJim Hahn <jrh3@att.com>2019-02-27 22:05:42 -0500
commite6b3fdd85893ea9a2ccff6e1e7be573e211d0c2c (patch)
tree1b9fbfc1be55ff5f4543da8603dc09d2fa933dbf
parentdf8ba3401bb8ca7056a4cf4fcb2a202ae454b7e0 (diff)
Add additional encode and decode methods to Coder
Also: Updated some comments and renamed a few parameters. Removed a "throws" for a RuntimeException. Short-circuit some calls. Typo in comment. Let gson create the JsonWriter. Renamed a few more parameters. Change-Id: I22e48c2191820c2a3d0743200edca79bd74353e7 Issue-ID: POLICY-1444 Signed-off-by: Jim Hahn <jrh3@att.com>
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java65
-rw-r--r--utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java142
-rw-r--r--utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java154
-rw-r--r--utils/src/test/resources/org/onap/policy/common/utils/coder/StandardCoder.json1
4 files changed, 347 insertions, 15 deletions
diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java
index 41db218b..66a308f7 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java
@@ -20,6 +20,12 @@
package org.onap.policy.common.utils.coder;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
/**
* JSON encoder and decoder.
*/
@@ -35,7 +41,34 @@ public interface Coder {
String encode(Object object) throws CoderException;
/**
- * Decodes a json string into an object.
+ * Encodes an object into json, writing to the given target.
+ *
+ * @param target target to which to write the encoded json
+ * @param object object to be encoded
+ * @throws CoderException if an error occurs
+ */
+ void encode(Writer target, Object object) throws CoderException;
+
+ /**
+ * Encodes an object into json, writing to the given target.
+ *
+ * @param target target to which to write the encoded json
+ * @param object object to be encoded
+ * @throws CoderException if an error occurs
+ */
+ void encode(OutputStream target, Object object) throws CoderException;
+
+ /**
+ * Encodes an object into json, writing to the given target.
+ *
+ * @param target target to which to write the encoded json
+ * @param object object to be encoded
+ * @throws CoderException if an error occurs
+ */
+ void encode(File target, Object object) throws CoderException;
+
+ /**
+ * Decodes json into an object.
*
* @param json json string to be decoded
* @param clazz class of object to be decoded
@@ -43,4 +76,34 @@ public interface Coder {
* @throws CoderException if an error occurs
*/
<T> T decode(String json, Class<T> clazz) throws CoderException;
+
+ /**
+ * Decodes json into an object, reading it from the given source.
+ *
+ * @param source source from which to read the json string to be decoded
+ * @param clazz class of object to be decoded
+ * @return the object represented by the given json string
+ * @throws CoderException if an error occurs
+ */
+ <T> T decode(Reader source, Class<T> clazz) throws CoderException;
+
+ /**
+ * Decodes json into an object, reading it from the given source.
+ *
+ * @param source source from which to read the json string to be decoded
+ * @param clazz class of object to be decoded
+ * @return the object represented by the given json string
+ * @throws CoderException if an error occurs
+ */
+ <T> T decode(InputStream source, Class<T> clazz) throws CoderException;
+
+ /**
+ * Decodes json into an object, reading it from the given source.
+ *
+ * @param source source from which to read the json string to be decoded
+ * @param clazz class of object to be decoded
+ * @return the object represented by the given json string
+ * @throws CoderException if an error occurs
+ */
+ <T> T decode(File source, Class<T> clazz) throws CoderException;
}
diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java
index 4c7a55c2..389720f9 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java
@@ -21,6 +21,18 @@
package org.onap.policy.common.utils.coder;
import com.google.gson.Gson;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
/**
* JSON encoder and decoder using the "standard" mechanism, which is currently gson.
@@ -50,6 +62,42 @@ public class StandardCoder implements Coder {
}
@Override
+ public void encode(Writer target, Object object) throws CoderException {
+ try {
+ toJson(target, object);
+
+ } catch (RuntimeException | IOException e) {
+ throw new CoderException(e);
+ }
+ }
+
+ @Override
+ public void encode(OutputStream target, Object object) throws CoderException {
+ try {
+ Writer wtr = makeWriter(target);
+ toJson(wtr, object);
+
+ // flush, but don't close
+ wtr.flush();
+
+ } catch (RuntimeException | IOException e) {
+ throw new CoderException(e);
+ }
+ }
+
+ @Override
+ public void encode(File target, Object object) throws CoderException {
+ try (Writer wtr = makeWriter(target)) {
+ toJson(wtr, object);
+
+ // no need to flush or close here
+
+ } catch (RuntimeException | IOException e) {
+ throw new CoderException(e);
+ }
+ }
+
+ @Override
public <T> T decode(String json, Class<T> clazz) throws CoderException {
try {
return fromJson(json, clazz);
@@ -59,9 +107,81 @@ public class StandardCoder implements Coder {
}
}
+ @Override
+ public <T> T decode(Reader source, Class<T> clazz) throws CoderException {
+ try {
+ return fromJson(source, clazz);
+
+ } catch (RuntimeException e) {
+ throw new CoderException(e);
+ }
+ }
+
+ @Override
+ public <T> T decode(InputStream source, Class<T> clazz) throws CoderException {
+ try {
+ return fromJson(makeReader(source), clazz);
+
+ } catch (RuntimeException e) {
+ throw new CoderException(e);
+ }
+ }
+
+ @Override
+ public <T> T decode(File source, Class<T> clazz) throws CoderException {
+ try (Reader input = makeReader(source)) {
+ return fromJson(input, clazz);
+
+ } catch (RuntimeException | IOException e) {
+ throw new CoderException(e);
+ }
+ }
+
// the remaining methods are wrappers that can be overridden by junit tests
/**
+ * Makes a writer for the given file.
+ *
+ * @param target file of interest
+ * @return a writer for the file
+ * @throws FileNotFoundException if the file cannot be created
+ */
+ protected Writer makeWriter(File target) throws FileNotFoundException {
+ return makeWriter(new FileOutputStream(target));
+ }
+
+ /**
+ * Makes a writer for the given stream.
+ *
+ * @param target stream of interest
+ * @return a writer for the stream
+ */
+ protected Writer makeWriter(OutputStream target) {
+ return new OutputStreamWriter(target, StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Makes a reader for the given file.
+ *
+ * @param source file of interest
+ * @return a reader for the file
+ * @throws FileNotFoundException if the file does not exist
+ */
+ protected Reader makeReader(File source) throws FileNotFoundException {
+ return makeReader(new FileInputStream(source));
+ }
+
+ /**
+ * Makes a reader for the given stream.
+ *
+ * @param source stream of interest
+ * @return a reader for the stream
+ */
+ protected Reader makeReader(InputStream source) {
+ return new InputStreamReader(source, StandardCharsets.UTF_8);
+ }
+
+ /**
* Encodes an object into json, without catching exceptions.
*
* @param object object to be encoded
@@ -72,6 +192,17 @@ public class StandardCoder implements Coder {
}
/**
+ * Encodes an object into json, without catching exceptions.
+ *
+ * @param target target to which to write the encoded json
+ * @param object object to be encoded
+ * @throws IOException if an I/O error occurs
+ */
+ protected void toJson(Writer target, Object object) throws IOException {
+ GSON.toJson(object, object.getClass(), target);
+ }
+
+ /**
* Decodes a json string into an object, without catching exceptions.
*
* @param json json string to be decoded
@@ -81,4 +212,15 @@ public class StandardCoder implements Coder {
protected <T> T fromJson(String json, Class<T> clazz) {
return GSON.fromJson(json, clazz);
}
+
+ /**
+ * Decodes a json string into an object, without catching exceptions.
+ *
+ * @param source source from which to read the json string to be decoded
+ * @param clazz class of object to be decoded
+ * @return the object represented by the given json string
+ */
+ protected <T> T fromJson(Reader source, Class<T> clazz) {
+ return GSON.fromJson(source, clazz);
+ }
}
diff --git a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java
index 80157d02..25cce748 100644
--- a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java
+++ b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java
@@ -22,17 +22,35 @@ package org.onap.policy.common.utils.coder;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
public class StandardCoderTest {
+ private static final String EXPECTED_EXCEPTION = "expected exception";
+
+ private static final JsonParseException jpe = new JsonParseException(EXPECTED_EXCEPTION);
+ private static final IOException ioe = new IOException(EXPECTED_EXCEPTION);
private StandardCoder coder;
@@ -42,32 +60,140 @@ public class StandardCoderTest {
}
@Test
- public void testEncode() throws Exception {
- List<Integer> arr = Arrays.asList(100, 110);
- assertEquals("[100,110]", coder.encode(arr));
+ public void testEncodeObject() throws Exception {
+ List<Integer> arr = Arrays.asList(1100, 1110);
+ assertEquals("[1100,1110]", coder.encode(arr));
// test exception case
- JsonParseException jpe = new JsonParseException("expected exception");
-
- coder = spy(coder);
+ coder = spy(new StandardCoder());
when(coder.toJson(arr)).thenThrow(jpe);
-
assertThatThrownBy(() -> coder.encode(arr)).isInstanceOf(CoderException.class).hasCause(jpe);
}
@Test
- public void testDecode() throws Exception {
- String text = "[200,210]";
- assertEquals(text, coder.decode(text, JsonElement.class).toString());
+ public void testEncodeWriterObject() throws Exception {
+ List<Integer> arr = Arrays.asList(1200, 1210);
+ StringWriter wtr = new StringWriter();
+ coder.encode(wtr, arr);
+ assertEquals("[1200,1210]", wtr.toString());
- // test exception case
- JsonParseException jpe = new JsonParseException("expected exception");
+ // test json exception
+ coder = spy(new StandardCoder());
+ doThrow(jpe).when(coder).toJson(wtr, arr);
+ assertThatThrownBy(() -> coder.encode(wtr, arr)).isInstanceOf(CoderException.class).hasCause(jpe);
+ }
- coder = spy(coder);
- when(coder.fromJson(text, JsonElement.class)).thenThrow(jpe);
+ @Test
+ public void testEncodeOutputStreamObject() throws Exception {
+ List<Integer> arr = Arrays.asList(1300, 1310);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ coder.encode(stream, arr);
+ assertEquals("[1300,1310]", stream.toString("UTF-8"));
+
+ // test json exception
+ Writer wtr = new StringWriter();
+ coder = spy(new StandardCoder());
+ when(coder.makeWriter(stream)).thenReturn(wtr);
+ doThrow(jpe).when(coder).toJson(wtr, arr);
+ assertThatThrownBy(() -> coder.encode(stream, arr)).isInstanceOf(CoderException.class).hasCause(jpe);
+ // test exception when flushed
+ wtr = spy(new OutputStreamWriter(stream));
+ doThrow(ioe).when(wtr).flush();
+ coder = spy(new StandardCoder());
+ when(coder.makeWriter(stream)).thenReturn(wtr);
+ assertThatThrownBy(() -> coder.encode(stream, arr)).isInstanceOf(CoderException.class).hasCause(ioe);
+ }
+
+ @Test
+ public void testEncodeFileObject() throws Exception {
+ File file = new File(getClass().getResource(StandardCoder.class.getSimpleName() + ".json").getFile() + "X");
+ file.deleteOnExit();
+ List<Integer> arr = Arrays.asList(1400, 1410);
+ coder.encode(file, arr);
+ assertEquals("[1400,1410]", new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8));
+
+ // test json exception
+ StringWriter wtr = new StringWriter();
+ coder = spy(new StandardCoder());
+ when(coder.makeWriter(file)).thenReturn(wtr);
+ doThrow(jpe).when(coder).toJson(wtr, arr);
+ assertThatThrownBy(() -> coder.encode(file, arr)).isInstanceOf(CoderException.class).hasCause(jpe);
+
+ // test exception when closed
+ coder = spy(new StandardCoder());
+ wtr = spy(new StringWriter());
+ doThrow(ioe).when(wtr).close();
+ coder = spy(new StandardCoder());
+ when(coder.makeWriter(file)).thenReturn(wtr);
+ assertThatThrownBy(() -> coder.encode(file, arr)).isInstanceOf(CoderException.class).hasCause(ioe);
+ }
+
+ @Test
+ public void testDecodeStringClass() throws Exception {
+ String text = "[2200,2210]";
+ assertEquals(text, coder.decode(text, JsonElement.class).toString());
+
+ // test json exception
+ coder = spy(new StandardCoder());
+ when(coder.fromJson(text, JsonElement.class)).thenThrow(jpe);
assertThatThrownBy(() -> coder.decode(text, JsonElement.class)).isInstanceOf(CoderException.class)
.hasCause(jpe);
}
+ @Test
+ public void testDecodeReaderClass() throws Exception {
+ String text = "[2300,2310]";
+ assertEquals(text, coder.decode(new StringReader(text), JsonElement.class).toString());
+
+ // test json exception
+ coder = spy(new StandardCoder());
+ StringReader rdr = new StringReader(text);
+ when(coder.fromJson(rdr, JsonElement.class)).thenThrow(jpe);
+ assertThatThrownBy(() -> coder.decode(rdr, JsonElement.class)).isInstanceOf(CoderException.class).hasCause(jpe);
+ }
+
+ @Test
+ public void testDecodeInputStreamClass() throws Exception {
+ String text = "[2400,2410]";
+ assertEquals(text,
+ coder.decode(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)), JsonElement.class)
+ .toString());
+
+ // test json exception
+ coder = spy(new StandardCoder());
+ ByteArrayInputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
+ StringReader rdr = new StringReader(text);
+ when(coder.makeReader(stream)).thenReturn(rdr);
+ when(coder.fromJson(rdr, JsonElement.class)).thenThrow(jpe);
+ assertThatThrownBy(() -> coder.decode(stream, JsonElement.class)).isInstanceOf(CoderException.class)
+ .hasCause(jpe);
+ }
+
+ @Test
+ public void testDecodeFileClass() throws Exception {
+ File file = new File(getClass().getResource(StandardCoder.class.getSimpleName() + ".json").getFile());
+ String text = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
+ assertEquals(text, coder.decode(file, JsonElement.class).toString());
+
+ // test FileNotFoundException case
+ assertThatThrownBy(() -> coder.decode(new File("unknown-file"), JsonElement.class))
+ .isInstanceOf(CoderException.class).hasCauseInstanceOf(FileNotFoundException.class);
+
+ // test json exception
+ Reader rdr = new StringReader(text);
+ coder = spy(new StandardCoder());
+ when(coder.makeReader(file)).thenReturn(rdr);
+ when(coder.fromJson(rdr, JsonElement.class)).thenThrow(jpe);
+ assertThatThrownBy(() -> coder.decode(file, JsonElement.class)).isInstanceOf(CoderException.class)
+ .hasCause(jpe);
+
+ // test IOException case
+ rdr = spy(new FileReader(file));
+ doThrow(ioe).when(rdr).close();
+ coder = spy(new StandardCoder());
+ when(coder.makeReader(file)).thenReturn(rdr);
+ assertThatThrownBy(() -> coder.decode(file, JsonElement.class)).isInstanceOf(CoderException.class)
+ .hasCause(ioe);
+ }
}
diff --git a/utils/src/test/resources/org/onap/policy/common/utils/coder/StandardCoder.json b/utils/src/test/resources/org/onap/policy/common/utils/coder/StandardCoder.json
new file mode 100644
index 00000000..b50b53b4
--- /dev/null
+++ b/utils/src/test/resources/org/onap/policy/common/utils/coder/StandardCoder.json
@@ -0,0 +1 @@
+[3000,3010] \ No newline at end of file