You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2025/10/12 20:22:39 UTC
(commons-codec) branch master updated: Add builder to Base16 streams and deprecate some old constructors
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git
The following commit(s) were added to refs/heads/master by this push:
new 18bd3d04 Add builder to Base16 streams and deprecate some old constructors
18bd3d04 is described below
commit 18bd3d041312579486ad12d3f3a803b485d9f5f0
Author: Gary D. Gregory <ga...@gmail.com>
AuthorDate: Sun Oct 12 16:22:33 2025 -0400
Add builder to Base16 streams and deprecate some old constructors
---
src/changes/changes.xml | 1 +
.../org/apache/commons/codec/binary/Base16.java | 88 ++++++++++++++++++----
.../codec/binary/Base16InputStreamTest.java | 6 +-
.../codec/binary/Base16OutputStreamTest.java | 6 +-
.../apache/commons/codec/binary/Base16Test.java | 4 +-
5 files changed, 82 insertions(+), 23 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1303b08c..3108b4ce 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -52,6 +52,7 @@ The <action> type attribute can be add,update,fix,remove.
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Fredrik Kjellberg, Gary Gregory">Add org.apache.commons.codec.digest.CRC16.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add builders to org.apache.commons.codec.digest streams and deprecate some old constructors.</action>
+ <action type="add" dev="ggregory" due-to="Gary Gregory">Add builder to Base16 streams and deprecate some old constructors.</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add support for SHAKE128-256 and SHAKE256-512 to `DigestUtils` and `MessageDigestAlgorithms` on Java 25 and up.</action>
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 85 to 89.</action>
diff --git a/src/main/java/org/apache/commons/codec/binary/Base16.java b/src/main/java/org/apache/commons/codec/binary/Base16.java
index 1de4ff10..99e1f0e6 100644
--- a/src/main/java/org/apache/commons/codec/binary/Base16.java
+++ b/src/main/java/org/apache/commons/codec/binary/Base16.java
@@ -17,6 +17,7 @@
package org.apache.commons.codec.binary;
+import java.util.Arrays;
import java.util.Objects;
import org.apache.commons.codec.CodecPolicy;
@@ -43,11 +44,59 @@ import org.apache.commons.codec.CodecPolicy;
*/
public class Base16 extends BaseNCodec {
+ /**
+ * Builds {@link Base16} instances.
+ *
+ * <p>
+ * To configure a new instance, use a {@link Builder}. For example:
+ * </p>
+ *
+ * <pre>
+ * Base16 Base16 = Base16.builder()
+ * .setDecodingPolicy(DecodingPolicy.LENIENT) // default is lenient
+ * .get()
+ * </pre>
+ *
+ * @since 1.20.0
+ */
+ public static class Builder extends AbstractBuilder<Base16, Builder> {
+
+ /**
+ * Constructs a new instance.
+ */
+ public Builder() {
+ super(null);
+ setEncodedBlockSize(BYTES_PER_ENCODED_BLOCK);
+ setUnencodedBlockSize(BYTES_PER_UNENCODED_BLOCK);
+ setLineLength(0);
+ setLineSeparator(EMPTY_BYTE_ARRAY);
+ }
+
+ @Override
+ public Base16 get() {
+ return new Base16(this);
+ }
+
+ /**
+ * Sets whether to use the the lower-case Base16 alphabet.
+ *
+ * @param lowerCase {@code true} to use the lower-case Base16 alphabet.
+ * @return {@code this} instance.
+ */
+ public Builder setLowerCase(final boolean lowerCase) {
+ setEncodeTableRaw(lowerCase ? LOWER_CASE_ENCODE_TABLE : UPPER_CASE_ENCODE_TABLE);
+ return asThis();
+ }
+
+ }
+
/**
* BASE16 characters are 4 bits in length. They are formed by taking an 8-bit group, which is converted into two BASE16 characters.
*/
private static final int BITS_PER_ENCODED_BYTE = 4;
+
private static final int BYTES_PER_ENCODED_BLOCK = 2;
+
private static final int BYTES_PER_UNENCODED_BLOCK = 1;
/**
* This array is a lookup table that translates Unicode characters drawn from the "Base16 Alphabet" (as specified in Table 5 of RFC 4648) into their 4-bit
@@ -68,6 +117,7 @@ public class Base16 extends BaseNCodec {
* 4648.
*/
private static final byte[] UPPER_CASE_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
/**
* This array is a lookup table that translates Unicode characters drawn from the a lower-case "Base16 Alphabet" into their 4-bit positive integer
* equivalents. Characters that are not in the Base16 alphabet but fall within the bounds of the array are translated to -1.
@@ -88,12 +138,25 @@ public class Base16 extends BaseNCodec {
* This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" lower-case equivalents.
*/
private static final byte[] LOWER_CASE_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
/** Mask used to extract 4 bits, used when decoding character. */
private static final int MASK_4_BITS = 0x0f;
+
+ /**
+ * Constructs a new builder.
+ *
+ * @return a new builder.
+ * @since 1.20.0
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
/**
* Decode table to use.
*/
private final byte[] decodeTable;
+
/**
* Encode table to use.
*/
@@ -109,8 +172,10 @@ public class Base16 extends BaseNCodec {
/**
* Constructs a Base16 codec used for decoding and encoding.
*
- * @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
+ * @param lowerCase {@code true} to use the lower-case Base16 alphabet.
+ * @deprecated Use {@link #builder()} and {@link Builder}.
*/
+ @Deprecated
public Base16(final boolean lowerCase) {
this(lowerCase, DECODING_POLICY_DEFAULT);
}
@@ -118,24 +183,19 @@ public class Base16 extends BaseNCodec {
/**
* Constructs a Base16 codec used for decoding and encoding.
*
- * @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
+ * @param lowerCase {@code true} to use the lower-case Base16 alphabet.
* @param decodingPolicy Decoding policy.
+ * @deprecated Use {@link #builder()} and {@link Builder}.
*/
+ @Deprecated
public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) {
- this(lowerCase ? LOWER_CASE_ENCODE_TABLE : UPPER_CASE_ENCODE_TABLE, decodingPolicy);
+ this(builder().setEncodeTable(lowerCase ? LOWER_CASE_ENCODE_TABLE : UPPER_CASE_ENCODE_TABLE).setDecodingPolicy(decodingPolicy));
}
- /**
- * Constructs a Base16 codec used for decoding and encoding.
- *
- * @param encodeTable the encode table.
- * @param decodingPolicy Decoding policy.
- */
- private Base16(final byte[] encodeTable, final CodecPolicy decodingPolicy) {
- super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 0, 0, PAD_DEFAULT, decodingPolicy);
- Objects.requireNonNull(encodeTable, "encodeTable");
- this.encodeTable = encodeTable;
- this.decodeTable = encodeTable == LOWER_CASE_ENCODE_TABLE ? LOWER_CASE_DECODE_TABLE : UPPER_CASE_DECODE_TABLE;
+ private Base16(final Builder builder) {
+ super(builder);
+ this.encodeTable = Objects.requireNonNull(builder.getEncodeTable(), "encodeTable");
+ this.decodeTable = Arrays.equals(encodeTable, LOWER_CASE_ENCODE_TABLE) ? LOWER_CASE_DECODE_TABLE : UPPER_CASE_DECODE_TABLE;
}
@Override
diff --git a/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java
index e87e015f..ee727607 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java
@@ -93,7 +93,7 @@ class Base16InputStreamTest {
decoded = BaseNTestData.DECODED;
testByChunk(encoded, decoded);
// test random data of sizes 0 through 150
- final BaseNCodec codec = new Base16(true);
+ final BaseNCodec codec = Base16.builder().setLowerCase(true).get();
for (int i = 0; i <= 150; i++) {
final byte[][] randomData = BaseNTestData.randomData(codec, i);
encoded = randomData[1];
@@ -122,7 +122,7 @@ class Base16InputStreamTest {
decoded = BaseNTestData.DECODED;
testByteByByte(encoded, decoded);
// test random data of sizes 0 through 150
- final BaseNCodec codec = new Base16(true);
+ final BaseNCodec codec = Base16.builder().setLowerCase(true).get();
for (int i = 0; i <= 150; i++) {
final byte[][] randomData = BaseNTestData.randomData(codec, i);
encoded = randomData[1];
@@ -225,7 +225,7 @@ class Base16InputStreamTest {
}
try (InputStream in = Base16InputStream.builder()
.setInputStream(new ByteArrayInputStream(decoded))
- .setEncode(true).setBaseNCodec(new Base16(lowerCase))
+ .setEncode(true).setBaseNCodec(Base16.builder().setLowerCase(lowerCase).get())
.get()) {
final byte[] output = new byte[encoded.length];
for (int i = 0; i < output.length; i++) {
diff --git a/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
index 6f0cc3ff..1ab234bd 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
@@ -65,7 +65,7 @@ class Base16OutputStreamTest {
testByChunk(encoded, decoded);
// test random data of sizes 0 through 150
- final BaseNCodec codec = new Base16(true);
+ final BaseNCodec codec = Base16.builder().setLowerCase(true).get();
for (int i = 0; i <= 150; i++) {
final byte[][] randomData = BaseNTestData.randomData(codec, i);
encoded = randomData[1];
@@ -90,7 +90,7 @@ class Base16OutputStreamTest {
decoded = new byte[] { (byte) 0x41 };
testByteByByte(encoded, decoded);
// test random data of sizes 0 through 150
- final BaseNCodec codec = new Base16(true);
+ final BaseNCodec codec = Base16.builder().setLowerCase(true).get();
for (int i = 0; i <= 150; i++) {
final byte[][] randomData = BaseNTestData.randomData(codec, i);
encoded = randomData[1];
@@ -199,7 +199,7 @@ class Base16OutputStreamTest {
}
try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
OutputStream out = Base16OutputStream.builder()
- .setOutputStream(byteOut).setEncode(true).setBaseNCodec(new Base16(lowerCase))
+ .setOutputStream(byteOut).setEncode(true).setBaseNCodec(Base16.builder().setLowerCase(lowerCase).get())
.get()) {
for (final byte element : decoded) {
out.write(element);
diff --git a/src/test/java/org/apache/commons/codec/binary/Base16Test.java b/src/test/java/org/apache/commons/codec/binary/Base16Test.java
index 98acee1e..7e36f729 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16Test.java
@@ -248,7 +248,7 @@ class Base16Test {
@Test
void testIsInAlphabet() {
// invalid bounds
- Base16 b16 = new Base16(true);
+ Base16 b16 = Base16.builder().setLowerCase(true).get();
assertFalse(b16.isInAlphabet((byte) 0));
assertFalse(b16.isInAlphabet((byte) 1));
assertFalse(b16.isInAlphabet((byte) -1));
@@ -256,7 +256,6 @@ class Base16Test {
assertFalse(b16.isInAlphabet((byte) -16));
assertFalse(b16.isInAlphabet((byte) 128));
assertFalse(b16.isInAlphabet((byte) 255));
-
// lower-case
b16 = new Base16(true);
for (char c = '0'; c <= '9'; c++) {
@@ -273,7 +272,6 @@ class Base16Test {
assertFalse(b16.isInAlphabet((byte) ('a' - 1)));
assertFalse(b16.isInAlphabet((byte) ('f' + 1)));
assertFalse(b16.isInAlphabet((byte) ('z' + 1)));
-
// upper-case
b16 = new Base16(false);
for (char c = '0'; c <= '9'; c++) {