add support for gson serialization
[storage-units.git] / README.md
blobc8dddb68c8eebb36abeea565e7715d86ad1069f7
1 <!--
2 SPDX-FileCopyrightText: The Storage-Units Authors
3 SPDX-License-Identifier: 0BSD
4  -->
6 # Storage-Units
8 Storage units according to ISO IEC 80000-13:2008 implemented in Java.
10 ## Features
12 * Immutable, type- and thread-safe object model for storage units
13 * Convenience factories to create units
14 * Basic arithmetic operators
15 * Comparisons and equality checks between units
16 * Lossless conversion between all units
17 * Human-readable text format, including custom formats
18 * Compatible with any `java.lang.Number`
19 * Custom serializers for Jackson, MongoDB, EclipseLink, and others
21 ### Available Units
23 | Name     | Symbol | Exponential          | Absolute                                       |
24 |----------|--------|----------------------|------------------------------------------------|
25 | Byte     | B      | 2<sup>0</sup> Byte   | 1 Byte                                         |
26 | Kibibyte | KiB    | 2<sup>10</sup> Byte  | 1 024 Byte                                     |
27 | Mebibyte | MiB    | 2<sup>20</sup> Byte  | 1 048 576 Byte                                 |
28 | Gibibyte | GiB    | 2<sup>30</sup> Byte  | 1 073 741 824 Byte                             |
29 | Tebibyte | TiB    | 2<sup>40</sup> Byte  | 1 099 511 627 776 Byte                         |
30 | Pebibyte | PiB    | 2<sup>50</sup> Byte  | 1 125 899 906 842 624 Byte                     |
31 | Exbibyte | EiB    | 2<sup>60</sup> Byte  | 1 152 921 504 606 846 976 Byte                 |
32 | Zebibyte | ZiB    | 2<sup>70</sup> Byte  | 1 180 591 620 717 411 303 424 Byte             |
33 | Yobibyte | YiB    | 2<sup>80</sup> Byte  | 1 208 925 819 614 629 174 706 176 Byte         |
34 | Robibyte | RiB    | 2<sup>90</sup> Byte  | 1 237 940 039 285 380 274 899 124 224 Byte     |
35 | Qubibyte | QiB    | 2<sup>100</sup> Byte | 1 267 650 600 228 229 401 496 703 205 376 Byte |
37 | Name       | Symbol | Exponential          | Absolute                                       |
38 |------------|--------|----------------------|------------------------------------------------|
39 | Byte       | B      | 10<sup>0</sup> Byte  | 1 Byte                                         |
40 | Kilobyte   | KB     | 10<sup>3</sup> Byte  | 1 000 Byte                                     |
41 | Megabyte   | MB     | 10<sup>6</sup> Byte  | 1 000 000 Byte                                 |
42 | Gigabyte   | GB     | 10<sup>9</sup> Byte  | 1 000 000 000 Byte                             |
43 | Terabyte   | TB     | 10<sup>12</sup> Byte | 1 000 000 000 000 Byte                         |
44 | Petabyte   | PB     | 10<sup>15</sup> Byte | 1 000 000 000 000 000 Byte                     |
45 | Exabyte    | EB     | 10<sup>18</sup> Byte | 1 000 000 000 000 000 000 Byte                 |
46 | Zettabyte  | ZB     | 10<sup>21</sup> Byte | 1 000 000 000 000 000 000 000 Byte             |
47 | Yottabyte  | YB     | 10<sup>24</sup> Byte | 1 000 000 000 000 000 000 000 000 Byte         |
48 | Ronnabyte  | RB     | 10<sup>27</sup> Byte | 1 000 000 000 000 000 000 000 000 000 Byte     |
49 | Quettabyte | QB     | 10<sup>30</sup> Byte | 1 000 000 000 000 000 000 000 000 000 000 Byte |
51 ## Usage
53 ### Factories
55 Each unit implements a Byte-based static factory method (`valueOf(BigInteger)` or `valueOf(long)`) that can be used to represent a given number of bytes in a specific unit. Note that `Long.MAX_VALUE == 8 Exabyte`, thus use `BigInteger` if you want to work with anything bigger than a eight Exabyte. When in doubt, always use `BigInteger`.
57 ```java
58 // 'long' based
59 Kilobyte unit = Kilobyte.valueOf(500)                           // 500 Byte or "0.50 kB"
60 Kibibyte unit = Kibibyte.valueOf(512)                           // 512 Byte or "0.50 KiB"
62 Megabyte unit = Megabyte.valueOf(1_000_000)                     // 1 000 000 Byte or "1.00 MB"
63 Mebibyte unit = Mebibyte.valueOf(1_048_576)                     // 1 048 576 Byte or "1.00 MiB"
65 // 'BigInteger' based
66 Kilobyte unit = Kilobyte.valueOf(BigInteger.valueOf(500))       // 500 Byte or "0.50 kB"
67 Kibibyte unit = Kibibyte.valueOf(BigInteger.valueOf(512))       // 512 Byte or "0.50 KiB"
69 Megabyte unit = Megabyte.valueOf(BigInteger.valueOf(1000000))   // 1 000 000 Byte or "1.00 MB"
70 Mebibyte unit = Mebibyte.valueOf(BigInteger.valueOf(1_048_576)) // 1 048 576 Byte or "1.00 MB"
71 ```
73 The `StorageUnits` class offers three factory methods that automatically pick the best-matching unit for a given number of bytes.
75 #### Binary Units
77 ```java
78 // 'long' based
79 StorageUnit<?> unit = StorageUnits.binaryValueOf(256)                         // Kibibyte (0.25 KiB)
80 StorageUnit<?> unit = StorageUnits.binaryValueOf(1048576)                     // Mebibyte (1.00 MiB)
82 // 'BigInteger' based
83 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(256))     // Kibibyte (0.25 MiB)
84 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(1048576)) // Mebibyte (1.00 MiB)
85 ```
87 #### Decimal Units
89 ```java
90 // 'long' based
91 StorageUnit<?> unit = StorageUnits.decimalValueOf(120000)                      // Kilobyte (120.00 kB)
92 StorageUnit<?> unit = StorageUnits.decimalValueOf(1000000)                     // Megabyte (1.00 MB)
94 // 'BigInteger' based
95 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(120000))  // Kilobyte (120.00 kB)
96 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(1000000)) // Megabyte (1.00 MB)
97 ```
99 Additionally high-level factory methods are also available in the `StorageUnits` class.
101 ```java
102 import static wtf.metio.storageunits.model.StorageUnits.*;
104 Kibibyte unit = kibibyte(1)   // 1 024 Byte
105 Mebibyte unit = mebibyte(1)   // 1 048 576 Byte
106 Gibibyte unit = gibibyte(1)   // 1 073 741 824 Byte
107 Tebibyte unit = tebibyte(1)   // 1 099 511 627 776 Byte
108 Pebibyte unit = pebibyte(1)   // 1 125 899 906 842 624 Byte
109 Exbibyte unit = exbibyte(1)   // 1 152 921 504 606 846 976 Byte
110 Zebibyte unit = zebibyte(1)   // 1 180 591 620 717 411 303 424 Byte
111 Yobibyte unit = yobibyte(1)   // 1 208 925 819 614 629 174 706 176 Byte
112 Robibyte unit = robibyte(1)   // 1 237 940 039 285 380 274 899 124 224 Byte
113 Qubibyte unit = qubibyte(1)   // 1 267 650 600 228 229 401 496 703 205 376 Byte
115 Kilobyte unit = kilobyte(1)     // 1 000 Byte
116 Megabyte unit = megabyte(1)     // 1 000 000 Byte
117 Gigabyte unit = gigabyte(1)     // 1 000 000 000 Byte
118 Terabyte unit = terabyte(1)     // 1 000 000 000 000 Byte
119 Petabyte unit = petabyte(1)     // 1 000 000 000 000 000 Byte
120 Exabyte unit = exabyte(1)       // 1 000 000 000 000 000 000 Byte
121 Zettabyte unit = zettabyte(1)   // 1 000 000 000 000 000 000 000 Byte
122 Yottabyte unit = yottabyte(1)   // 1 000 000 000 000 000 000 000 000 Byte
123 Ronnabyte unit = ronnabyte(1)   // 1 000 000 000 000 000 000 000 000 000 Byte
124 Quettabyte unit = quettabyte(1) // 1 000 000 000 000 000 000 000 000 000 000 Byte
127 ### Add, Subtract, Multiply, Divide
129 Each unit implements the basic four math operations. All operations retain their original type, e.g. `[Kilobyte] + [Megabyte] = [Kilobyte]`
131 ```java
132 import static wtf.metio.storageunits.model.StorageUnits.*;
134 kilobyte(4).add(kilobyte(8))        // 4 Kilobyte + 8 Kilobyte = 12 Kilobyte = 12 000 Byte
135 kibibyte(1).add(1024)               // 1 Kibibyte + 1 024 Byte = 2 Kibibyte = 2 048 Byte
136 kibibyte(1).subtract(24)            // 1 024 Byte - 24 Byte = 1 000 Byte
137 megabyte(5).subtract(kilobyte(500)) // 5 Megabyte - 500 Kilobyte = 4.5 Megabyte = 4 500 Kilobyte = 4 500 000 Byte
138 gigabyte(1).multiply(5)             // 1 Gigabyte times 5 = 5 Gigabyte
139 terabyte(1).divide(5)               // 1 Terabyte divided by 5 = 0.2 Terabyte = 200 Gigabyte
142 ### Comparison & Equality
144 Each unit is comparable to each other unit.
146 ```java
147 import static wtf.metio.storageunits.model.StorageUnits.*;
149 kibibyte(1024).compareTo(mebibyte(1)) == 0 // true
150 kibibyte(1000).compareTo(mebibyte(1)) == 0 // false
151 petabyte(3).compareTo(terabyte(3000)) == 0 // true
153 megabyte(1000).equals(gigabyte(1))         // true
154 megabyte(1024).equals(gigabyte(1))         // false
155 terabyte(12).equals(gigabyte(12000))       // true
158 ### Formatting
160 Each unit prints a human-readable string, representing the amount of bytes in the given unit using the symbol specified in ISO IEC 80000-13:2008.
162 ```java
163 import static wtf.metio.storageunits.model.StorageUnits.*;
165 // default pattern '0.00'
166 terabyte(2).toString()                         // "2.00 TB"
167 gigabyte(1).add(megabyte(200)).toString()      // "1.20 GB"
168 petabyte(1).subtract(terabyte(250)).toString() // "0.75 PB"
170 // use custom pattern
171 kilobyte(212345).toString("0.0")                                    // "212345.0 kB"
172 gibibyte(2123458).asTebibyte().toString("#,###.000")                // "2,073.689 TiB"
173 kilobyte(120).asMegabyte().add(gigabyte(1)).toString("#,##0.00000") // "1,000.12000 MB"
175 // use custom pattern with specific Locale
176 kilobyte(212345).toString("0.0", Locale.GERMAN)                     // "212345,0 kB"
177 gibibyte(2123458).asTebibyte().toString("#,###.000", Locale.GERMAN) // "2.073,689 TiB"
179 // use custom format
180 Format customFormat = new DecimalFormat("#.00000");
181 terabyte(4).asTebibyte().toString(customFormat) // "3.63798 TiB"
183 // without creating unit type first
184 long numberOfBytes = 1_000_000_000_000_000L;
185 formatAsPetabyte(numberOfBytes) // "1.00 PB"
186 formatAsTerabyte(numberOfBytes) // "1000.00 TB"
187 formatAsPebibyte(numberOfBytes) // "0.89 PiB"
189 // use custom pattern
190 formatAsTerabyte(numberOfBytes, "#0.#####") // "1000 TB"
191 formatAsPebibyte(numberOfBytes, "#0.#####") // "0.88818 PiB"
193 // use custom pattern with specific Locale
194 formatAsTerabyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "1000 TB"
195 formatAsPebibyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "0,88818 PiB"
197 // use custom format
198 formatAsTerabyte(numberOfBytes, customFormat) // "1000.00000 TB"
199 formatAsPebibyte(numberOfBytes, customFormat) // ".88818 PiB"
202 ### Conversions
204 Each unit can be converted to each other unit without loss of information.
206 ```java
207 import static wtf.metio.storageunits.model.StorageUnits.*;
209 Megabyte unit = kilobyte(1000).asMegabyte() // "1.00 MB"
210 Kilobyte unit = gigabyte(12).asKilobyte()   // "12000000.00 kB"
211 Gigabyte unit = terabyte(1).asGigabyte()    // "1000.00 GB"
213 // convert to best-match
214 kilobyte(1100).asBestMatchingUnit()          // "1.10 MB"
215 kilobyte(1100).asBestMatchingBinaryUnit()    // "1.05 MiB"
216 kilobyte(1100).asBestMatchingDecimalUnit()   // "1.10 MB"
219 Each unit can be expressed as a fraction of another unit (precise up to 24 decimal places)
221 ```java
222 import static wtf.metio.storageunits.model.StorageUnits.*;
224 BigDecimal kilobytes = megabyte(1).inKilobyte()  // 1 000
225 BigInteger bytes = kibibyte(2).inByte()          // 2 048
226 BigDecimal terabytes = gigabyte(15).inTerabyte() // 0.015
229 ### Serialization/Converters/Mappers
231 Multiple custom serializers, converters, and mappers are available for all storage units.
233 #### Dozer
235 Use a [Dozer](https://dozermapper.github.io/) converter like this:
237 ```java
238 import static wtf.metio.storageunits.dozer.*;
240 DozerBeanMapperBuilder.create()
241         .withCustomConverter(new BigIntegerBinaryStorageUnitConverter())
242         .withCustomConverter(new BigIntegerDecimalStorageUnitConverter())
243         .withCustomConverter(new LongBinaryStorageUnitConverter())
244         .withCustomConverter(new LongDecimalStorageUnitConverter())
245         .build();
248 #### EclipseLink
250 Use any of the three converters like this:
252 ```java
253 import static wtf.metio.storageunits.eclipselink.*;
255 @Entity
256 public class HardDisk implements Serializable {
258     @Basic
259     @Converter (
260         name="binaryConverter",
261         converterClass=BinaryStorageUnitConverter.class
262     )
263     @Convert("binaryConverter")
264     public StorageUnit<?> getFreeSize() {
265         return freeSize;
266     }
268     @Basic
269     @Converter (
270         name="decimalConverter",
271         converterClass=DecimalyStorageUnitConverter.class
272     )
273     @Convert("decimalConverter")
274     public StorageUnit<?> getTotalSize() {
275         return totalSize;
276     }
281 #### GSON
283 Use a [GSON](https://github.com/google/gson) serializer/deserializer like this:
285 ```java
286 import static wtf.metio.storageunits.gson.*;
288 new GsonBuilder()
289         .registerTypeHierarchyAdapter(StorageUnit.class, new StorageUnitSerializer())
290         .registerTypeHierarchyAdapter(StorageUnit.class, new BinaryStorageUnitDeserializer())
291         .registerTypeHierarchyAdapter(StorageUnit.class, new DecimalStorageUnitDeserializer())
292         .create();
295 #### Jackson
297 Use the provided `StorageUnitModule` like this:
299 ```java
300 import static wtf.metio.storageunits.jackson.*;
302 ObjectMapper objectMapper = new ObjectMapper();
303 objectMapper.registerModule(new StorageUnitModule()); // defaults to binary units
304 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.BINARY));
305 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.DECIMAL));
308 #### Jakarta
310 Use the provided `AttributeConverter`s like this:
312 ```java
313 import static wtf.metio.storageunits.jakarta.*;
315 @Entity
316 public class HardDisk implements Serializable {
318     @Convert(converter = BinaryStorageUnitConverter.class)
319     public StorageUnit<?> getFreeSize() {
320         return freeSize;
321     }
323     @Convert(converter = DecimalStorageUnitConverter.class)
324     public StorageUnit<?> getTotalSize() {
325         return totalSize;
326     }
331 #### MapStruct
333 Use any of the available mappers like this:
335 ```java
336 import static wtf.metio.storageunits.mapstruct.*;
338 @Mapper( uses = BigIntegerToBinaryUnitMapper.class )
339 public interface MovieMapper {
341      DestinationType toDestination(SourceType sourceValue);
346 #### ModelMapper
348 Use any of the available converters like this:
350 ```java
351 import static wtf.metio.storageunits.modelmapper.*;
353 modelMapper.addConverter(new BigIntegerToBinaryUnitConverter());
354 modelMapper.addConverter(new BigIntegerToDecimalUnitConverter());
355 modelMapper.addConverter(new LongToBinaryUnitConverter());
356 modelMapper.addConverter(new LongToDecimalUnitConverter());
357 modelMapper.addConverter(new StorageUnitToBigIntegerConverter());
360 #### MongoDB
362 Use any of the three codecs like this:
364 ```java
365 import static wtf.metio.storageunits.mongodb.*;
367 CodecRegistry binaryRegistry = CodecRegistries.fromCodecs(new BinaryStorageUnitCodec(), ...);
368 CodecRegistry decimalRegistry = CodecRegistries.fromCodecs(new DecimalStorageUnitCodec(), ...);
371 #### Orika
373 Use any of the provided converters like this:
375 ```java
376 import static wtf.metio.storageunits.orika.*;
378 ConverterFactory converterFactory = mapperFactory.getConverterFactory();
379 converterFactory.registerConverter(new BinaryStorageUnitConverter());
380 converterFactory.registerConverter(new DecimalStorageUnitConverter());
383 ### Integration
385 To use this project just declare the following dependency inside your POM:
387 ```xml
388 <dependencies>
389     <dependency>
390         <groupId>wtf.metio.storage-units</groupId>
391         <artifactId>storage-units-model</artifactId>
392         <version>${version.storage-units}</version>
393     </dependency>
395     <!-- Dozer ONLY -->
396     <dependency>
397         <groupId>wtf.metio.storage-units</groupId>
398         <artifactId>storage-units-dozer</artifactId>
399         <version>${version.storage-units}</version>
400     </dependency>
401     <!-- Dozer ONLY -->
403     <!-- EclipseLink ONLY -->
404     <dependency>
405         <groupId>wtf.metio.storage-units</groupId>
406         <artifactId>storage-units-eclipselink</artifactId>
407         <version>${version.storage-units}</version>
408     </dependency>
409     <!-- EclipseLink ONLY -->
411     <!-- GSON ONLY -->
412     <dependency>
413         <groupId>wtf.metio.storage-units</groupId>
414         <artifactId>storage-units-gson</artifactId>
415         <version>${version.storage-units}</version>
416     </dependency>
417     <!-- GSON ONLY -->
419     <!-- Jackson ONLY -->
420     <dependency>
421         <groupId>wtf.metio.storage-units</groupId>
422         <artifactId>storage-units-jackson</artifactId>
423         <version>${version.storage-units}</version>
424     </dependency>
425     <!-- Jackson ONLY -->
427     <!-- Jakarta ONLY -->
428     <dependency>
429         <groupId>wtf.metio.storage-units</groupId>
430         <artifactId>storage-units-jakarta</artifactId>
431         <version>${version.storage-units}</version>
432     </dependency>
433     <!-- Jakarta ONLY -->
435     <!-- MapStruct ONLY -->
436     <dependency>
437         <groupId>wtf.metio.storage-units</groupId>
438         <artifactId>storage-units-mapstruct</artifactId>
439         <version>${version.storage-units}</version>
440     </dependency>
441     <!-- MapStruct ONLY -->
443     <!-- ModelMapper ONLY -->
444     <dependency>
445         <groupId>wtf.metio.storage-units</groupId>
446         <artifactId>storage-units-modelmapper</artifactId>
447         <version>${version.storage-units}</version>
448     </dependency>
449     <!-- ModelMapper ONLY -->
451     <!-- MongoDB ONLY -->
452     <dependency>
453         <groupId>wtf.metio.storage-units</groupId>
454         <artifactId>storage-units-mongodb</artifactId>
455         <version>${version.storage-units}</version>
456     </dependency>
457     <!-- MongoDB ONLY -->
459     <!-- Orika ONLY -->
460     <dependency>
461         <groupId>wtf.metio.storage-units</groupId>
462         <artifactId>storage-units-orika</artifactId>
463         <version>${version.storage-units}</version>
464     </dependency>
465     <!-- Orika ONLY -->
466 </dependencies>
469 Replace `${version.storage-units}` with the [latest release](https://search.maven.org/search?q=g:wtf.metio.storage-units).
471 ## Reference
473 Originally inspired by [Twitters util](https://github.com/twitter/util#space) package.
475 ## Alternatives
477 * [Byte Units](https://github.com/JakeWharton/byteunits)
478 * [triava](https://github.com/trivago/triava)
480 ## License
483 Permission to use, copy, modify, and/or distribute this software for any
484 purpose with or without fee is hereby granted.
486 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
487 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
488 FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
489 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
490 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
491 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
492 PERFORMANCE OF THIS SOFTWARE.