From 367eb34e3806225e98fea2a85cf4772249e20cb3 Mon Sep 17 00:00:00 2001 From: devjeonghwan Date: Mon, 21 Aug 2023 17:30:22 +0900 Subject: [PATCH] Reformat README.md usage and Add `of` method to create dense reader/writer --- ...e__com_esotericsoftware_kryo_5_0_0_RC1.xml | 11 - ...dle__com_esotericsoftware_minlog_1_3_0.xml | 11 - ...com_esotericsoftware_reflectasm_1_11_7.xml | 11 - ...ackson_core_jackson_annotations_2_13_2.xml | 11 - ...erxml_jackson_core_jackson_core_2_13_2.xml | 14 - ...jackson_core_jackson_databind_2_13_2_2.xml | 14 - ...radle__com_google_code_gson_gson_2_8_9.xml | 11 - ..._org_apiguardian_apiguardian_api_1_1_2.xml | 11 - ...adle__org_jetbrains_annotations_22_0_0.xml | 11 - ..._junit_jupiter_junit_jupiter_api_5_8_2.xml | 11 - ...nit_jupiter_junit_jupiter_engine_5_8_2.xml | 11 - ..._platform_junit_platform_commons_1_8_2.xml | 11 - ...t_platform_junit_platform_engine_1_8_2.xml | 11 - .../Gradle__org_objenesis_objenesis_2_6.xml | 11 - ...radle__org_opentest4j_opentest4j_1_2_0.xml | 11 - README.md | 280 ++++++++++-------- .../codec/dense/reader/InputStreamReader.java | 15 +- .../dense/writer/OutputStreamWriter.java | 15 +- 18 files changed, 177 insertions(+), 304 deletions(-) delete mode 100644 .idea/libraries/Gradle__com_esotericsoftware_kryo_5_0_0_RC1.xml delete mode 100644 .idea/libraries/Gradle__com_esotericsoftware_minlog_1_3_0.xml delete mode 100644 .idea/libraries/Gradle__com_esotericsoftware_reflectasm_1_11_7.xml delete mode 100644 .idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml delete mode 100644 .idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_13_2.xml delete mode 100644 .idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml delete mode 100644 .idea/libraries/Gradle__com_google_code_gson_gson_2_8_9.xml delete mode 100644 .idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml delete mode 100644 .idea/libraries/Gradle__org_jetbrains_annotations_22_0_0.xml delete mode 100644 .idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_8_2.xml delete mode 100644 .idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml delete mode 100644 .idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_8_2.xml delete mode 100644 .idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_8_2.xml delete mode 100644 .idea/libraries/Gradle__org_objenesis_objenesis_2_6.xml delete mode 100644 .idea/libraries/Gradle__org_opentest4j_opentest4j_1_2_0.xml diff --git a/.idea/libraries/Gradle__com_esotericsoftware_kryo_5_0_0_RC1.xml b/.idea/libraries/Gradle__com_esotericsoftware_kryo_5_0_0_RC1.xml deleted file mode 100644 index 1eff7af..0000000 --- a/.idea/libraries/Gradle__com_esotericsoftware_kryo_5_0_0_RC1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_esotericsoftware_minlog_1_3_0.xml b/.idea/libraries/Gradle__com_esotericsoftware_minlog_1_3_0.xml deleted file mode 100644 index b1b116b..0000000 --- a/.idea/libraries/Gradle__com_esotericsoftware_minlog_1_3_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_esotericsoftware_reflectasm_1_11_7.xml b/.idea/libraries/Gradle__com_esotericsoftware_reflectasm_1_11_7.xml deleted file mode 100644 index 3364313..0000000 --- a/.idea/libraries/Gradle__com_esotericsoftware_reflectasm_1_11_7.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml b/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml deleted file mode 100644 index 2553398..0000000 --- a/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_13_2.xml b/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_13_2.xml deleted file mode 100644 index 8b1adfd..0000000 --- a/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_13_2.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml b/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml deleted file mode 100644 index af3e336..0000000 --- a/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_google_code_gson_gson_2_8_9.xml b/.idea/libraries/Gradle__com_google_code_gson_gson_2_8_9.xml deleted file mode 100644 index ee99a23..0000000 --- a/.idea/libraries/Gradle__com_google_code_gson_gson_2_8_9.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml b/.idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml deleted file mode 100644 index c32e243..0000000 --- a/.idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_annotations_22_0_0.xml b/.idea/libraries/Gradle__org_jetbrains_annotations_22_0_0.xml deleted file mode 100644 index 9b98629..0000000 --- a/.idea/libraries/Gradle__org_jetbrains_annotations_22_0_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_8_2.xml b/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_8_2.xml deleted file mode 100644 index 60ca08f..0000000 --- a/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_8_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml b/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml deleted file mode 100644 index b9bc9a3..0000000 --- a/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_8_2.xml b/.idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_8_2.xml deleted file mode 100644 index ca1c45c..0000000 --- a/.idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_8_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_8_2.xml b/.idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_8_2.xml deleted file mode 100644 index d1d20da..0000000 --- a/.idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_8_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_objenesis_objenesis_2_6.xml b/.idea/libraries/Gradle__org_objenesis_objenesis_2_6.xml deleted file mode 100644 index 33ae966..0000000 --- a/.idea/libraries/Gradle__org_objenesis_objenesis_2_6.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_opentest4j_opentest4j_1_2_0.xml b/.idea/libraries/Gradle__org_opentest4j_opentest4j_1_2_0.xml deleted file mode 100644 index b904752..0000000 --- a/.idea/libraries/Gradle__org_opentest4j_opentest4j_1_2_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 679eb1e..9b18743 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@

-Opack is a Java library that can serialize/deserialize between Java objects and common objects(OpackValue). Also, common objects can be encoded or decoded as JSON or Bytes(Dense). +Opack is a Java library that can serialize/deserialize between Java objects and common objects(OpackValue). Also, common +objects can be encoded or decoded as JSON or Bytes(Dense). **We faster then GSON and Kryo.** (See [tests](./src/test/java/com/realtimetech/opack/test/performance))
@@ -28,10 +29,11 @@ Opack is a Java library that can serialize/deserialize between Java objects and Jackson: 6412ms Opack : 6404ms ``` -
+ ### Simple flow +

@@ -40,139 +42,162 @@ Opack is a Java library that can serialize/deserialize between Java objects and

- ### Download Gradle: + ```gradle dependencies { - implementation 'com.realtimetech:opack:0.0.11' + implementation 'com.realtimetech:opack:0.0.9' } ``` Maven: + ```xml + - com.realtimetech - opack - 0.0.11 + com.realtimetech + opack + 0.0.9 ``` ### Usage + #### 1. Serialize + ```java -Opacker opacker = new Opacker.Builder().create(); +public class Usage { + public static void main(String[] arguments) { + Opacker opacker = new Opacker.Builder().create(); -SomeObject someObject = new SomeObject(); + SomeObject someObject = new SomeObject(); -OpackValue opackValue = opacker.serialize(someObject); + OpackValue opackValue = opacker.serialize(someObject); + } +} ``` #### 2. Deserialize + ```java -Opacker opacker = new Opacker.Builder() - .setContextStackInitialSize(128) // (Optional) Creation size of stack for processing - .setValueStackInitialSize(512) // (Optional) Creation size of stack for processing - - .setEnableWrapListElementType(false) // (Optional) When converting elements of a list, record the type as well - .setEnableWrapMapElementType(false) // (Optional) When converting elements of a map, record the type as well - .setEnableConvertEnumToOrdinal(false) // (Optional) Convert enum to ordinal or name - .setEnableConvertRecursiveDependencyToNull(false); // (Optional) Convert recursive depandency, record null - - .create(); - -OpackValue serializedSomeObject = /** See Serialize Usage **/; - -SomeObject someObject = opacker.deserialize(SomeObject.class, serializedSomeObject); +public class Usage { + public static void main(String[] arguments) { + Opacker opacker = new Opacker.Builder() + .setContextStackInitialSize(128) // (Optional) Creation size of stack for processing + .setValueStackInitialSize(512) // (Optional) Creation size of stack for processing + + .setEnableWrapListElementType(false) // (Optional) When converting elements of a list, record the type as well + .setEnableWrapMapElementType(false) // (Optional) When converting elements of a map, record the type as well + .setEnableConvertEnumToOrdinal(false) // (Optional) Convert enum to ordinal or name + .setEnableConvertRecursiveDependencyToNull(false) // (Optional) Convert recursive depandency, record null + .create(); + + OpackValue serializedSomeObject = null; + + SomeObject someObject = opacker.deserialize(SomeObject.class, serializedSomeObject); + } +} ``` #### 3. Json Codec + ```java -JsonCodec jsonCodec = new JsonCodec.Builder() - .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing - .setEncodeStringBufferSize(1024) // (Optional) Creation size of stack for processing - .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing - - .setAllowOpackValueToKeyValue(false) // (Optional) Accepts Objct or Array as Key of Json Object - .setEnableConvertCharacterToString(false) // (Optional) Convert character to string instead of character int value - .setUsePrettyFormat(false) // (Optional) When encoding, it prints formatted - - .create(); - -OpackValue opackValue = /** See Serialize Usage **/; - -/* - Encode - */ -String json = jsonCodec.encode(opackValue); -// Or -Writer writer = new StringWriter(); -jsonCodec.encode(writer, opackValue); - -/* - Decode - */ -OpackValue decodedOpackValue = jsonCodec.decode(json); +public class Usage { + public static void main(String[] arguments) { + JsonCodec jsonCodec = new JsonCodec.Builder() + .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing + .setEncodeStringBufferSize(1024) // (Optional) Creation size of stack for processing + .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing + + .setAllowOpackValueToKeyValue(false) // (Optional) Accepts Object or Array as Key of Json Object + .setEnableConvertCharacterToString(false) // (Optional) Convert character to string instead of character int value + .setUsePrettyFormat(false) // (Optional) When encoding, it prints formatted + + .create(); + + OpackValue opackValue = /* See Serialize Usage */; + + // Encode Basic + String json = jsonCodec.encode(opackValue); + + // Encode with Java IO Writer + Writer writer = /* Java IO Writer */; + jsonCodec.encode(writer, opackValue); + + // Decode Basic + OpackValue decodedOpackValue = jsonCodec.decode(json); + } +} ``` #### 4. Dense Codec + ```java -DenseCodec denseCodec = new DenseCodec.Builder() - .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing - .setEncodeOutputBufferInitialSize(1024) // (Optional) Creation size of stack for processing - .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing - - .setIgnoreVersionCompare(false) // (Optional) Ignore compare dense codec version in data - - .create(); - -OpackValue opackValue = /** See Serialize Usage **/; - -/* - Encode - */ -byte[] bytes = denseCodec.encode(opackValue); -// Or -OutputStream outputStream = new ByteArrayOutputStream(); -denseCodec.encode(outputStream, opackValue); - -/* - Decode - */ -OpackValue decodedOpackValue1 = denseCodec.decode(bytes); -// Or -InputStream inputStream = new ByteArrayInputStream(bytes); -OpackValue decodedOpackValue2 = denseCodec.decode(inputStream); +public class Usage { + public static void main(String[] arguments) { + DenseCodec denseCodec = new DenseCodec.Builder() + .setEncodeStackInitialSize(128) // (Optional) Creation size of stack for processing + .setDecodeStackInitialSize(128) // (Optional) Creation size of stack for processing + + .setIgnoreVersionCompare(false) // (Optional) Ignore compare dense codec version in data + + .create(); + + OpackValue opackValue = /* See Serialize Usage */; + + // Encode Basic + byte[] bytes = denseCodec.encode(opackValue); + + // Encode with Java IO OutputStream + OutputStream outputStream = /* Java IO OutputStream */; + denseCodec.encode(OutputStreamWriter.of(outputStream), opackValue); + + // Encode with ByteArrayWriter + ByteArrayWriter byteArrayWriter = new ByteArrayWriter(); + denseCodec.encode(byteArrayWriter, opackValue); + byte[] bytes = byteArrayWriter.toByteArray(); + + // Decode Basic + OpackValue decodedOpackValue = denseCodec.decode(bytes); + + // Decode with Java IO InputStream + InputStream inputStream = /* Java IO InputStream */; + OpackValue decodedOpackValue = denseCodec.decode(InputStreamReader.of(inputStream)); + + // Decode with ByteArrayReader + ByteArrayReader byteArrayReader = new ByteArrayReader(bytes); + OpackValue decodedOpackValue = denseCodec.decode(byteArrayReader); + } +} ``` ### Advanced Usage + #### 1. Ignore and Type and Name + ```java public class SomeObject { private String stringField; private byte[] bytesField; - /* - This field is not serialized/deserialized - */ + // This field will not serialize/deserialize @Ignore private String verySecretField; - /* - This field is serialized/deserialized to explicit type `ArrayList` instead of ambiguous field type `List` - */ + // This field will serialize/deserialize to explicit type `ArrayList` instead of ambiguous field type `List` @Type(ArrayList.class) private List listField; - - /* - This field is serialized/deserialized to `newFieldName` name instead of actual field name `oldFieldName` - */ + + // This field will serialize/deserialize to `newFieldName` name instead of actual field name `oldFieldName` @Name("newFieldName") private String oldFieldName; } ``` + #### 2. Field Transformer + ```java public class ByteToBase64Transformer implements Transformer { @Override @@ -195,14 +220,14 @@ public class ByteToBase64Transformer implements Transformer { } public class SomeObject { - /* - This field is serialized/deserialized via Base64 - */ + // This field will serialize/deserialize to Base64 @Transform(transformer = ByteToBase64Transformer.class) private byte[] bytesField; } ``` + #### 3. Field With Type + ```java public class SomeObject { // This field will serialize with runtime type, and deserialize actual type instead of ambiguous field type `List` @@ -214,12 +239,12 @@ public class SomeObject { private Object[] objectArrayField; } ``` + #### 4. Class Transformer + ```java public class AnimalTransformer implements Transformer { - /* - Remove a `sound` from a serialized `Animal` - */ + // Remove a `sound` from a serialized `Animal` @Override public Object serialize(Opacker opacker, Object value) throws SerializeException { if (value instanceof Animal) { @@ -236,9 +261,7 @@ public class AnimalTransformer implements Transformer { return value; } - /* - Restore `sound` from `Animal` before deserialization - */ + // Restore `sound` from `Animal` before deserialization @Override public Object deserialize(Opacker opacker, Class goalType, Object value) throws DeserializeException { if (value instanceof OpackObject) { @@ -253,9 +276,7 @@ public class AnimalTransformer implements Transformer { } } -/* - When `inheritable` is set to true, it applies to child classes. -*/ +// When `inheritable` is set to true, it applies to child classes. @Transform(transformer = AnimalTransformer.class, inheritable = true) abstract class Animal { private String sound; @@ -284,42 +305,47 @@ public class SomeObject { ``` #### 5. Handling Opack Value -```java -OpackObject rootObject = new OpackObject<>(); -{ - OpackArray opackArray = new OpackArray<>(); - opackArray.add(Integer.MAX_VALUE); - rootObject.put("array", opackArray); -} +```java +public class Usage { + public static void main(String[] arguments) { + OpackObject rootObject = new OpackObject<>(); + + { + OpackArray opackArray = new OpackArray<>(); + opackArray.add(Integer.MAX_VALUE); + rootObject.put("array", opackArray); + } -{ - OpackArray opackArray = OpackArray.createWithArrayObject(new int[]{1, 2, 3, 4, 5, 6}); - rootObject.put("unmodifiable(but, really fast) array", opackArray); -} + { + OpackArray opackArray = OpackArray.createWithArrayObject(new int[]{1, 2, 3, 4, 5, 6}); + rootObject.put("unmodifiable(but, really fast) array", opackArray); + } -{ - OpackObject opackObject = new OpackObject<>(); - opackObject.put("int", 1); - opackObject.put("float", 1.1f); - opackObject.put("long", Long.MAX_VALUE); - opackObject.put("double", 1.1d); + { + OpackObject opackObject = new OpackObject<>(); + opackObject.put("int", 1); + opackObject.put("float", 1.1f); + opackObject.put("long", Long.MAX_VALUE); + opackObject.put("double", 1.1d); - opackObject.put(1024, "2^10"); - opackObject.put( - OpackArray.createWithArrayObject(new byte[]{1,2,3,4,5}), - "a lot of bytes" - ); + opackObject.put(1024, "2^10"); + opackObject.put( + OpackArray.createWithArrayObject(new byte[]{1, 2, 3, 4, 5}), + "a lot of bytes" + ); - rootObject.put("number_map", opackObject); -} + rootObject.put("number_map", opackObject); + } -OpackArray opackArray = (OpackArray) rootObject.get("array"); -OpackObject opackObject = (OpackObject) rootObject.get("number_map"); + OpackArray opackArray = (OpackArray) rootObject.get("array"); + OpackObject opackObject = (OpackObject) rootObject.get("number_map"); -System.out.println("1024 is " + (opackObject.get(1024))); -System.out.println("Array length is " + (opackArray.length())); -System.out.println("First element is " + (opackArray.get(0))); + System.out.println("1024 is " + (opackObject.get(1024))); + System.out.println("Array length is " + (opackArray.length())); + System.out.println("First element is " + (opackArray.get(0))); + } +} ``` ### To-Do @@ -338,4 +364,4 @@ Opack uses [Apache License 2.0](./LICENSE.txt). Please, leave your feedback if y Jeonghwan, Park +821032735003 dev.parkjeonghwan@gmail.com -``` +``` \ No newline at end of file diff --git a/src/main/java/com/realtimetech/opack/codec/dense/reader/InputStreamReader.java b/src/main/java/com/realtimetech/opack/codec/dense/reader/InputStreamReader.java index 8a86f00..5dcb2b8 100644 --- a/src/main/java/com/realtimetech/opack/codec/dense/reader/InputStreamReader.java +++ b/src/main/java/com/realtimetech/opack/codec/dense/reader/InputStreamReader.java @@ -28,14 +28,23 @@ import java.io.InputStream; public class InputStreamReader implements Reader { + /** + * Create InputStreamReader + * + * @param inputStream the input stream + */ + public static @NotNull InputStreamReader of(@NotNull InputStream inputStream) { + return new InputStreamReader(inputStream); + } + private final @NotNull InputStream inputStream; /** - * Constructs the InputStreamReader. + * Constructs InputStreamReader * - * @param inputStream an InputStream + * @param inputStream the input stream */ - public InputStreamReader(@NotNull InputStream inputStream) { + InputStreamReader(@NotNull InputStream inputStream) { this.inputStream = inputStream; } diff --git a/src/main/java/com/realtimetech/opack/codec/dense/writer/OutputStreamWriter.java b/src/main/java/com/realtimetech/opack/codec/dense/writer/OutputStreamWriter.java index dc9d899..3e3cb0b 100644 --- a/src/main/java/com/realtimetech/opack/codec/dense/writer/OutputStreamWriter.java +++ b/src/main/java/com/realtimetech/opack/codec/dense/writer/OutputStreamWriter.java @@ -28,14 +28,23 @@ import java.io.OutputStream; public class OutputStreamWriter implements Writer { + /** + * Create OutputStreamWriter + * + * @param outputStream the output stream + */ + public static @NotNull OutputStreamWriter of(@NotNull OutputStream outputStream) { + return new OutputStreamWriter(outputStream); + } + private final @NotNull OutputStream outputStream; /** - * Constructs a OutputStreamWriter + * Constructs OutputStreamWriter * - * @param outputStream an outputStream + * @param outputStream the output stream */ - public OutputStreamWriter(@NotNull OutputStream outputStream) { + OutputStreamWriter(@NotNull OutputStream outputStream) { this.outputStream = outputStream; }