0
# IO Utilities
1
2
This document covers encoding, decoding, and serialization utilities in JJWT API for Base64/Base64URL operations and custom JSON processing.
3
4
## Encoding and Decoding
5
6
JJWT provides standard encoders and decoders for Base64 and Base64URL operations, which are essential for JWT processing.
7
8
### Encoders
9
10
```java { .api }
11
public final class Encoders {
12
public static final Encoder<byte[], String> BASE64;
13
public static final Encoder<byte[], String> BASE64URL;
14
}
15
```
16
17
### Decoders
18
19
```java { .api }
20
public final class Decoders {
21
public static final Decoder<CharSequence, byte[]> BASE64;
22
public static final Decoder<CharSequence, byte[]> BASE64URL;
23
}
24
```
25
26
### Core Encoder/Decoder Interfaces
27
28
```java { .api }
29
public interface Encoder<T, R> {
30
R encode(T t) throws EncodingException;
31
}
32
33
public interface Decoder<T, R> {
34
R decode(T t) throws DecodingException;
35
}
36
```
37
38
### Usage Examples
39
40
```java
41
import io.jsonwebtoken.io.Encoders;
42
import io.jsonwebtoken.io.Decoders;
43
44
// Encode bytes to Base64URL string (JWT standard)
45
byte[] data = "Hello, World!".getBytes(StandardCharsets.UTF_8);
46
String base64url = Encoders.BASE64URL.encode(data);
47
System.out.println(base64url); // SGVsbG8sIFdvcmxkIQ
48
49
// Decode Base64URL string back to bytes
50
byte[] decoded = Decoders.BASE64URL.decode(base64url);
51
String original = new String(decoded, StandardCharsets.UTF_8);
52
System.out.println(original); // Hello, World!
53
54
// Standard Base64 encoding (with padding)
55
String base64 = Encoders.BASE64.encode(data);
56
System.out.println(base64); // SGVsbG8sIFdvcmxkIQ==
57
58
// Decode standard Base64
59
byte[] decodedBase64 = Decoders.BASE64.decode(base64);
60
```
61
62
## Serialization and Deserialization
63
64
JJWT provides interfaces for custom JSON serialization and deserialization, allowing integration with different JSON libraries.
65
66
### Serializer Interface
67
68
```java { .api }
69
public interface Serializer<T> {
70
byte[] serialize(T t) throws SerializationException;
71
}
72
```
73
74
### Deserializer Interface
75
76
```java { .api }
77
public interface Deserializer<T> {
78
T deserialize(byte[] bytes) throws DeserializationException;
79
}
80
```
81
82
### Abstract Base Classes
83
84
```java { .api }
85
public abstract class AbstractSerializer<T> implements Serializer<T> {
86
// Base implementation with common functionality
87
}
88
89
public abstract class AbstractDeserializer<T> implements Deserializer<T> {
90
// Base implementation with common functionality
91
}
92
```
93
94
### Custom Serialization Examples
95
96
```java
97
import io.jsonwebtoken.io.Serializer;
98
import io.jsonwebtoken.io.Deserializer;
99
import com.fasterxml.jackson.databind.ObjectMapper;
100
101
// Custom Jackson serializer
102
public class JacksonSerializer<T> implements Serializer<T> {
103
private final ObjectMapper objectMapper = new ObjectMapper();
104
105
@Override
106
public byte[] serialize(T object) throws SerializationException {
107
try {
108
return objectMapper.writeValueAsBytes(object);
109
} catch (Exception e) {
110
throw new SerializationException("Unable to serialize object", e);
111
}
112
}
113
}
114
115
// Custom Jackson deserializer
116
public class JacksonDeserializer<T> implements Deserializer<T> {
117
private final ObjectMapper objectMapper = new ObjectMapper();
118
private final Class<T> targetClass;
119
120
public JacksonDeserializer(Class<T> targetClass) {
121
this.targetClass = targetClass;
122
}
123
124
@Override
125
public T deserialize(byte[] bytes) throws DeserializationException {
126
try {
127
return objectMapper.readValue(bytes, targetClass);
128
} catch (Exception e) {
129
throw new DeserializationException("Unable to deserialize bytes", e);
130
}
131
}
132
}
133
134
// Usage in JWT operations
135
Serializer<Map<String, Object>> serializer = new JacksonSerializer<>();
136
Deserializer<Map<String, Object>> deserializer = new JacksonDeserializer<>(Map.class);
137
138
// Use custom serializers in JWT parsing
139
JwtParser parser = Jwts.parser()
140
.deserializer(deserializer)
141
.verifyWith(key)
142
.build();
143
```
144
145
## Compression
146
147
JJWT supports payload compression to reduce JWT size using standard compression algorithms.
148
149
### Compression Algorithm Interface
150
151
```java { .api }
152
public interface CompressionAlgorithm extends Identifiable {
153
String getId();
154
155
// Compression operations
156
byte[] compress(byte[] payload) throws CompressionException;
157
byte[] decompress(byte[] compressed) throws CompressionException;
158
}
159
```
160
161
### Standard Compression Algorithms
162
163
Available through `Jwts.ZIP`:
164
165
```java { .api }
166
public static final class ZIP {
167
public static final CompressionAlgorithm DEF; // DEFLATE
168
public static final CompressionAlgorithm GZIP; // GZIP
169
}
170
```
171
172
### Compression Usage Examples
173
174
```java
175
import io.jsonwebtoken.Jwts;
176
import io.jsonwebtoken.CompressionAlgorithm;
177
178
// Create JWT with DEFLATE compression
179
CompressionAlgorithm deflate = Jwts.ZIP.DEF;
180
181
String compressedJwt = Jwts.builder()
182
.subject("user123")
183
.claim("largeData", Arrays.asList(/* large data object */))
184
.compressWith(deflate)
185
.signWith(key)
186
.compact();
187
188
// Decompression is automatic during parsing
189
JwtParser parser = Jwts.parser()
190
.verifyWith(key)
191
.build();
192
193
Jws<Claims> jws = parser.parseSignedClaims(compressedJwt);
194
Claims claims = jws.getPayload();
195
196
// Use GZIP compression
197
String gzipJwt = Jwts.builder()
198
.claim("data", largeDataSet)
199
.compressWith(Jwts.ZIP.GZIP)
200
.signWith(key)
201
.compact();
202
```
203
204
## Advanced Base64 Support
205
206
### Base64 Support Utilities
207
208
```java { .api }
209
public final class Base64Support {
210
// Utility methods for Base64 operations
211
public static boolean isBase64(CharSequence s);
212
public static boolean isBase64Url(CharSequence s);
213
}
214
```
215
216
### Custom Base64 Implementations
217
218
```java { .api }
219
// Base64 Encoder Interface
220
public interface Base64Encoder extends Encoder<byte[], String> {
221
// Standard Base64 encoding
222
}
223
224
// Base64URL Encoder Interface
225
public interface Base64UrlEncoder extends Encoder<byte[], String> {
226
// Base64URL encoding (RFC 4648 Section 5)
227
}
228
229
// Base64 Decoder Interface
230
public interface Base64Decoder extends Decoder<CharSequence, byte[]> {
231
// Standard Base64 decoding
232
}
233
234
// Base64URL Decoder Interface
235
public interface Base64UrlDecoder extends Decoder<CharSequence, byte[]> {
236
// Base64URL decoding (RFC 4648 Section 5)
237
}
238
```
239
240
### Exception-Handling Wrappers
241
242
```java { .api }
243
public class ExceptionPropagatingEncoder<T, R> implements Encoder<T, R> {
244
// Wraps encoders to propagate specific exceptions
245
}
246
247
public class ExceptionPropagatingDecoder<T, R> implements Decoder<T, R> {
248
// Wraps decoders to propagate specific exceptions
249
}
250
```
251
252
## Parser and JSON Processing
253
254
### Parser Interface
255
256
```java { .api }
257
public interface Parser<T> {
258
T parse(CharSequence input) throws IOException;
259
}
260
```
261
262
### Parser Builder
263
264
```java { .api }
265
public interface ParserBuilder<T> extends Builder<Parser<T>> {
266
ParserBuilder<T> deserializer(Deserializer<T> deserializer);
267
Parser<T> build();
268
}
269
```
270
271
### JSON Processing Integration
272
273
```java
274
import io.jsonwebtoken.io.Parser;
275
import io.jsonwebtoken.io.ParserBuilder;
276
277
// Custom JSON parser integration
278
Parser<Map<String, Object>> jsonParser = new ParserBuilder<Map<String, Object>>()
279
.deserializer(new JacksonDeserializer<>(Map.class))
280
.build();
281
282
// Parse JSON string
283
String jsonInput = "{\"sub\":\"user123\",\"exp\":1234567890}";
284
Map<String, Object> parsed = jsonParser.parse(jsonInput);
285
```
286
287
## Exception Hierarchy
288
289
### Base IO Exception
290
291
```java { .api }
292
public class IOException extends JwtException {
293
// Base exception for all IO operations
294
}
295
```
296
297
### Specific IO Exceptions
298
299
```java { .api }
300
public class CodecException extends IOException {
301
// General codec operation failures
302
}
303
304
public class EncodingException extends CodecException {
305
// Encoding operation failures
306
}
307
308
public class DecodingException extends CodecException {
309
// Decoding operation failures
310
}
311
312
public class SerializationException extends IOException {
313
// Serialization operation failures
314
}
315
316
public class DeserializationException extends IOException {
317
// Deserialization operation failures
318
}
319
320
public class SerialException extends IOException {
321
// Serial operation failures
322
}
323
```
324
325
### Exception Handling Examples
326
327
```java
328
import io.jsonwebtoken.io.*;
329
330
try {
331
// Encode potentially problematic data
332
String encoded = Encoders.BASE64URL.encode(problematicData);
333
} catch (EncodingException e) {
334
System.err.println("Encoding failed: " + e.getMessage());
335
// Handle encoding failure
336
}
337
338
try {
339
// Decode potentially malformed input
340
byte[] decoded = Decoders.BASE64URL.decode(malformedInput);
341
} catch (DecodingException e) {
342
System.err.println("Decoding failed: " + e.getMessage());
343
// Handle decoding failure
344
}
345
346
try {
347
// Serialize complex object
348
byte[] serialized = customSerializer.serialize(complexObject);
349
} catch (SerializationException e) {
350
System.err.println("Serialization failed: " + e.getMessage());
351
// Handle serialization failure
352
}
353
```
354
355
## Integration Examples
356
357
### Custom JSON Library Integration
358
359
```java
360
import io.jsonwebtoken.Jwts;
361
import io.jsonwebtoken.JwtBuilder;
362
import io.jsonwebtoken.JwtParser;
363
364
// Integrate with Gson
365
public class GsonIntegration {
366
private final Gson gson = new Gson();
367
368
public Serializer<Map<String, Object>> createSerializer() {
369
return new Serializer<Map<String, Object>>() {
370
@Override
371
public byte[] serialize(Map<String, Object> object) throws SerializationException {
372
try {
373
return gson.toJson(object).getBytes(StandardCharsets.UTF_8);
374
} catch (Exception e) {
375
throw new SerializationException("Gson serialization failed", e);
376
}
377
}
378
};
379
}
380
381
public Deserializer<Map<String, Object>> createDeserializer() {
382
return new Deserializer<Map<String, Object>>() {
383
@Override
384
public Map<String, Object> deserialize(byte[] bytes) throws DeserializationException {
385
try {
386
String json = new String(bytes, StandardCharsets.UTF_8);
387
Type type = new TypeToken<Map<String, Object>>(){}.getType();
388
return gson.fromJson(json, type);
389
} catch (Exception e) {
390
throw new DeserializationException("Gson deserialization failed", e);
391
}
392
}
393
};
394
}
395
}
396
397
// Use custom integration
398
GsonIntegration gsonIntegration = new GsonIntegration();
399
400
JwtParser parser = Jwts.parser()
401
.deserializer(gsonIntegration.createDeserializer())
402
.verifyWith(key)
403
.build();
404
```
405
406
### Performance Optimizations
407
408
```java
409
// Reuse encoder/decoder instances for better performance
410
public class JwtUtils {
411
private static final Encoder<byte[], String> ENCODER = Encoders.BASE64URL;
412
private static final Decoder<CharSequence, byte[]> DECODER = Decoders.BASE64URL;
413
414
public static String encodePayload(byte[] payload) {
415
return ENCODER.encode(payload);
416
}
417
418
public static byte[] decodePayload(String encoded) {
419
return DECODER.decode(encoded);
420
}
421
422
// Batch operations for better performance
423
public static List<String> encodeMultiple(List<byte[]> payloads) {
424
return payloads.stream()
425
.map(ENCODER::encode)
426
.collect(Collectors.toList());
427
}
428
}
429
```
430
431
### Testing Utilities
432
433
```java
434
import io.jsonwebtoken.io.*;
435
436
public class TestUtils {
437
// Test data generation
438
public static byte[] generateTestData(int size) {
439
byte[] data = new byte[size];
440
new Random().nextBytes(data);
441
return data;
442
}
443
444
// Round-trip testing
445
public static boolean testEncodeDecode(byte[] original) {
446
try {
447
String encoded = Encoders.BASE64URL.encode(original);
448
byte[] decoded = Decoders.BASE64URL.decode(encoded);
449
return Arrays.equals(original, decoded);
450
} catch (Exception e) {
451
return false;
452
}
453
}
454
455
// Performance testing
456
public static long measureEncodePerformance(byte[] data, int iterations) {
457
long start = System.nanoTime();
458
for (int i = 0; i < iterations; i++) {
459
Encoders.BASE64URL.encode(data);
460
}
461
return System.nanoTime() - start;
462
}
463
}