Skip to content

Commit a1c24b1

Browse files
committed
Add builders to org.apache.commons.codec.digest streams and deprecate
some old constructors
1 parent 4272563 commit a1c24b1

18 files changed

+862
-404
lines changed

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ The <action> type attribute can be add,update,fix,remove.
5151
<action type="update" dev="ggregory" due-to="Gary Gregory">BaseNCodecOutputStream subclasses are now type-safe to match its matching BaseNCodec.</action>
5252
<!-- ADD -->
5353
<action type="add" dev="ggregory" due-to="Fredrik Kjellberg, Gary Gregory">Add org.apache.commons.codec.digest.CRC16.</action>
54+
<action type="add" dev="ggregory" due-to="Gary Gregory">Add builders to org.apache.commons.codec.digest streams and deprecate some old constructors.</action>
5455
<!-- UPDATE -->
5556
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 85 to 88.</action>
5657
<action type="update" dev="ggregory" due-to="Gary Gregory">[test] Bump org.apache.commons:commons-lang3 from 3.18.0 to 3.19.0.</action>

src/conf/spotbugs-exclude-filter.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,10 @@
9898
<Class name="org.apache.commons.codec.language.bm.Rule$PhonemeList" />
9999
<Method name="&lt;init&gt;" />
100100
</Match>
101+
<Match>
102+
<!-- By design -->
103+
<Bug pattern="EI_EXPOSE_REP2" />
104+
<Class name="org.apache.commons.codec.binary.BaseNCodecOutputStream$AbstractBuilder" />
105+
<Method name="setOutputStream" />
106+
</Match>
101107
</FindBugsFilter>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.commons.codec.binary;
19+
20+
import java.util.function.Supplier;
21+
22+
/**
23+
* Builds input and output stream instances in {@link BaseNCodec} format.
24+
*
25+
* @param <T> the stream type to build.
26+
* @param <C> A {@link BaseNCodec} subclass.
27+
* @param <B> the builder subclass.
28+
* @since 1.20.0
29+
*/
30+
public abstract class AbstractBaseNCodecStreamBuilder<T, C extends BaseNCodec, B extends AbstractBaseNCodecStreamBuilder<T, C, B>> implements Supplier<T> {
31+
32+
private C baseNCodec;
33+
private boolean encode;
34+
35+
/**
36+
* Constructs a new instance.
37+
*/
38+
public AbstractBaseNCodecStreamBuilder() {
39+
baseNCodec = newBaseNCodec();
40+
}
41+
42+
@SuppressWarnings("unchecked")
43+
B asThis() {
44+
return (B) this;
45+
}
46+
47+
/**
48+
* Gets the codec to encode/decode a stream.
49+
*
50+
* @return the codec to encode/decode a stream.
51+
*/
52+
protected C getBaseNCodec() {
53+
return baseNCodec;
54+
}
55+
56+
/**
57+
* Gets whether to encode or decode a stream.
58+
*
59+
* @return whether to encode or decode a stream.
60+
*/
61+
protected boolean getEncode() {
62+
return encode;
63+
}
64+
65+
/**
66+
* Creates a new BaseNCodec subclass of type C.
67+
*
68+
* @return a new BaseNCodec subclass of type C.
69+
*/
70+
protected abstract C newBaseNCodec();
71+
72+
/**
73+
* Sets a BaseNCodec subclass of type C.
74+
*
75+
* @param baseNCodec a BaseNCodec subclass of type C.
76+
* @return {@code this} instance.
77+
*/
78+
public B setBaseNCodec(final C baseNCodec) {
79+
this.baseNCodec = baseNCodec != null ? baseNCodec : newBaseNCodec();
80+
return asThis();
81+
}
82+
83+
/**
84+
* Sets whether we should encode all data read (true), or if false if we should decode.
85+
*
86+
* @param encode encode or decode.
87+
* @return {@code this} instance.
88+
*/
89+
public B setEncode(final boolean encode) {
90+
this.encode = encode;
91+
return asThis();
92+
}
93+
}

src/main/java/org/apache/commons/codec/binary/Base16.java

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public class Base16 extends BaseNCodec {
4949
private static final int BITS_PER_ENCODED_BYTE = 4;
5050
private static final int BYTES_PER_ENCODED_BLOCK = 2;
5151
private static final int BYTES_PER_UNENCODED_BLOCK = 1;
52-
5352
/**
5453
* 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
5554
* positive integer equivalents. Characters that are not in the Base16 alphabet but fall within the bounds of the array are translated to -1.
@@ -64,13 +63,11 @@ public class Base16 extends BaseNCodec {
6463
-1, 10, 11, 12, 13, 14, 15 // 40-46 A-F
6564
};
6665
// @formatter:on
67-
6866
/**
6967
* This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" equivalents as specified in Table 5 of RFC
7068
* 4648.
7169
*/
7270
private static final byte[] UPPER_CASE_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
73-
7471
/**
7572
* This array is a lookup table that translates Unicode characters drawn from the a lower-case "Base16 Alphabet" into their 4-bit positive integer
7673
* equivalents. Characters that are not in the Base16 alphabet but fall within the bounds of the array are translated to -1.
@@ -87,20 +84,16 @@ public class Base16 extends BaseNCodec {
8784
-1, 10, 11, 12, 13, 14, 15 // 60-66 a-f
8885
};
8986
// @formatter:on
90-
9187
/**
9288
* This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" lower-case equivalents.
9389
*/
9490
private static final byte[] LOWER_CASE_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
95-
9691
/** Mask used to extract 4 bits, used when decoding character. */
9792
private static final int MASK_4_BITS = 0x0f;
98-
9993
/**
10094
* Decode table to use.
10195
*/
10296
private final byte[] decodeTable;
103-
10497
/**
10598
* Encode table to use.
10699
*/
@@ -124,24 +117,25 @@ public Base16(final boolean lowerCase) {
124117

125118
/**
126119
* Constructs a Base16 codec used for decoding and encoding.
127-
* @param encodeTable the encode table.
120+
*
121+
* @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
128122
* @param decodingPolicy Decoding policy.
129123
*/
130-
private Base16(final byte[] encodeTable, final CodecPolicy decodingPolicy) {
131-
super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 0, 0, PAD_DEFAULT, decodingPolicy);
132-
Objects.requireNonNull(encodeTable, "encodeTable");
133-
this.encodeTable = encodeTable;
134-
this.decodeTable = encodeTable == LOWER_CASE_ENCODE_TABLE ? LOWER_CASE_DECODE_TABLE : UPPER_CASE_DECODE_TABLE;
124+
public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) {
125+
this(lowerCase ? LOWER_CASE_ENCODE_TABLE : UPPER_CASE_ENCODE_TABLE, decodingPolicy);
135126
}
136127

137128
/**
138129
* Constructs a Base16 codec used for decoding and encoding.
139130
*
140-
* @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
131+
* @param encodeTable the encode table.
141132
* @param decodingPolicy Decoding policy.
142133
*/
143-
public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) {
144-
this(lowerCase ? LOWER_CASE_ENCODE_TABLE : UPPER_CASE_ENCODE_TABLE, decodingPolicy);
134+
private Base16(final byte[] encodeTable, final CodecPolicy decodingPolicy) {
135+
super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 0, 0, PAD_DEFAULT, decodingPolicy);
136+
Objects.requireNonNull(encodeTable, "encodeTable");
137+
this.encodeTable = encodeTable;
138+
this.decodeTable = encodeTable == LOWER_CASE_ENCODE_TABLE ? LOWER_CASE_DECODE_TABLE : UPPER_CASE_DECODE_TABLE;
145139
}
146140

147141
@Override
@@ -240,7 +234,7 @@ public boolean isInAlphabet(final byte octet) {
240234
*/
241235
private void validateTrailingCharacter() {
242236
if (isStrictDecoding()) {
243-
throw new IllegalArgumentException("Strict decoding: Last encoded character is a valid base 16 alphabet character but not a possible encoding. " +
237+
throw new IllegalArgumentException("Strict decoding: Last encoded character is a valid Base 16 alphabet character but not a possible encoding. " +
244238
"Decoding requires at least two characters to create one byte.");
245239
}
246240
}

src/main/java/org/apache/commons/codec/binary/Base16InputStream.java

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,63 +20,98 @@
2020
import java.io.InputStream;
2121

2222
import org.apache.commons.codec.CodecPolicy;
23+
import org.apache.commons.codec.binary.BaseNCodecInputStream.AbstracBuilder; // NOPMD: Required by ECJ (Eclipse)
2324

2425
/**
2526
* Provides Base16 decoding in a streaming fashion (unlimited size).
2627
* <p>
27-
* The default behavior of the Base16InputStream is to DECODE, whereas the default behavior of the
28-
* {@link Base16OutputStream} is to ENCODE, but this behavior can be overridden by using a different constructor.
28+
* The default behavior of the Base16InputStream is to DECODE, whereas the default behavior of the {@link Base16OutputStream} is to ENCODE, but this behavior
29+
* can be overridden by using a different constructor.
2930
* </p>
3031
*
3132
* @see Base16
3233
* @since 1.15
3334
*/
34-
public class Base16InputStream extends BaseNCodecInputStream<Base16> {
35+
public class Base16InputStream extends BaseNCodecInputStream<Base16, Base16InputStream, Base16InputStream.Builder> {
36+
37+
/**
38+
* Builds instances of Base16InputStream.
39+
*/
40+
public static class Builder extends AbstracBuilder<Base16InputStream, Base16, Builder> {
41+
42+
/**
43+
* Constructs a new instance.
44+
*/
45+
public Builder() {
46+
// empty
47+
}
48+
49+
@Override
50+
public Base16InputStream get() {
51+
return new Base16InputStream(this);
52+
}
53+
54+
@Override
55+
protected Base16 newBaseNCodec() {
56+
return new Base16();
57+
}
58+
}
59+
60+
/**
61+
* Constructs a new Builder.
62+
*
63+
* @return a new Builder.
64+
*/
65+
public static Builder builder() {
66+
return new Builder();
67+
}
68+
69+
private Base16InputStream(final Builder builder) {
70+
super(builder);
71+
}
3572

3673
/**
3774
* Constructs a Base16InputStream such that all data read is Base16-decoded from the original provided InputStream.
3875
*
3976
* @param inputStream InputStream to wrap.
4077
*/
4178
public Base16InputStream(final InputStream inputStream) {
42-
this(inputStream, false);
79+
super(builder().setInputStream(inputStream));
4380
}
4481

4582
/**
46-
* Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original
47-
* provided InputStream.
83+
* Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original provided InputStream.
4884
*
4985
* @param inputStream InputStream to wrap.
50-
* @param doEncode true if we should encode all data read from us, false if we should decode.
86+
* @param encode true if we should encode all data read from us, false if we should decode.
5187
*/
52-
public Base16InputStream(final InputStream inputStream, final boolean doEncode) {
53-
this(inputStream, doEncode, false);
88+
@Deprecated
89+
public Base16InputStream(final InputStream inputStream, final boolean encode) {
90+
super(builder().setInputStream(inputStream).setEncode(encode));
5491
}
5592

5693
/**
57-
* Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original
58-
* provided InputStream.
94+
* Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original provided InputStream.
5995
*
6096
* @param inputStream InputStream to wrap.
61-
* @param doEncode true if we should encode all data read from us, false if we should decode.
62-
* @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
97+
* @param encode true if we should encode all data read from us, false if we should decode.
98+
* @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
6399
*/
64-
public Base16InputStream(final InputStream inputStream, final boolean doEncode,
65-
final boolean lowerCase) {
66-
this(inputStream, doEncode, lowerCase, CodecPolicy.LENIENT);
100+
@Deprecated
101+
public Base16InputStream(final InputStream inputStream, final boolean encode, final boolean lowerCase) {
102+
super(builder().setInputStream(inputStream).setEncode(encode).setBaseNCodec(new Base16(lowerCase)));
67103
}
68104

69105
/**
70-
* Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original
71-
* provided InputStream.
106+
* Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original provided InputStream.
72107
*
73-
* @param inputStream InputStream to wrap.
74-
* @param doEncode true if we should encode all data read from us, false if we should decode.
75-
* @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
108+
* @param inputStream InputStream to wrap.
109+
* @param encode true if we should encode all data read from us, false if we should decode.
110+
* @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
76111
* @param decodingPolicy Decoding policy.
77112
*/
78-
public Base16InputStream(final InputStream inputStream, final boolean doEncode,
79-
final boolean lowerCase, final CodecPolicy decodingPolicy) {
80-
super(inputStream, new Base16(lowerCase, decodingPolicy), doEncode);
113+
@Deprecated
114+
public Base16InputStream(final InputStream inputStream, final boolean encode, final boolean lowerCase, final CodecPolicy decodingPolicy) {
115+
super(builder().setInputStream(inputStream).setEncode(encode).setBaseNCodec(new Base16(lowerCase, decodingPolicy)));
81116
}
82117
}

0 commit comments

Comments
 (0)