Interface Swapper<T>

Type Parameters:
T - The type of object this swapper handles
All Superinterfaces:
BiFunction<BeanConverter,T,Object>
Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

Functional interface for pre-processing and transforming objects before conversion.

Swappers provide object transformation logic that runs before stringification or listification. They enable unwrapping, preprocessing, and value extraction from wrapper objects, containers, and lazy evaluation constructs.

Key Features:
  • Pre-processing: Transform objects before string/list conversion
  • Wrapper unwrapping: Extract values from Optional, Supplier, Future, etc.
  • Lazy evaluation: Trigger computation of lazy values
  • Type transformation: Convert between related types for better testing
Common Use Cases:
  • Optional unwrapping: Extract values from Optional containers
  • Supplier evaluation: Call get() on Supplier objects
  • Future resolution: Extract completed values from Future objects
  • Proxy unwrapping: Extract underlying objects from proxies
  • Value extraction: Pull relevant data from complex wrapper objects
Usage Examples:

// Future value extraction Swapper<CompletableFuture> futureSwapper = (conv, future) -> { try { return future.isDone() ? future.get() : "<pending>"; } catch (Exception e) { return "<error: " + e.getMessage() + ">"; } }; // Custom wrapper unwrapping Swapper<LazyValue> lazySwapper = (conv, lazy) -> lazy.isEvaluated() ? lazy.getValue() : "<unevaluated>"; // Entity to DTO conversion Swapper<UserEntity> entitySwapper = (conv, entity) -> new UserDTO(entity.getId(), entity.getName(), entity.getEmail());

Registration:

var converter = BasicBeanConverter.builder() .defaultSettings() .addSwapper(CompletableFuture.class, futureSwapper) .addSwapper(LazyValue.class, lazySwapper) .addSwapper(UserEntity.class, entitySwapper) .build();

Execution Flow:

Swappers are applied early in the conversion process:

  1. Object received for conversion
  2. Swapper applied if one is registered for the object's type
  3. Result processed through normal stringification/listification
  4. Chain continues recursively for nested objects
Best Practices:
  • Handle exceptions gracefully, returning error indicators rather than throwing
  • Preserve semantics - the swapped object should represent the same logical value
  • Consider performance - swappers are called frequently during conversion
  • Return meaningful values for null or invalid states
  • Avoid recursion - ensure swappers don't create circular transformations that could lead to StackOverflowError. The framework does not detect recursion, so developers must ensure swapped objects don't trigger the same or related swappers in an endless cycle
See Also: