0
# Serialization
1
2
Object serialization utilities with support for various formats, compression, encryption, and Jackson integration for secure and efficient data persistence and transmission.
3
4
## SerializationUtils
5
6
Core utility class providing comprehensive serialization operations with support for encryption and encoding.
7
8
```java { .api }
9
@UtilityClass
10
public class SerializationUtils {
11
12
// Basic serialization operations
13
public static byte[] serialize(Serializable object);
14
public static void serialize(Serializable object, OutputStream outputStream);
15
16
// Basic deserialization operations
17
public static <T> T deserialize(byte[] inBytes, Class<T> clazz);
18
public static <T> T deserialize(InputStream inputStream, Class<T> clazz);
19
20
// Encrypted serialization operations
21
public static byte[] serializeAndEncodeObject(EncodableCipher cipher,
22
Serializable object,
23
Object[] parameters);
24
25
public static byte[] serializeAndEncodeObject(EncodableCipher cipher,
26
Serializable object);
27
28
// Encrypted deserialization operations
29
public static <T extends Serializable> T decodeAndDeserializeObject(
30
byte[] object,
31
Class<T> type,
32
DecodableCipher cipher,
33
Object[] parameters
34
);
35
36
public static <T extends Serializable> T decodeAndDeserializeObject(
37
byte[] object,
38
Class<T> type,
39
DecodableCipher cipher
40
);
41
42
// Validation and safety operations
43
public static <T extends Serializable> T deserializeAndCheckObject(
44
byte[] object,
45
Class<T> type
46
);
47
}
48
```
49
50
### Usage Examples
51
52
**Basic serialization operations:**
53
```java
54
@Service
55
public class CacheService {
56
57
public void storeUserSession(String sessionId, UserSession session) {
58
try {
59
// Serialize user session
60
byte[] serialized = SerializationUtils.serialize(session);
61
62
// Store in cache/database
63
cacheManager.put(sessionId, serialized);
64
65
} catch (Exception e) {
66
log.error("Failed to serialize user session", e);
67
throw new SerializationException("Session storage failed", e);
68
}
69
}
70
71
public Optional<UserSession> retrieveUserSession(String sessionId) {
72
try {
73
byte[] data = cacheManager.get(sessionId);
74
if (data != null) {
75
UserSession session = SerializationUtils.deserialize(data, UserSession.class);
76
return Optional.of(session);
77
}
78
return Optional.empty();
79
80
} catch (Exception e) {
81
log.error("Failed to deserialize user session", e);
82
return Optional.empty();
83
}
84
}
85
86
public void persistToFile(Serializable object, Path filePath) {
87
try (FileOutputStream fos = new FileOutputStream(filePath.toFile())) {
88
SerializationUtils.serialize(object, fos);
89
} catch (Exception e) {
90
log.error("Failed to persist object to file", e);
91
throw new SerializationException("File persistence failed", e);
92
}
93
}
94
95
public <T> Optional<T> loadFromFile(Path filePath, Class<T> type) {
96
try (FileInputStream fis = new FileInputStream(filePath.toFile())) {
97
T object = SerializationUtils.deserialize(fis, type);
98
return Optional.of(object);
99
} catch (Exception e) {
100
log.error("Failed to load object from file", e);
101
return Optional.empty();
102
}
103
}
104
}
105
```
106
107
**Encrypted serialization for sensitive data:**
108
```java
109
@Service
110
public class SecureDataService {
111
112
private final CipherExecutor<Serializable, byte[]> cipher;
113
114
public SecureDataService(CipherExecutor<Serializable, byte[]> cipher) {
115
this.cipher = cipher;
116
}
117
118
public void storeSecureData(String key, SensitiveData data) {
119
try {
120
// Serialize and encrypt in one operation
121
byte[] encrypted = SerializationUtils.serializeAndEncodeObject(cipher, data);
122
123
// Store encrypted data
124
secureStorage.store(key, encrypted);
125
126
log.info("Securely stored data for key: {}", key);
127
128
} catch (Exception e) {
129
log.error("Failed to store secure data", e);
130
throw new SecurityException("Secure storage failed", e);
131
}
132
}
133
134
public Optional<SensitiveData> retrieveSecureData(String key) {
135
try {
136
byte[] encrypted = secureStorage.retrieve(key);
137
if (encrypted != null) {
138
// Decrypt and deserialize in one operation
139
SensitiveData data = SerializationUtils.decodeAndDeserializeObject(
140
encrypted,
141
SensitiveData.class,
142
cipher
143
);
144
return Optional.of(data);
145
}
146
return Optional.empty();
147
148
} catch (Exception e) {
149
log.error("Failed to retrieve secure data", e);
150
return Optional.empty();
151
}
152
}
153
154
public void storeWithParameters(String key, ConfigurableData data, String[] params) {
155
try {
156
// Use cipher parameters for additional security context
157
Object[] cipherParams = Arrays.stream(params)
158
.map(String::getBytes)
159
.toArray();
160
161
byte[] encrypted = SerializationUtils.serializeAndEncodeObject(
162
cipher,
163
data,
164
cipherParams
165
);
166
167
secureStorage.store(key, encrypted);
168
169
} catch (Exception e) {
170
log.error("Failed to store configurable data", e);
171
throw new SecurityException("Parameterized storage failed", e);
172
}
173
}
174
}
175
```
176
177
**Safe deserialization with validation:**
178
```java
179
@Component
180
public class SafeDeserializationService {
181
182
private final Set<Class<?>> allowedClasses;
183
184
public SafeDeserializationService() {
185
// Whitelist of allowed classes for deserialization
186
this.allowedClasses = Set.of(
187
UserSession.class,
188
AuthenticationToken.class,
189
ServiceTicket.class,
190
CacheEntry.class
191
);
192
}
193
194
public <T extends Serializable> Optional<T> safeDeserialize(byte[] data, Class<T> type) {
195
// Validate class is allowed
196
if (!isAllowedClass(type)) {
197
log.warn("Attempted to deserialize disallowed class: {}", type.getName());
198
return Optional.empty();
199
}
200
201
try {
202
// Use safe deserialization with validation
203
T object = SerializationUtils.deserializeAndCheckObject(data, type);
204
205
// Additional validation
206
if (isValidObject(object)) {
207
return Optional.of(object);
208
} else {
209
log.warn("Deserialized object failed validation: {}", type.getName());
210
return Optional.empty();
211
}
212
213
} catch (Exception e) {
214
log.error("Safe deserialization failed for type: {}", type.getName(), e);
215
return Optional.empty();
216
}
217
}
218
219
private boolean isAllowedClass(Class<?> clazz) {
220
return allowedClasses.contains(clazz) ||
221
allowedClasses.stream().anyMatch(allowed -> allowed.isAssignableFrom(clazz));
222
}
223
224
private boolean isValidObject(Object object) {
225
// Implement business logic validation
226
if (object instanceof UserSession session) {
227
return session.getUserId() != null && session.getCreatedAt() != null;
228
}
229
230
if (object instanceof AuthenticationToken token) {
231
return token.getToken() != null && token.getExpiresAt() > System.currentTimeMillis();
232
}
233
234
return true; // Default validation
235
}
236
}
237
```
238
239
## Jackson Integration
240
241
### BaseJacksonSerializer
242
243
Abstract Jackson-based serializer providing customizable JSON serialization.
244
245
```java { .api }
246
public abstract class BaseJacksonSerializer<T> {
247
248
// Jackson ObjectMapper instance
249
protected final ObjectMapper objectMapper;
250
251
// Constructor
252
protected BaseJacksonSerializer(ObjectMapper objectMapper);
253
254
// Serialization methods
255
public String serialize(T object);
256
public byte[] serializeToBytes(T object);
257
public void serializeToStream(T object, OutputStream outputStream);
258
259
// Deserialization methods
260
public T deserialize(String json);
261
public T deserialize(byte[] data);
262
public T deserialize(InputStream inputStream);
263
264
// Abstract methods for subclasses
265
protected abstract Class<T> getObjectType();
266
protected abstract void configureObjectMapper(ObjectMapper mapper);
267
}
268
```
269
270
### JacksonObjectMapperFactory
271
272
Factory for creating and configuring Jackson ObjectMapper instances with CAS-specific settings.
273
274
```java { .api }
275
public class JacksonObjectMapperFactory {
276
277
// Factory methods
278
public static ObjectMapper builder();
279
public static ObjectMapper builder(boolean defaultTypingEnabled);
280
281
// Configuration methods
282
public static ObjectMapper configure(ObjectMapper mapper);
283
public static ObjectMapper configureForCas(ObjectMapper mapper);
284
285
// Specialized configurations
286
public static ObjectMapper createForTickets();
287
public static ObjectMapper createForServices();
288
public static ObjectMapper createForAuthentication();
289
290
// Feature configuration
291
public static ObjectMapper withFeature(ObjectMapper mapper,
292
SerializationFeature feature,
293
boolean enabled);
294
295
public static ObjectMapper withFeature(ObjectMapper mapper,
296
DeserializationFeature feature,
297
boolean enabled);
298
}
299
```
300
301
### Usage Examples
302
303
**Custom Jackson serializer implementation:**
304
```java
305
@Component
306
public class UserSessionSerializer extends BaseJacksonSerializer<UserSession> {
307
308
public UserSessionSerializer() {
309
super(JacksonObjectMapperFactory.builder());
310
}
311
312
@Override
313
protected Class<UserSession> getObjectType() {
314
return UserSession.class;
315
}
316
317
@Override
318
protected void configureObjectMapper(ObjectMapper mapper) {
319
// Custom configuration for user sessions
320
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
321
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
322
323
// Custom date format
324
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
325
326
// Include type information for polymorphic handling
327
mapper.activateDefaultTyping(
328
LaissezFaireSubTypeValidator.instance,
329
ObjectMapper.DefaultTyping.NON_FINAL
330
);
331
332
// Custom modules
333
mapper.registerModule(new JavaTimeModule());
334
mapper.registerModule(new CasJacksonModule());
335
}
336
}
337
```
338
339
**Factory usage for different contexts:**
340
```java
341
@Configuration
342
public class SerializationConfiguration {
343
344
@Bean("ticketObjectMapper")
345
public ObjectMapper ticketObjectMapper() {
346
ObjectMapper mapper = JacksonObjectMapperFactory.createForTickets();
347
348
// Additional ticket-specific configuration
349
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
350
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
351
352
return mapper;
353
}
354
355
@Bean("serviceObjectMapper")
356
public ObjectMapper serviceObjectMapper() {
357
ObjectMapper mapper = JacksonObjectMapperFactory.createForServices();
358
359
// Service registry specific settings
360
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
361
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
362
363
return mapper;
364
}
365
366
@Bean("authenticationObjectMapper")
367
public ObjectMapper authenticationObjectMapper() {
368
ObjectMapper mapper = JacksonObjectMapperFactory.createForAuthentication();
369
370
// Security-focused configuration
371
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
372
mapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true);
373
374
return mapper;
375
}
376
}
377
```
378
379
## DefaultComponentSerializationPlan
380
381
Default serialization plan for component-based serialization strategies.
382
383
```java { .api }
384
public class DefaultComponentSerializationPlan implements ComponentSerializationPlan {
385
386
// Serialization strategy configuration
387
private final Map<Class<?>, SerializationStrategy> strategies;
388
389
// Constructor
390
public DefaultComponentSerializationPlan();
391
public DefaultComponentSerializationPlan(Map<Class<?>, SerializationStrategy> strategies);
392
393
// Plan execution
394
@Override
395
public byte[] serialize(Object object);
396
397
@Override
398
public <T> T deserialize(byte[] data, Class<T> type);
399
400
// Strategy management
401
public void registerStrategy(Class<?> type, SerializationStrategy strategy);
402
public void removeStrategy(Class<?> type);
403
public SerializationStrategy getStrategy(Class<?> type);
404
}
405
```
406
407
### Usage Examples
408
409
**Component serialization plan:**
410
```java
411
@Configuration
412
public class SerializationPlanConfiguration {
413
414
@Bean
415
public ComponentSerializationPlan casSerializationPlan() {
416
Map<Class<?>, SerializationStrategy> strategies = new HashMap<>();
417
418
// Different strategies for different types
419
strategies.put(UserSession.class, new JacksonSerializationStrategy());
420
strategies.put(ServiceTicket.class, new CompactBinaryStrategy());
421
strategies.put(AuthenticationToken.class, new EncryptedJsonStrategy());
422
strategies.put(CacheEntry.class, new CompressedSerializationStrategy());
423
424
DefaultComponentSerializationPlan plan = new DefaultComponentSerializationPlan(strategies);
425
426
// Register additional strategies
427
plan.registerStrategy(RegisteredService.class, new ServiceJsonStrategy());
428
429
return plan;
430
}
431
}
432
433
@Service
434
public class ComponentSerializationService {
435
436
private final ComponentSerializationPlan serializationPlan;
437
438
public byte[] serializeComponent(Object component) {
439
return serializationPlan.serialize(component);
440
}
441
442
public <T> T deserializeComponent(byte[] data, Class<T> type) {
443
return serializationPlan.deserialize(data, type);
444
}
445
}
446
```
447
448
## JacksonInjectableValueSupplier
449
450
Injectable value supplier for providing runtime values during Jackson deserialization.
451
452
```java { .api }
453
public class JacksonInjectableValueSupplier extends InjectableValues {
454
455
// Value providers
456
private final Map<String, Supplier<Object>> valueSuppliers;
457
private final ApplicationContext applicationContext;
458
459
// Constructor
460
public JacksonInjectableValueSupplier(ApplicationContext applicationContext);
461
462
// Value injection
463
@Override
464
public Object findInjectableValue(Object valueId,
465
DeserializationContext ctxt,
466
BeanProperty forProperty,
467
Object beanInstance);
468
469
// Supplier registration
470
public void registerSupplier(String valueId, Supplier<Object> supplier);
471
public void registerBean(String valueId, Class<?> beanType);
472
public void registerConstant(String valueId, Object value);
473
}
474
```
475
476
### Usage Examples
477
478
**Injectable value configuration:**
479
```java
480
@Configuration
481
public class JacksonInjectableConfiguration {
482
483
@Bean
484
public JacksonInjectableValueSupplier injectableValueSupplier(ApplicationContext context) {
485
JacksonInjectableValueSupplier supplier = new JacksonInjectableValueSupplier(context);
486
487
// Register runtime suppliers
488
supplier.registerSupplier("currentTime", System::currentTimeMillis);
489
supplier.registerSupplier("serverId", () -> getServerId());
490
supplier.registerSupplier("environment", () -> getEnvironment());
491
492
// Register Spring beans for injection
493
supplier.registerBean("userService", UserService.class);
494
supplier.registerBean("cacheManager", CacheManager.class);
495
496
// Register constants
497
supplier.registerConstant("version", "7.2.4");
498
supplier.registerConstant("deployment", "production");
499
500
return supplier;
501
}
502
503
@Bean
504
public ObjectMapper injectableObjectMapper(JacksonInjectableValueSupplier supplier) {
505
ObjectMapper mapper = JacksonObjectMapperFactory.builder();
506
mapper.setInjectableValues(supplier);
507
return mapper;
508
}
509
}
510
511
// Usage in domain objects
512
public class AuditableEntity {
513
514
@JsonProperty
515
private String id;
516
517
@JacksonInject("currentTime")
518
private Long createdAt;
519
520
@JacksonInject("serverId")
521
private String serverId;
522
523
@JacksonInject("userService")
524
private transient UserService userService;
525
526
// getters/setters
527
}
528
```
529
530
## PatternJsonDeserializer
531
532
Pattern-based JSON deserializer for handling regular expressions and pattern objects.
533
534
```java { .api }
535
public class PatternJsonDeserializer extends JsonDeserializer<Pattern> {
536
537
@Override
538
public Pattern deserialize(JsonParser parser,
539
DeserializationContext context) throws IOException;
540
541
// Pattern compilation options
542
public Pattern deserializeWithFlags(JsonParser parser,
543
DeserializationContext context,
544
int flags) throws IOException;
545
}
546
```
547
548
### Complete Integration Example
549
550
```java
551
@Service
552
@Slf4j
553
public class ComprehensiveSerializationService {
554
555
private final ObjectMapper jacksonMapper;
556
private final CipherExecutor<Serializable, byte[]> cipher;
557
private final ComponentSerializationPlan serializationPlan;
558
559
public ComprehensiveSerializationService(
560
@Qualifier("casObjectMapper") ObjectMapper jacksonMapper,
561
CipherExecutor<Serializable, byte[]> cipher,
562
ComponentSerializationPlan serializationPlan) {
563
564
this.jacksonMapper = jacksonMapper;
565
this.cipher = cipher;
566
this.serializationPlan = serializationPlan;
567
}
568
569
// JSON serialization for web APIs
570
public String toJson(Object object) {
571
try {
572
return jacksonMapper.writeValueAsString(object);
573
} catch (JsonProcessingException e) {
574
log.error("JSON serialization failed", e);
575
throw new SerializationException("JSON conversion failed", e);
576
}
577
}
578
579
public <T> T fromJson(String json, Class<T> type) {
580
try {
581
return jacksonMapper.readValue(json, type);
582
} catch (JsonProcessingException e) {
583
log.error("JSON deserialization failed", e);
584
throw new SerializationException("JSON parsing failed", e);
585
}
586
}
587
588
// Binary serialization for caching
589
public byte[] toBinary(Serializable object) {
590
return SerializationUtils.serialize(object);
591
}
592
593
public <T> T fromBinary(byte[] data, Class<T> type) {
594
return SerializationUtils.deserialize(data, type);
595
}
596
597
// Encrypted serialization for sensitive data
598
public byte[] toEncryptedBinary(Serializable object) {
599
return SerializationUtils.serializeAndEncodeObject(cipher, object);
600
}
601
602
public <T extends Serializable> T fromEncryptedBinary(byte[] data, Class<T> type) {
603
return SerializationUtils.decodeAndDeserializeObject(data, type, cipher);
604
}
605
606
// Component-based serialization
607
public byte[] serializeComponent(Object component) {
608
return serializationPlan.serialize(component);
609
}
610
611
public <T> T deserializeComponent(byte[] data, Class<T> type) {
612
return serializationPlan.deserialize(data, type);
613
}
614
615
// Hybrid operations combining multiple strategies
616
public StorageEntry createStorageEntry(String key, Object data, StorageOptions options) {
617
byte[] serializedData;
618
619
if (options.isEncrypted()) {
620
if (data instanceof Serializable serializable) {
621
serializedData = toEncryptedBinary(serializable);
622
} else {
623
// Convert to JSON first, then encrypt
624
String json = toJson(data);
625
serializedData = toEncryptedBinary(json);
626
}
627
} else if (options.useComponentSerialization()) {
628
serializedData = serializeComponent(data);
629
} else if (options.isJsonFormat()) {
630
String json = toJson(data);
631
serializedData = json.getBytes(StandardCharsets.UTF_8);
632
} else {
633
if (data instanceof Serializable serializable) {
634
serializedData = toBinary(serializable);
635
} else {
636
throw new IllegalArgumentException("Object must be Serializable for binary format");
637
}
638
}
639
640
return new StorageEntry(key, serializedData, options);
641
}
642
643
public <T> T retrieveFromStorageEntry(StorageEntry entry, Class<T> type) {
644
StorageOptions options = entry.getOptions();
645
byte[] data = entry.getData();
646
647
if (options.isEncrypted()) {
648
if (String.class.equals(type)) {
649
String decrypted = fromEncryptedBinary(data, String.class);
650
return jacksonMapper.convertValue(decrypted, type);
651
} else {
652
return fromEncryptedBinary(data, type.asSubclass(Serializable.class));
653
}
654
} else if (options.useComponentSerialization()) {
655
return deserializeComponent(data, type);
656
} else if (options.isJsonFormat()) {
657
String json = new String(data, StandardCharsets.UTF_8);
658
return fromJson(json, type);
659
} else {
660
return fromBinary(data, type);
661
}
662
}
663
}
664
```
665
666
This serialization library provides comprehensive support for various serialization needs in CAS applications, from simple JSON conversion to encrypted binary storage with proper security and performance considerations.