fix #25 add SimpleXML converter
[storage-units.git] / README.md
blobe2c56523cc4efce16a9c0751f5403b7d098ce52b
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
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 |
35 | Name      | Symbol | Exponential          | Absolute                               |
36 |-----------|--------|----------------------|----------------------------------------|
37 | Byte      | B      | 10<sup>0</sup> Byte  | 1 Byte                                 |
38 | Kilobyte  | KB     | 10<sup>3</sup> Byte  | 1 000 Byte                             |
39 | Megabyte  | MB     | 10<sup>6</sup> Byte  | 1 000 000 Byte                         |
40 | Gigabyte  | GB     | 10<sup>9</sup> Byte  | 1 000 000 000 Byte                     |
41 | Terabyte  | TB     | 10<sup>12</sup> Byte | 1 000 000 000 000 Byte                 |
42 | Petabyte  | PB     | 10<sup>15</sup> Byte | 1 000 000 000 000 000 Byte             |
43 | Exabyte   | EB     | 10<sup>18</sup> Byte | 1 000 000 000 000 000 000 Byte         |
44 | Zettabyte | ZB     | 10<sup>21</sup> Byte | 1 000 000 000 000 000 000 000 Byte     |
45 | Yottabyte | YB     | 10<sup>24</sup> Byte | 1 000 000 000 000 000 000 000 000 Byte |
47 ## Usage
49 ### Factories
51 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`.
53 ```java
54 // 'long' based
55 Kilobyte unit = Kilobyte.valueOf(500)                                       // 500 Byte or "0.50 kB"
56 Kibibyte unit = Kibibyte.valueOf(512)                                       // 512 Byte or "0.50 KiB"
58 Megabyte unit = Megabyte.valueOf(1_000_000)                                 // 1 000 000 Byte or "1.00 MB"
59 Mebibyte unit = Mebibyte.valueOf(1_048_576)                                 // 1 048 576 Byte or "1.00 MiB"
61 // 'BigInteger' based
62 Kilobyte unit = Kilobyte.valueOf(BigInteger.valueOf(500))                   // 500 Byte or "0.50 kB"
63 Kibibyte unit = Kibibyte.valueOf(BigInteger.valueOf(512))                   // 512 Byte or "0.50 KiB"
65 Megabyte unit = Megabyte.valueOf(BigInteger.valueOf(1000000))               // 1 000 000 Byte or "1.00 MB"
66 Mebibyte unit = Mebibyte.valueOf(BigInteger.valueOf(1_048_576))             // 1 048 576 Byte or "1.00 MB"
67 ```
69 The `StorageUnits` class offers three factory methods that automatically pick the best-matching unit for a given number of bytes.
71 #### Binary Units
73 ```java
74 // 'long' based
75 StorageUnit<?> unit = StorageUnits.binaryValueOf(256)                         // Kibibyte (0.25 KiB)
76 StorageUnit<?> unit = StorageUnits.binaryValueOf(1048576)                     // Mebibyte (1.00 MiB)
78 // 'BigInteger' based
79 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(256))     // Kibibyte (0.25 MiB)
80 StorageUnit<?> unit = StorageUnits.binaryValueOf(BigInteger.valueOf(1048576)) // Mebibyte (1.00 MiB)
81 ```
83 #### Decimal Units
85 ```java
86 // 'long' based
87 StorageUnit<?> unit = StorageUnits.decimalValueOf(120000)                      // Kilobyte (120.00 kB)
88 StorageUnit<?> unit = StorageUnits.decimalValueOf(1000000)                     // Megabyte (1.00 MB)
90 // 'BigInteger' based
91 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(120000))  // Kilobyte (120.00 kB)
92 StorageUnit<?> unit = StorageUnits.decimalValueOf(BigInteger.valueOf(1000000)) // Megabyte (1.00 MB)
93 ```
95 Additionally high-level factory methods are also available in the `StorageUnits` class.
97 ```java
98 import static wtf.metio.storageunits.model.StorageUnits.*;
100 Kibibyte unit = kibibyte(1)   // 1 024 Byte
101 Mebibyte unit = mebibyte(1)   // 1 048 576 Byte
102 Gibibyte unit = gibibyte(1)   // 1 073 741 824 Byte
103 Tebibyte unit = tebibyte(1)   // 1 099 511 627 776 Byte
104 Pebibyte unit = pebibyte(1)   // 1 125 899 906 842 624 Byte
105 Exbibyte unit = exbibyte(1)   // 1 152 921 504 606 846 976 Byte
106 Zebibyte unit = zebibyte(1)   // 1 180 591 620 717 411 303 424 Byte
107 Yobibyte unit = yobibyte(1)   // 1 208 925 819 614 629 174 706 176 Byte
109 Kilobyte unit = kilobyte(1)   // 1 000 Byte
110 Megabyte unit = megabyte(1)   // 1 000 000 Byte
111 Gigabyte unit = gigabyte(1)   // 1 000 000 000 Byte
112 Terabyte unit = terabyte(1)   // 1 000 000 000 000 Byte
113 Petabyte unit = petabyte(1)   // 1 000 000 000 000 000 Byte
114 Exabyte unit = exabyte(1)     // 1 000 000 000 000 000 000 Byte
115 Zettabyte unit = zettabyte(1) // 1 000 000 000 000 000 000 000 Byte
116 Yottabyte unit = yottabyte(1) // 1 000 000 000 000 000 000 000 000 Byte
119 ### Add, Subtract, Multiply, Divide
121 Each unit implements the basic four math operations. All operations retain their original type, e.g. `[Kilobyte] + [Megabyte] = [Kilobyte]`
123 ```java
124 import static wtf.metio.storageunits.model.StorageUnits.*;
126 kilobyte(4).add(kilobyte(8))        // 4 Kilobyte + 8 Kilobyte = 12 Kilobyte = 12 000 Byte
127 kibibyte(1).add(1024)               // 1 Kibibyte + 1 024 Byte = 2 Kibibyte = 2 048 Byte
128 kibibyte(1).subtract(24)            // 1 024 Byte - 24 Byte = 1 000 Byte
129 megabyte(5).subtract(kilobyte(500)) // 5 Megabyte - 500 Kilobyte = 4.5 Megabyte = 4 500 Kilobyte = 4 500 000 Byte
130 gigabyte(1).multiply(5)             // 1 Gigabyte times 5 = 5 Gigabyte
131 terabyte(1).divide(5)               // 1 Terabyte divided by 5 = 0.2 Terabyte = 200 Gigabyte
134 ### Comparison & Equality
136 Each unit is comparable to each other unit.
138 ```java
139 import static wtf.metio.storageunits.model.StorageUnits.*;
141 kibibyte(1024).compareTo(mebibyte(1)) == 0 // true
142 kibibyte(1000).compareTo(mebibyte(1)) == 0 // false
143 petabyte(3).compareTo(terabyte(3000)) == 0 // true
145 megabyte(1000).equals(gigabyte(1))         // true
146 megabyte(1024).equals(gigabyte(1))         // false
147 terabyte(12).equals(gigabyte(12000))       // true
150 ### Formatting
152 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.
154 ```java
155 import static wtf.metio.storageunits.model.StorageUnits.*;
157 // default pattern '0.00'
158 terabyte(2).toString()                         // "2.00 TB"
159 gigabyte(1).add(megabyte(200)).toString()      // "1.20 GB"
160 petabyte(1).subtract(terabyte(250)).toString() // "0.75 PB"
162 // use custom pattern
163 kilobyte(212345).toString("0.0")                                    // "212345.0 kB"
164 gibibyte(2123458).asTebibyte().toString("#,###.000")                // "2,073.689 TiB"
165 kilobyte(120).asMegabyte().add(gigabyte(1)).toString("#,##0.00000") // "1,000.12000 MB"
167 // use custom pattern with specific Locale
168 kilobyte(212345).toString("0.0", Locale.GERMAN)                     // "212345,0 kB"
169 gibibyte(2123458).asTebibyte().toString("#,###.000", Locale.GERMAN) // "2.073,689 TiB"
171 // use custom format
172 Format customFormat = new DecimalFormat("#.00000");
173 terabyte(4).asTebibyte().toString(customFormat) // "3.63798 TiB"
175 // without creating unit type first
176 long numberOfBytes = 1_000_000_000_000_000L;
177 formatAsPetabyte(numberOfBytes) // "1.00 PB"
178 formatAsTerabyte(numberOfBytes) // "1000.00 TB"
179 formatAsPebibyte(numberOfBytes) // "0.89 PiB"
181 // use custom pattern
182 formatAsTerabyte(numberOfBytes, "#0.#####") // "1000 TB"
183 formatAsPebibyte(numberOfBytes, "#0.#####") // "0.88818 PiB"
185 // use custom pattern with specific Locale
186 formatAsTerabyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "1000 TB"
187 formatAsPebibyte(numberOfBytes, "#0.#####", Locale.GERMAN) // "0,88818 PiB"
189 // use custom format
190 formatAsTerabyte(numberOfBytes, customFormat) // "1000.00000 TB"
191 formatAsPebibyte(numberOfBytes, customFormat) // ".88818 PiB"
194 ### Conversions
196 Each unit can be converted to each other unit without loss of information.
198 ```java
199 import static wtf.metio.storageunits.model.StorageUnits.*;
201 Megabyte unit = kilobyte(1000).asMegabyte() // "1.00 MB"
202 Kilobyte unit = gigabyte(12).asKilobyte()   // "12000000.00 kB"
203 Gigabyte unit = terabyte(1).asGigabyte()    // "1000.00 GB"
205 // convert to best-match
206 kilobyte(1100).asBestMatchingUnit()          // "1.10 MB"
207 kilobyte(1100).asBestMatchingBinaryUnit()    // "1.05 MiB"
208 kilobyte(1100).asBestMatchingDecimalUnit()   // "1.10 MB"
209 kilobyte(1100).asBestMatchingCommonUnit()    // "1.05 MB"
212 Each unit can be expressed as a fraction of another unit (precise up to 24 decimal places)
214 ```java
215 import static wtf.metio.storageunits.model.StorageUnits.*;
217 BigDecimal kilobytes = megabyte(1).inKilobyte()  // 1 000
218 BigInteger bytes = kibibyte(2).inByte()          // 2 048
219 BigDecimal terabytes = gigabyte(15).inTerabyte() // 0.015
222 ### Serialization/Converters/Mappers
224 Multiple custom serializers, converters, and mappers are available for all storage units.
226 #### Dozer
228 Use a [Dozer](https://dozermapper.github.io/) converter like this:
230 ```java
231 import static wtf.metio.storageunits.dozer.*;
233 DozerBeanMapperBuilder.create()
234         .withCustomConverter(new BigIntegerBinaryStorageUnitConverter())
235         .withCustomConverter(new BigIntegerDecimalStorageUnitConverter())
236         .withCustomConverter(new LongBinaryStorageUnitConverter())
237         .withCustomConverter(new LongDecimalStorageUnitConverter())
238         .build();
241 #### EclipseLink
243 Use any of the three converters like this:
245 ```java
246 import static wtf.metio.storageunits.eclipselink.*;
248 @Entity
249 public class HardDisk implements Serializable {
251     @Basic
252     @Converter (
253         name="binaryConverter",
254         converterClass=BinaryStorageUnitConverter.class
255     )
256     @Convert("binaryConverter")
257     public StorageUnit<?> getFreeSize() {
258         return freeSize;
259     }
261     @Basic
262     @Converter (
263         name="decimalConverter",
264         converterClass=DecimalyStorageUnitConverter.class
265     )
266     @Convert("decimalConverter")
267     public StorageUnit<?> getTotalSize() {
268         return totalSize;
269     }
274 #### Jackson
276 Use the provided `StorageUnitModule` like this:
278 ```java
279 import static wtf.metio.storageunits.jackson.*;
281 ObjectMapper objectMapper = new ObjectMapper();
282 objectMapper.registerModule(new StorageUnitModule()); // defaults to binary units
283 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.BINARY));
284 objectMapper.registerModule(new StorageUnitModule(StorageUnitModule.PreferredUnitType.DECIMAL));
287 #### Jakarta
289 Use the provided `AttributeConverter`s like this:
291 ```java
292 import static wtf.metio.storageunits.jakarta.*;
294 @Entity
295 public class HardDisk implements Serializable {
297     @Convert(converter = BinaryStorageUnitConverter.class)
298     public StorageUnit<?> getFreeSize() {
299         return freeSize;
300     }
302     @Convert(converter = DecimalStorageUnitConverter.class)
303     public StorageUnit<?> getTotalSize() {
304         return totalSize;
305     }
310 #### MapStruct
312 Use any of the available mappers like this:
314 ```java
315 import static wtf.metio.storageunits.mapstruct.*;
317 @Mapper( uses = BigIntegerToBinaryUnitMapper.class )
318 public interface MovieMapper {
320      DestinationType toDestination(SourceType sourceValue);
325 #### ModelMapper
327 Use any of the available converters like this:
329 ```java
330 import static wtf.metio.storageunits.modelmapper.*;
332 modelMapper.addConverter(new BigIntegerToBinaryUnitConverter());
333 modelMapper.addConverter(new BigIntegerToDecimalUnitConverter());
334 modelMapper.addConverter(new LongToBinaryUnitConverter());
335 modelMapper.addConverter(new LongToDecimalUnitConverter());
336 modelMapper.addConverter(new StorageUnitToBigIntegerConverter());
339 #### MongoDB
341 Use any of the three codecs like this:
343 ```java
344 import static wtf.metio.storageunits.mongodb.*;
346 CodecRegistry binaryRegistry = CodecRegistries.fromCodecs(new BinaryStorageUnitCodec(), ...);
347 CodecRegistry decimalRegistry = CodecRegistries.fromCodecs(new DecimalStorageUnitCodec(), ...);
350 #### Orika
352 Use any of the provided converters like this:
354 ```java
355 import static wtf.metio.storageunits.orika.*;
357 ConverterFactory converterFactory = mapperFactory.getConverterFactory();
358 converterFactory.registerConverter(new BinaryStorageUnitConverter());
359 converterFactory.registerConverter(new DecimalStorageUnitConverter());
362 ### Integration
364 To use this project just declare the following dependency inside your POM:
366 ```xml
367 <dependencies>
368     <dependency>
369         <groupId>wtf.metio.storage-units</groupId>
370         <artifactId>storage-units-model</artifactId>
371         <version>${version.storage-units}</version>
372     </dependency>
374     <!-- Dozer ONLY -->
375     <dependency>
376         <groupId>wtf.metio.storage-units</groupId>
377         <artifactId>storage-units-dozer</artifactId>
378         <version>${version.storage-units}</version>
379     </dependency>
380     <!-- Dozer ONLY -->
382     <!-- EclipseLink ONLY -->
383     <dependency>
384         <groupId>wtf.metio.storage-units</groupId>
385         <artifactId>storage-units-eclipselink</artifactId>
386         <version>${version.storage-units}</version>
387     </dependency>
388     <!-- EclipseLink ONLY -->
390     <!-- Jackson ONLY -->
391     <dependency>
392         <groupId>wtf.metio.storage-units</groupId>
393         <artifactId>storage-units-jackson</artifactId>
394         <version>${version.storage-units}</version>
395     </dependency>
396     <!-- Jackson ONLY -->
398     <!-- Jakarta ONLY -->
399     <dependency>
400         <groupId>wtf.metio.storage-units</groupId>
401         <artifactId>storage-units-jakarta</artifactId>
402         <version>${version.storage-units}</version>
403     </dependency>
404     <!-- Jakarta ONLY -->
406     <!-- MapStruct ONLY -->
407     <dependency>
408         <groupId>wtf.metio.storage-units</groupId>
409         <artifactId>storage-units-mapstruct</artifactId>
410         <version>${version.storage-units}</version>
411     </dependency>
412     <!-- MapStruct ONLY -->
414     <!-- ModelMapper ONLY -->
415     <dependency>
416         <groupId>wtf.metio.storage-units</groupId>
417         <artifactId>storage-units-modelmapper</artifactId>
418         <version>${version.storage-units}</version>
419     </dependency>
420     <!-- ModelMapper ONLY -->
422     <!-- MongoDB ONLY -->
423     <dependency>
424         <groupId>wtf.metio.storage-units</groupId>
425         <artifactId>storage-units-mongodb</artifactId>
426         <version>${version.storage-units}</version>
427     </dependency>
428     <!-- MongoDB ONLY -->
430     <!-- Orika ONLY -->
431     <dependency>
432         <groupId>wtf.metio.storage-units</groupId>
433         <artifactId>storage-units-orika</artifactId>
434         <version>${version.storage-units}</version>
435     </dependency>
436     <!-- Orika ONLY -->
437 </dependencies>
440 Replace `${version.storage-units}` with the [latest release](https://search.maven.org/search?q=g:wtf.metio.storageunits).
442 ## Reference
444 Originally inspired by [Twitters util](https://github.com/twitter/util#space) package.
446 ## Alternatives
448 * [Byte Units](https://github.com/JakeWharton/byteunits)
449 * [triava](https://github.com/trivago/triava)
451 ## License
454 Permission to use, copy, modify, and/or distribute this software for any
455 purpose with or without fee is hereby granted.
457 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
458 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
459 FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
460 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
461 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
462 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
463 PERFORMANCE OF THIS SOFTWARE.