diff --git a/sdk/core/azure-core-experimental/CHANGELOG.md b/sdk/core/azure-core-experimental/CHANGELOG.md index 369cd8bcefe5..9ed249c7810f 100644 --- a/sdk/core/azure-core-experimental/CHANGELOG.md +++ b/sdk/core/azure-core-experimental/CHANGELOG.md @@ -2,6 +2,7 @@ ## 1.0.0-beta.7 (2020-10-08) +- Added API `fromObject()` in `BinaryData` which uses `JsonSerializer` present in the classpath. - Added APIs to `JsonPatchDocument` which accept pre-serialized JSON. - Updated `azure-core` dependency to released version. diff --git a/sdk/core/azure-core-experimental/src/main/java/com/azure/core/experimental/util/BinaryData.java b/sdk/core/azure-core-experimental/src/main/java/com/azure/core/experimental/util/BinaryData.java index 2979599d21ca..060cda67f27b 100644 --- a/sdk/core/azure-core-experimental/src/main/java/com/azure/core/experimental/util/BinaryData.java +++ b/sdk/core/azure-core-experimental/src/main/java/com/azure/core/experimental/util/BinaryData.java @@ -5,7 +5,9 @@ import com.azure.core.util.FluxUtil; import com.azure.core.util.logging.ClientLogger; +import com.azure.core.util.serializer.JsonSerializerProviders; import com.azure.core.util.serializer.ObjectSerializer; +import com.azure.core.util.serializer.JsonSerializer; import com.azure.core.util.serializer.TypeReference; import static com.azure.core.util.FluxUtil.monoError; @@ -18,18 +20,20 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.ByteBuffer; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Objects; /** * This class is an abstraction over many different ways that binary data can be represented. The {@link BinaryData} - * can be created from {@link InputStream}, {@link Flux} of {@link ByteBuffer}, {@link String}, {@link Object} and byte - * array. The data is collected from provided sources and stored into a byte array. + * can be created from {@link InputStream}, {@link Flux} of {@link ByteBuffer}, {@link String}, {@link Object}, or byte + * array. + *

Immutable data

+ * {@link BinaryData} is constructed by copying the given data. Once {@link BinaryData} is instantiated, it can not be + * changed. It provides various convenient APIs to get data out of {@link BinaryData}, they all start with the 'to' + * prefix, for example {@link BinaryData#toBytes()}. *

- * It also provides a way to serialize and deserialize an {@link Object} into {@link BinaryData} given an - * {@link ObjectSerializer}. Code samples are explained below. + * Code samples are presented below. * *

Create an instance from Bytes

* {@codesnippet com.azure.core.experimental.util.BinaryDocument.from#bytes} @@ -43,57 +47,48 @@ *

Get an Object from {@link BinaryData}

* {@codesnippet com.azure.core.experimental.util.BinaryDocument.to#ObjectAsync} * + *

Create an instance from Object

+ * {@codesnippet com.azure.core.experimental.util.BinaryDocument.from#Object} + * * @see ObjectSerializer + * @see JsonSerializer + * @see More about serialization */ public final class BinaryData { private static final ClientLogger LOGGER = new ClientLogger(BinaryData.class); - private final byte[] data; + private static final BinaryData EMPTY_DATA = new BinaryData(new byte[0]); - /** - * Create instance of {@link BinaryData} given the data. - * @param data to represent as bytes. - * @throws NullPointerException If {@code data} is null. - */ - BinaryData(byte[] data) { - Objects.requireNonNull(data, "'data' cannot be null."); - this.data = Arrays.copyOf(data, data.length); - } + private static final Object LOCK = new Object(); - /** - * Provides {@link InputStream} for the data represented by this {@link BinaryData} object. - * - *

Get InputStream from BinaryData

- * {@codesnippet com.azure.core.experimental.util.BinaryDocument.to#Stream} - * - * @return {@link InputStream} representing the binary data. - */ - public InputStream toStream() { - return new ByteArrayInputStream(this.data); - } + private final byte[] data; + + private static volatile JsonSerializer defaultJsonSerializer; /** - * Provides {@link Mono} of {@link InputStream} for the data represented by this {@link BinaryData} object. + * Create an instance of {@link BinaryData} from the given data. * - * @return {@link InputStream} representation of the {@link BinaryData}. + * @param data to represent as bytes. */ - public Mono toStreamAsync() { - return Mono.fromCallable(() -> toStream()); + BinaryData(byte[] data) { + this.data = data; } /** - * Create {@link BinaryData} instance with given {@link InputStream} as source of data. The {@link InputStream} is - * not closed by this function. + * Creates a {@link BinaryData} instance with given {@link InputStream} as source of data. The {@link InputStream} + * is not closed by this function. * *

Create an instance from InputStream

* {@codesnippet com.azure.core.experimental.util.BinaryDocument.from#Stream} * * @param inputStream to read bytes from. * @throws UncheckedIOException If any error in reading from {@link InputStream}. - * @throws NullPointerException if {@code inputStream} is null. + * @throws NullPointerException If {@code inputStream} is null. * @return {@link BinaryData} representing the binary data. */ public static BinaryData fromStream(InputStream inputStream) { - Objects.requireNonNull(inputStream, "'inputStream' cannot be null."); + if (Objects.isNull(inputStream)) { + return EMPTY_DATA; + } final int bufferSize = 1024; try { @@ -103,98 +98,125 @@ public static BinaryData fromStream(InputStream inputStream) { while ((nRead = inputStream.read(data, 0, data.length)) != -1) { dataOutputBuffer.write(data, 0, nRead); } + dataOutputBuffer.flush(); + + return new BinaryData(dataOutputBuffer.toByteArray()); - return fromBytes(dataOutputBuffer.toByteArray()); } catch (IOException ex) { throw LOGGER.logExceptionAsError(new UncheckedIOException(ex)); } } /** - * Asynchronously create {@link BinaryData} instance with given {@link InputStream} as source of data. The - * {@link InputStream} is not closed by this function. + * Asynchronously creates a {@link BinaryData} instance with the given {@link InputStream} as source of data. The + * {@link InputStream} is not closed by this function. If the {@link InputStream} is {@code null}, an empty + * {@link BinaryData} will be returned. * * @param inputStream to read bytes from. - * @throws NullPointerException if {@code inputStream} is null. * @return {@link Mono} of {@link BinaryData} representing the binary data. */ public static Mono fromStreamAsync(InputStream inputStream) { - Objects.requireNonNull(inputStream, "'inputStream' cannot be null."); - return Mono.fromCallable(() -> fromStream(inputStream)); } /** - * Create {@link BinaryData} instance with given {@link Flux} of {@link ByteBuffer} as source of data. It will - * collect all the bytes from {@link ByteBuffer} into {@link BinaryData}. + * Creates a {@link BinaryData} instance with given {@link Flux} of {@link ByteBuffer} as source of data. It will + * collect all the bytes from {@link ByteBuffer} into {@link BinaryData}. If the {@link Flux} is {@code null}, an + * empty {@link BinaryData} will be returned. * *

Create an instance from String

* {@codesnippet com.azure.core.experimental.util.BinaryDocument.from#Flux} * * @param data to use. - * @throws NullPointerException if {@code inputStream} is null. * @return {@link Mono} of {@link BinaryData} representing binary data. */ public static Mono fromFlux(Flux data) { if (Objects.isNull(data)) { - return monoError(LOGGER, new NullPointerException("'data' cannot be null.")); + return Mono.just(EMPTY_DATA); } return FluxUtil.collectBytesInByteBufferStream(data) - .flatMap(bytes -> Mono.just(fromBytes(bytes))); + .flatMap(bytes -> Mono.just(new BinaryData(bytes))); } /** - * Create {@link BinaryData} instance with given data and character set. - * - *

Create an instance from String

- * {@codesnippet com.azure.core.experimental.util.BinaryDocument.from#String} + * Creates a {@link BinaryData} instance with given data. The {@link String} is converted into bytes using UTF_8 + * character set. If the String is {@code null}, an empty {@link BinaryData} will be returned. * * @param data to use. - * @param charSet to use. - * @throws NullPointerException if {@code inputStream} is null. - * @return {@link BinaryData} representing the binary data. + * @return {@link BinaryData} representing binary data. */ - public static BinaryData fromString(String data, Charset charSet) { - Objects.requireNonNull(data, "'data' cannot be null."); + public static BinaryData fromString(String data) { + if (Objects.isNull(data) || data.length() == 0) { + return EMPTY_DATA; + } - return new BinaryData(data.getBytes(charSet)); + return new BinaryData(data.getBytes(StandardCharsets.UTF_8)); } /** - * Create {@link BinaryData} instance with given data. The {@link String} is converted into bytes using - * {@link StandardCharsets#UTF_8} character set. + * Creates a {@link BinaryData} instance with given byte array data. If the byte array is {@code null}, an empty + * {@link BinaryData} will be returned. * * @param data to use. - * @throws NullPointerException if {@code inputStream} is null. - * @return {@link BinaryData} representing binary data. + * @return {@link BinaryData} representing the binary data. */ - public static BinaryData fromString(String data) { - Objects.requireNonNull(data, "'data' cannot be null."); + public static BinaryData fromBytes(byte[] data) { + if (Objects.isNull(data) || data.length == 0) { + return EMPTY_DATA; + } - return new BinaryData(data.getBytes(StandardCharsets.UTF_8)); + return new BinaryData(Arrays.copyOf(data, data.length)); } /** - * Create {@link BinaryData} instance with given byte array data. + * Serialize the given {@link Object} into {@link BinaryData} using json serializer which is available on classpath. + * The serializer on classpath must implement {@link JsonSerializer} interface. If the given Object is {@code null}, + * an empty {@link BinaryData} will be returned. + *

Code sample

+ * {@codesnippet com.azure.core.experimental.util.BinaryDocument.from.default.serializer#Object} + + * @param data The {@link Object} which needs to be serialized into bytes. + * @throws IllegalStateException If a {@link JsonSerializer} cannot be found on the classpath. + * @return {@link BinaryData} representing the JSON serialized object. * - * @param data to use. - * @return {@link BinaryData} representing the binary data. + * @see JsonSerializer + * @see More about serialization */ - public static BinaryData fromBytes(byte[] data) { - return new BinaryData(data); + public static BinaryData fromObject(Object data) { + if (Objects.isNull(data)) { + return EMPTY_DATA; + } + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + getDefaultSerializer().serialize(outputStream, data); + + return new BinaryData(outputStream.toByteArray()); } /** * Serialize the given {@link Object} into {@link BinaryData} using the provided {@link ObjectSerializer}. + * If the Object is {@code null}, an empty {@link BinaryData} will be returned. + *

You can provide your custom implementation of {@link ObjectSerializer} interface or use one provided in azure + * sdk by adding them as dependency. These implementations could be found at + * Json Jackson serializer + * and Gson based serializer. + * + *

Create an instance from Object

+ * {@codesnippet com.azure.core.experimental.util.BinaryDocument.from#Object} * * @param data The {@link Object} which needs to be serialized into bytes. * @param serializer to use for serializing the object. - * @throws NullPointerException if {@code inputStream} or {@code serializer} is null. + * @throws NullPointerException If {@code serializer} is null. * @return {@link BinaryData} representing binary data. + * @see ObjectSerializer + * @see JsonSerializer + * @see More about serialization */ public static BinaryData fromObject(Object data, ObjectSerializer serializer) { - Objects.requireNonNull(data, "'data' cannot be null."); + if (Objects.isNull(data)) { + return EMPTY_DATA; + } + Objects.requireNonNull(serializer, "'serializer' cannot be null."); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -204,19 +226,25 @@ public static BinaryData fromObject(Object data, ObjectSerializer serializer) { /** * Serialize the given {@link Object} into {@link Mono} {@link BinaryData} using the provided - * {@link ObjectSerializer}. + * {@link ObjectSerializer}. If the Object is {@code null}, an empty {@link BinaryData} will be returned. + * + *

You can provide your custom implementation of {@link ObjectSerializer} interface or use one provided in azure + * sdk by adding them as dependency. These implementations could be found at + * Json Jackson serializer + * and Gson based serializer. * * @param data The {@link Object} which needs to be serialized into bytes. * @param serializer to use for serializing the object. - * @throws NullPointerException if {@code inputStream} or {@code serializer} is null. + * @throws NullPointerException If {@code serializer} is null. * @return {@link Mono} of {@link BinaryData} representing the binary data. + * @see ObjectSerializer + * @see More about serialization */ public static Mono fromObjectAsync(Object data, ObjectSerializer serializer) { - Objects.requireNonNull(data, "'data' cannot be null."); - Objects.requireNonNull(serializer, "'serializer' cannot be null."); - + if (Objects.isNull(serializer)) { + return monoError(LOGGER, new NullPointerException("'serializer' cannot be null.")); + } return Mono.fromCallable(() -> fromObject(data, serializer)); - } /** @@ -230,7 +258,7 @@ public byte[] toBytes() { /** * Provides {@link String} representation of this {@link BinaryData} object. The bytes are converted into - * {@link String} using {@link StandardCharsets#UTF_8} character set. + * {@link String} using the UTF-8 character set. * * @return {@link String} representation of the data. */ @@ -238,23 +266,21 @@ public String toString() { return new String(this.data, StandardCharsets.UTF_8); } - /** - * Provides {@link String} representation of this {@link BinaryData} object given a character set. - * - * @param charSet to use to convert bytes into {@link String}. - * @return {@link String} representation of the the binary data. - */ - public String toString(Charset charSet) { - return new String(this.data, charSet); - } - /** * Deserialize the bytes into the {@link Object} of given type by applying the provided {@link ObjectSerializer} on * the data. * + *

You can provide your custom implementation of {@link ObjectSerializer} interface or use one provided in azure + * sdk by adding them as dependency. These implementations could be found at + * Json Jackson serializer + * and Gson based serializer. + * + *

Code sample

+ * {@codesnippet com.azure.core.experimental.util.BinaryDocument.to#Object} * @param clazz representing the type of the Object. * @param serializer to use deserialize data into type. * @param Generic type that the data is deserialized into. + * @throws NullPointerException If {@code serializer} or {@code clazz} is null. * @return The {@link Object} of given type after deserializing the bytes. */ public T toObject(Class clazz, ObjectSerializer serializer) { @@ -267,8 +293,13 @@ public T toObject(Class clazz, ObjectSerializer serializer) { } /** - * Return a {@link Mono} by deserialize the bytes into the {@link Object} of given type after applying the provided - * {@link ObjectSerializer} on the {@link BinaryData}. + * Return a {@link Mono} by deserializing the bytes into the {@link Object} of given type after applying the + * provided {@link ObjectSerializer} on the {@link BinaryData}. + * + *

You can provide your custom implementation of {@link ObjectSerializer} interface or use one provided in azure + * sdk by adding them as dependency. These implementations could be found at + * Json Jackson serializer + * and Gson based serializer. * *

Gets the specified object

* {@codesnippet com.azure.core.experimental.util.BinaryDocument.to#ObjectAsync} @@ -276,10 +307,77 @@ public T toObject(Class clazz, ObjectSerializer serializer) { * @param clazz representing the type of the Object. * @param serializer to use deserialize data into type. * @param Generic type that the data is deserialized into. - * @throws NullPointerException if {@code clazz} or {@code serializer} is null. + * @throws NullPointerException If {@code clazz} or {@code serializer} is null. * @return The {@link Object} of given type after deserializing the bytes. */ public Mono toObjectAsync(Class clazz, ObjectSerializer serializer) { + + if (Objects.isNull(clazz)) { + return monoError(LOGGER, new NullPointerException("'clazz' cannot be null.")); + } else if (Objects.isNull(serializer)) { + return monoError(LOGGER, new NullPointerException("'serializer' cannot be null.")); + } return Mono.fromCallable(() -> toObject(clazz, serializer)); } + + /** + * Deserialize the bytes into the {@link Object} of given type by using json serializer which is available in + * classpath. The serializer must implement {@link JsonSerializer} interface. A singleton instance of + * {@link JsonSerializer} is kept for this class to use. + * + * @param clazz representing the type of the Object. + * @param Generic type that the data is deserialized into. + * @throws NullPointerException If {@code clazz} is null. + * @return The {@link Object} of given type after deserializing the bytes. + */ + public T toObject(Class clazz) { + Objects.requireNonNull(clazz, "'clazz' cannot be null."); + + TypeReference ref = TypeReference.createInstance(clazz); + InputStream jsonStream = new ByteArrayInputStream(this.data); + return getDefaultSerializer().deserialize(jsonStream, ref); + } + + /** + * Return a {@link Mono} by deserializing the bytes into the {@link Object} of given type after applying the Json + * serializer found on classpath. + * + *

Gets the specified object

+ * {@codesnippet com.azure.core.experimental.util.BinaryDocument.to#ObjectAsync} + * + * @param clazz representing the type of the Object. + * @param Generic type that the data is deserialized into. + * @throws NullPointerException If {@code clazz} is null. + * @return The {@link Object} of given type after deserializing the bytes. + */ + public Mono toObjectAsync(Class clazz) { + if (Objects.isNull(clazz)) { + return monoError(LOGGER, new NullPointerException("'clazz' cannot be null.")); + } + return Mono.fromCallable(() -> toObject(clazz)); + } + + /** + * Provides {@link InputStream} for the data represented by this {@link BinaryData} object. + * + *

Get InputStream from BinaryData

+ * {@codesnippet com.azure.core.experimental.util.BinaryDocument.to#Stream} + * + * @return {@link InputStream} representing the binary data. + */ + public InputStream toStream() { + return new ByteArrayInputStream(this.data); + } + + /* This will ensure lazy instantiation to avoid hard dependency on Json Serializer. */ + private static JsonSerializer getDefaultSerializer() { + if (defaultJsonSerializer == null) { + synchronized (LOCK) { + if (defaultJsonSerializer == null) { + defaultJsonSerializer = JsonSerializerProviders.createInstance(); + } + } + } + return defaultJsonSerializer; + } } diff --git a/sdk/core/azure-core-experimental/src/samples/java/com/azure/core/experimental/util/BinaryDateJavaDocCodeSnippet.java b/sdk/core/azure-core-experimental/src/samples/java/com/azure/core/experimental/util/BinaryDateJavaDocCodeSnippet.java index d4999b654cf2..a7211d27ca89 100644 --- a/sdk/core/azure-core-experimental/src/samples/java/com/azure/core/experimental/util/BinaryDateJavaDocCodeSnippet.java +++ b/sdk/core/azure-core-experimental/src/samples/java/com/azure/core/experimental/util/BinaryDateJavaDocCodeSnippet.java @@ -58,8 +58,8 @@ public void createFromString() { */ public void createFromStream() { // BEGIN: com.azure.core.experimental.util.BinaryDocument.from#Stream - final byte[] data = "Some Data".getBytes(StandardCharsets.UTF_8); - BinaryData binaryData = BinaryData.fromStream(new ByteArrayInputStream(data)); + final ByteArrayInputStream inputStream = new ByteArrayInputStream("Some Data".getBytes(StandardCharsets.UTF_8)); + BinaryData binaryData = BinaryData.fromStream(inputStream); System.out.println(binaryData.toString()); // END: com.azure.core.experimental.util.BinaryDocument.from#Stream } @@ -88,6 +88,40 @@ public void createFromFlux() throws InterruptedException { // END: com.azure.core.experimental.util.BinaryDocument.from#Flux } + /** + * Codesnippets for {@link BinaryData#fromObject(Object, ObjectSerializer)}. + */ + public void createFromObject() { + // BEGIN: com.azure.core.experimental.util.BinaryDocument.from#Object + // Lets say we have Person object which could be serialized into json. + class Person { + @JsonProperty + private String name; + + @JsonSetter + public Person setName(String name) { + this.name = name; + return this; + } + + @JsonGetter + public String getName() { + return name; + } + } + final Person data = new Person().setName("John"); + + // Provide your custom serializer or use Azure provided serializers. + // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-jackson or + // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-gson + + final ObjectSerializer serializer = + new MyJsonSerializer(); // Replace this with your Serializer or from above libraries. + BinaryData binaryData = BinaryData.fromObject(data, serializer); + System.out.println(binaryData.toString()); + // END: com.azure.core.experimental.util.BinaryDocument.from#Object + } + /** * Codesnippets for {@link BinaryData#toStream()}. */ @@ -124,8 +158,7 @@ public String getName() { } final Person data = new Person().setName("John"); - // Ensure your classpath have the Serializer to use to serialize object. For example you can use one of - // following library. + // Provide your custom serializer or use Azure provided serializers. // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-jackson or // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-gson @@ -133,7 +166,6 @@ public String getName() { new MyJsonSerializer(); // Replace this with your Serializer BinaryData binaryData = BinaryData.fromObject(data, serializer); - // Lets print the value of BinaryData Disposable subscriber = binaryData .toObjectAsync(Person.class, serializer) .map(person -> { @@ -148,6 +180,78 @@ public String getName() { // END: com.azure.core.experimental.util.BinaryDocument.to#ObjectAsync } + /** + * Codesnippets for {@link BinaryData#toObject(Class, ObjectSerializer)}. + */ + public void createToObject() { + // BEGIN: com.azure.core.experimental.util.BinaryDocument.to#Object + // Lets say we have Person object which could be serialized into json. + class Person { + @JsonProperty + private String name; + + @JsonSetter + public Person setName(String name) { + this.name = name; + return this; + } + + @JsonGetter + public String getName() { + return name; + } + } + final Person data = new Person().setName("John"); + + // Provide your custom serializer or use Azure provided serializers. + // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-jackson or + // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-gson + + final ObjectSerializer serializer = + new MyJsonSerializer(); // Replace this with your Serializer + BinaryData binaryData = BinaryData.fromObject(data, serializer); + + Person person = binaryData.toObject(Person.class, serializer); + // Lets print the name + System.out.println("Name : " + person.getName()); + + // END: com.azure.core.experimental.util.BinaryDocument.to#Object + } + + /** + * Codesnippets for {@link BinaryData#fromObject(Object)}. + */ + public void createFromObjectDefaultSerializer() { + // BEGIN: com.azure.core.experimental.util.BinaryDocument.from.default.serializer#Object + // Lets say we have Person object which could be serialized into json. + class Person { + @JsonProperty + private String name; + + @JsonSetter + public Person setName(String name) { + this.name = name; + return this; + } + + @JsonGetter + public String getName() { + return name; + } + } + final Person data = new Person().setName("John"); + + // Ensure your classpath have the Serializer to serialize the object which implement implement + // com.azure.core.util.serializer.JsonSerializer interface. + // Or use Azure provided libraries for this. + // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-jackson or + // https://mvnrepository.com/artifact/com.azure/azure-core-serializer-json-gson + + BinaryData binaryData = BinaryData.fromObject(data); + System.out.println(binaryData.toString()); + // END: com.azure.core.experimental.util.BinaryDocument.from.default.serializer#Object + } + public static class MyJsonSerializer implements JsonSerializer { private final ClientLogger logger = new ClientLogger(BinaryDataTest.MyJsonSerializer.class); private final ObjectMapper mapper; @@ -192,4 +296,3 @@ public Mono serializeAsync(OutputStream stream, Object value) { } } } - diff --git a/sdk/core/azure-core-experimental/src/test/java/com/azure/core/experimental/util/BinaryDataTest.java b/sdk/core/azure-core-experimental/src/test/java/com/azure/core/experimental/util/BinaryDataTest.java index e0afe19e16d3..157b7d8ea094 100644 --- a/sdk/core/azure-core-experimental/src/test/java/com/azure/core/experimental/util/BinaryDataTest.java +++ b/sdk/core/azure-core-experimental/src/test/java/com/azure/core/experimental/util/BinaryDataTest.java @@ -85,34 +85,75 @@ public void createFromString() { } @Test - public void createFromStringCharSet() { + public void createFromByteArray() { // Arrange - final String expected = "Doe"; + final byte[] expected = "Doe".getBytes(StandardCharsets.UTF_8); // Act - final BinaryData data = BinaryData.fromString(expected, StandardCharsets.UTF_8); + final BinaryData data = new BinaryData(expected); // Assert - assertArrayEquals(expected.getBytes(), data.toBytes()); - assertEquals(expected, data.toString(StandardCharsets.UTF_8)); + assertArrayEquals(expected, data.toBytes()); } @Test - public void createFromByteArray() { + public void createFromNullStream() throws IOException { // Arrange - final byte[] expected = "Doe".getBytes(StandardCharsets.UTF_8); + final byte[] expected = new byte[0]; // Act - final BinaryData data = new BinaryData(expected); + BinaryData data = BinaryData.fromStream(null); + final byte[] actual = new byte[0]; + (data.toStream()).read(actual, 0, expected.length); // Assert assertArrayEquals(expected, data.toBytes()); + assertArrayEquals(expected, actual); + } + + @Test + public void createFromNullByteArray() { + // Arrange + final byte[] expected = new byte[0]; + + // Act + BinaryData actual = BinaryData.fromBytes(null); + + // Assert + assertArrayEquals(expected, actual.toBytes()); + } + + @Test + public void createFromNullObject() { + // Arrange + final byte[] expected = new byte[0]; + + // Act + BinaryData actual = BinaryData.fromObject(null); + + // Assert + assertArrayEquals(expected, actual.toBytes()); } @Test public void createFromStream() throws IOException { // Arrange final byte[] expected = "Doe".getBytes(StandardCharsets.UTF_8); + + // Act + BinaryData data = BinaryData.fromStream(new ByteArrayInputStream(expected)); + final byte[] actual = new byte[expected.length]; + (data.toStream()).read(actual, 0, expected.length); + + // Assert + assertArrayEquals(expected, data.toBytes()); + assertArrayEquals(expected, actual); + } + + @Test + public void createFromEmptyStream() throws IOException { + // Arrange + final byte[] expected = "".getBytes(); final byte[] actual = new byte[expected.length]; // Act @@ -140,7 +181,7 @@ public void createFromFlux() { } @Test - public void createFromStreamAsync() throws IOException { + public void createFromStreamAsync() { // Arrange final byte[] expected = "Doe".getBytes(StandardCharsets.UTF_8); @@ -152,27 +193,6 @@ public void createFromStreamAsync() throws IOException { .verifyComplete(); } - @Test - public void createToStreamAsync() { - // Arrange - final byte[] expected = "Doe".getBytes(StandardCharsets.UTF_8); - final BinaryData actual = BinaryData.fromStreamAsync(new ByteArrayInputStream(expected)).block(); - // Act & Assert - StepVerifier.create(actual.toStreamAsync()) - .assertNext(inutStream -> { - byte[] actualBytes = new byte[expected.length]; - - // Act - try { - inutStream.read(actualBytes, 0, expected.length); - } catch (IOException e) { - e.printStackTrace(); - } - Assertions.assertArrayEquals(expected, actualBytes); - }) - .verifyComplete(); - } - @Test public void createFromObjectAsync() { // Arrange @@ -189,6 +209,58 @@ public void createFromObjectAsync() { .verifyComplete(); } + + @Test + public void createFromEmptyString() { + // Arrange + final String expected = ""; + + // Act + final BinaryData data = BinaryData.fromString(expected); + + // Assert + assertArrayEquals(expected.getBytes(), data.toBytes()); + assertEquals(expected, data.toString()); + } + + @Test + public void createFromEmptyByteArray() { + // Arrange + final byte[] expected = new byte[0]; + + // Act + final BinaryData data = BinaryData.fromBytes(expected); + + // Assert + assertArrayEquals(expected, data.toBytes()); + } + + @Test + public void createFromNullString() { + // Arrange + final String expected = null; + + // Arrange & Act + final BinaryData data = BinaryData.fromString(expected); + + // Assert + assertArrayEquals(new byte[0], data.toBytes()); + assertEquals("", data.toString()); + } + + @Test + public void createFromNullByte() { + // Arrange + final byte[] expected = null; + + // Arrange & Act + final BinaryData data = BinaryData.fromBytes(expected); + + // Assert + assertArrayEquals(new byte[0], data.toBytes()); + assertEquals("", data.toString()); + } + public static class MyJsonSerializer implements JsonSerializer { private final ClientLogger logger = new ClientLogger(MyJsonSerializer.class); private final ObjectMapper mapper;