Utility functions for reading and writing primitive values from byte collections with explicit byte order and word order control.
- Multiple byte sources:
byte[],java.nio.ByteBuffer, and NettyByteBuf - Four byte ordering variations: Big-endian, little-endian, and word-swapped variants
- Unsigned type support: Optional modules for jOOU and Eclipse Milo unsigned types
- Zero dependencies: Core module has no runtime dependencies (besides JSpecify annotations)
- Java 11+: Compatible with Java 11 and later
Add the dependency to your pom.xml:
<dependency>
<groupId>com.digitalpetri.util</groupId>
<artifactId>byteops</artifactId>
<version>0.2.1</version>
</dependency>| Module | Artifact ID | Description |
|---|---|---|
| Core | byteops | byte[] and ByteBuffer support |
| Netty | byteops-netty | Netty ByteBuf support |
| Unsigned (jOOU) | byteops-unsigned | UByte, UShort, UInteger, ULong via jOOU |
| Unsigned (Milo) | byteops-milo | Unsigned types from Eclipse Milo |
importcom.digitalpetri.util.byteops.ByteArrayByteOps;
importcom.digitalpetri.util.byteops.ByteOps;
// Get a ByteOps instance for your preferred byte orderingByteOps<byte[]> ops = ByteArrayByteOps.BIG_ENDIAN;
byte[] data = newbyte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
shorts = ops.getShort(data, 0); // 0x0001inti = ops.getInt(data, 0); // 0x00010203longl = ops.getLong(data, 0); // 0x0001020304050607Lfloatf = ops.getFloat(data, 0); // Float.intBitsToFloat(0x00010203)doubled = ops.getDouble(data, 0); // Double.longBitsToDouble(0x0001020304050607L)ByteOps<byte[]> ops = ByteArrayByteOps.LITTLE_ENDIAN;
byte[] buffer = newbyte[8];
ops.setInt(buffer, 0, 0x01020304);
ops.setInt(buffer, 4, 0x05060708);
// buffer: [0x04, 0x03, 0x02, 0x01, 0x08, 0x07, 0x06, 0x05]ByteOps<byte[]> ops = ByteArrayByteOps.BIG_ENDIAN;
// Read an array of ints (2 ints = 8 bytes)byte[] data = newbyte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
int[] ints = ops.getIntArray(data, 0, 2); // [0x00010203, 0x04050607]// Write an array of shortsbyte[] buffer = newbyte[4];
ops.setShortArray(buffer, 0, newshort[] {0x0102, 0x0304});
// buffer: [0x01, 0x02, 0x03, 0x04]importcom.digitalpetri.util.byteops.ByteBufferByteOps;
importjava.nio.ByteBuffer;
ByteOps<ByteBuffer> ops = ByteBufferByteOps.BIG_ENDIAN;
ByteBufferbuffer = ByteBuffer.allocate(8);
ops.setLong(buffer, 0, 0x0102030405060708L);
longvalue = ops.getLong(buffer, 0); // 0x0102030405060708Limportcom.digitalpetri.util.byteops.netty.ByteBufByteOps;
importio.netty.buffer.ByteBuf;
importio.netty.buffer.Unpooled;
ByteOps<ByteBuf> ops = ByteBufByteOps.LITTLE_ENDIAN;
ByteBufbuf = Unpooled.buffer(8);
buf.writeZero(8); // ensure writable bytesops.setLong(buf, 0, 0x0102030405060708L);
longvalue = ops.getLong(buf, 0); // 0x0102030405060708Limportcom.digitalpetri.util.byteops.unsigned.UnsignedByteOps;
importorg.joou.UInteger;
ByteOps<byte[]> baseOps = ByteArrayByteOps.BIG_ENDIAN;
UnsignedByteOps<byte[]> ops = UnsignedByteOps.of(baseOps);
byte[] data = newbyte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
UIntegervalue = ops.getUInt(data, 0); // 4294967295 (not -1)Four byte ordering variations are available for each implementation:
| Constant | Byte Order | Word Order |
|---|---|---|
BIG_ENDIAN | Big | High-Low |
LITTLE_ENDIAN | Little | High-Low |
BIG_ENDIAN_LOW_HIGH | Big | Low-High |
LITTLE_ENDIAN_LOW_HIGH | Little | Low-High |
For a 32-bit integer 0x01020304:
BIG_ENDIAN: [0x01, 0x02, 0x03, 0x04] (bytes: 1,2,3,4)
LITTLE_ENDIAN: [0x04, 0x03, 0x02, 0x01] (bytes: 4,3,2,1)
BIG_ENDIAN_LOW_HIGH: [0x03, 0x04, 0x01, 0x02] (words swapped: 3,4,1,2)
LITTLE_ENDIAN_LOW_HIGH: [0x02, 0x01, 0x04, 0x03] (words swapped: 2,1,4,3)
The ByteOps<T> interface provides:
| Method | Size | Description |
|---|---|---|
getBoolean / setBoolean | 1 byte | false = 0, true = non-zero |
getByte / setByte | 1 byte | Signed byte |
getShort / setShort | 2 bytes | Signed 16-bit integer |
getInt / setInt | 4 bytes | Signed 32-bit integer |
getLong / setLong | 8 bytes | Signed 64-bit integer |
getFloat / setFloat | 4 bytes | IEEE 754 single-precision |
getDouble / setDouble | 8 bytes | IEEE 754 double-precision |
get*Array/set*Array- Primitive arrays (boolean[],byte[],short[], etc.)getBoxed*Array/setBoxed*Array- Boxed arrays (Boolean[],Byte[],Short[], etc.)
- JDK 17 is required to build (via Maven Toolchains)
- Target: Java 11 bytecode
Create or edit ~/.m2/toolchains.xml:
<?xml version="1.0" encoding="UTF-8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>17</version>
</provides>
<configuration>
<jdkHome>/path/to/your/jdk-17</jdkHome>
</configuration>
</toolchain>
</toolchains>mvn clean package # Build all modules
mvn test# Run tests
mvn spotless:apply # Format code (Google Java Format)
mvn spotless:check # Check code formattingbyteops/
├── byteops/ # Core module (byte[], ByteBuffer)
├── byteops-netty/ # Netty ByteBuf support
├── byteops-unsigned/ # jOOU unsigned types (UByte, UShort, UInteger, ULong)
└── byteops-milo/ # Eclipse Milo unsigned types
This project is licensed under the Eclipse Public License 2.0.