• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 package software.amazon.awssdk.core;
17 
18 import static java.nio.charset.StandardCharsets.UTF_8;
19 
20 import java.io.ByteArrayInputStream;
21 import java.io.InputStream;
22 import java.io.UncheckedIOException;
23 import java.nio.ByteBuffer;
24 import java.nio.charset.CharacterCodingException;
25 import java.nio.charset.Charset;
26 import java.util.Arrays;
27 import software.amazon.awssdk.annotations.SdkInternalApi;
28 import software.amazon.awssdk.annotations.SdkPublicApi;
29 import software.amazon.awssdk.http.ContentStreamProvider;
30 import software.amazon.awssdk.utils.StringUtils;
31 import software.amazon.awssdk.utils.Validate;
32 
33 /**
34  * A base class for {@link SdkBytes} and {@link ResponseBytes} that enables retrieving an underlying byte array as multiple
35  * different types, like a byte buffer (via {@link #asByteBuffer()}, or a string (via {@link #asUtf8String()}.
36  */
37 @SdkPublicApi
38 public abstract class BytesWrapper {
39     private final byte[] bytes;
40 
41     // Needed for serialization
42     @SdkInternalApi
BytesWrapper()43     BytesWrapper() {
44         this(new byte[0]);
45     }
46 
47     @SdkInternalApi
BytesWrapper(byte[] bytes)48     BytesWrapper(byte[] bytes) {
49         this.bytes = Validate.paramNotNull(bytes, "bytes");
50     }
51 
52     /**
53      * @return The output as a read-only byte buffer.
54      */
asByteBuffer()55     public final ByteBuffer asByteBuffer() {
56         return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
57     }
58 
59     /**
60      * @return A copy of the output as a byte array.
61      * @see #asByteBuffer() to prevent creating an additional array copy.
62      */
asByteArray()63     public final byte[] asByteArray() {
64         return Arrays.copyOf(bytes, bytes.length);
65     }
66 
67     /**
68      * @return The output as a byte array. This <b>does not</b> create a copy of the underlying byte array. This introduces
69      * concurrency risks, allowing: (1) the caller to modify the byte array stored in this object implementation AND
70      * (2) the original creator of this object, if they created it using the unsafe method.
71      *
72      * <p>Consider using {@link #asByteBuffer()}, which is a safer method to avoid an additional array copy because it does not
73      * provide a way to modify the underlying buffer. As the method name implies, this is unsafe. If you're not sure, don't use
74      * this. The only guarantees given to the user of this method is that the SDK itself won't modify the underlying byte
75      * array.</p>
76      *
77      * @see #asByteBuffer() to prevent creating an additional array copy safely.
78      */
asByteArrayUnsafe()79     public final byte[] asByteArrayUnsafe() {
80         return bytes;
81     }
82 
83     /**
84      * Retrieve the output as a string.
85      *
86      * @param charset The charset of the string.
87      * @return The output as a string.
88      * @throws UncheckedIOException with a {@link CharacterCodingException} as the cause if the bytes cannot be encoded using the
89      * provided charset
90      */
asString(Charset charset)91     public final String asString(Charset charset) throws UncheckedIOException {
92         return StringUtils.fromBytes(bytes, charset);
93     }
94 
95     /**
96      * @return The output as a utf-8 encoded string.
97      * @throws UncheckedIOException with a {@link CharacterCodingException} as the cause if the bytes cannot be encoded as UTF-8.
98      */
asUtf8String()99     public final String asUtf8String() throws UncheckedIOException {
100         return asString(UTF_8);
101     }
102 
103     /**
104      * @return The output as an input stream. This stream will not need to be closed.
105      */
asInputStream()106     public final InputStream asInputStream() {
107         return new ByteArrayInputStream(bytes);
108     }
109 
110     /**
111      * @return The output as a {@link ContentStreamProvider}.
112      */
asContentStreamProvider()113     public final ContentStreamProvider asContentStreamProvider() {
114         return this::asInputStream;
115     }
116 
117     @Override
equals(Object o)118     public boolean equals(Object o) {
119         if (this == o) {
120             return true;
121         }
122         if (o == null || getClass() != o.getClass()) {
123             return false;
124         }
125 
126         BytesWrapper sdkBytes = (BytesWrapper) o;
127 
128         return Arrays.equals(bytes, sdkBytes.bytes);
129     }
130 
131     @Override
hashCode()132     public int hashCode() {
133         return Arrays.hashCode(bytes);
134     }
135 }
136