Package org.bct.api

Class BasicBeanConverter

java.lang.Object
org.bct.api.BasicBeanConverter
All Implemented Interfaces:
BeanConverter

public class BasicBeanConverter extends Object implements BeanConverter
Default implementation of BeanConverter for Bean-Centric Test (BCT) object conversion.

This class provides a comprehensive, extensible framework for converting Java objects to strings and lists, with sophisticated property access capabilities. It's the core engine behind BCT testing assertions, handling complex object introspection and value extraction with high performance through intelligent caching and optimized lookup strategies.

Key Features:
  • Extensible Type Handlers: Pluggable stringifiers, listifiers, and swappers for custom types
  • Performance Optimization: ConcurrentHashMap caching for type-to-handler mappings
  • Comprehensive Defaults: Built-in support for all common Java types and structures
  • Configurable Settings: Customizable formatting, delimiters, and display options
  • Thread Safety: Fully thread-safe implementation suitable for concurrent testing
Architecture Overview:

The converter uses four types of pluggable handlers:

Stringifiers:
Convert objects to string representations with custom formatting rules
Listifiers:
Convert collection-like objects to List<Object> for uniform iteration
Swappers:
Pre-process objects before conversion (unwrap Optional, call Supplier, etc.)
PropertyExtractors:
Define custom property access strategies for nested field navigation (e.g., "user.address.city")

PropertyExtractors use a chain-of-responsibility pattern, where each extractor in the chain is tried until one can handle the property access. The framework includes built-in extractors for:

  • JavaBean properties: Standard getter methods and public fields
  • Collection/Array access: Numeric indices and size/length properties
  • Map access: Key-based property retrieval and size property
Default Type Support:

Out-of-the-box stringification support includes:

  • Collections: List, Set, Queue → "[item1,item2,item3]" format
  • Maps: Map, Properties → "{key1=value1,key2=value2}" format
  • Map Entries: Map.Entry → "key=value" format
  • Arrays: All array types → "[element1,element2]" format
  • Dates: Date, Calendar → ISO-8601 format
  • Files/Streams: File, InputStream, Reader → content as hex or text
  • Reflection: Class, Method, Constructor → human-readable signatures
  • Enums: Enum values → name() format

Default listification support includes:

  • Collection types: List, Set, Queue, and all subtypes
  • Iterable objects: Any Iterable implementation
  • Iterators: Iterator and Enumeration (consumed to list)
  • Streams: Stream objects (terminated to list)
  • Optional: Empty list or single-element list
  • Maps: Converted to list of Map.Entry objects

Default swapping support includes:

  • Optional: Unwrapped to contained value or null
  • Supplier: Called to get supplied value
  • Future: Extracts completed result or returns "<pending>" for incomplete futures (via Swappers.futureSwapper())
Configuration Settings:

The converter supports extensive customization via settings:

nullValue
String representation for null values (default: "<null>")
selfValue
Special property name that returns the object itself (default: "<self>")
emptyValue
String representation for empty collections (default: "<empty>")
fieldSeparator
Delimiter between collection elements and map entries (default: ",")
collectionPrefix/Suffix
Brackets around collection content (default: "[" and "]")
mapPrefix/Suffix
Brackets around map content (default: "{" and "}")
mapEntrySeparator
Separator between map keys and values (default: "=")
calendarFormat
DateTimeFormatter for calendar objects (default: ISO_INSTANT)
classNameFormat
Format for class names: "simple", "canonical", or "full" (default: "simple")
Usage Examples:

Basic Usage with Defaults:

// Use default converter var converter = BasicBeanConverter.DEFAULT; var result = converter.stringify(myObject);

Custom Configuration:

// Build custom converter var converter = BasicBeanConverter.builder() .defaultSettings() .addSetting(SETTING_nullValue, "<null>") .addSetting(SETTING_fieldSeparator, " | ") .addStringifier(MyClass.class, (obj, conv) -> "MyClass[" + obj.getName() + "]") .addListifier(MyIterable.class, (obj, conv) -> obj.toList()) .addSwapper(MyWrapper.class, (obj, conv) -> obj.getWrapped()) .build();

Complex Property Access:

// Extract nested properties var name = converter.getEntry(user, "name"); var city = converter.getEntry(user, "address.city"); var firstOrder = converter.getEntry(user, "orders.0.id"); var orderCount = converter.getEntry(user, "orders.length");

Special Property Values:

// Use special property names var userObj = converter.getEntry(user, "<self>"); // Returns the user object itself var nullValue = converter.getEntry(user, "<null>"); // Returns null // Custom self value var customConverter = BasicBeanConverter.builder() .defaultSettings() .addSetting(SETTING_selfValue, "this") .build(); var selfRef = customConverter.getEntry(user, "this"); // Returns user object

Performance Characteristics:
  • Handler Lookup: O(1) average case via ConcurrentHashMap caching
  • Type Registration: Handlers checked in reverse registration order (last wins)
  • Inheritance Support: Handlers support class inheritance and interface implementation
  • Thread Safety: Full concurrency support with no locking overhead after initialization
  • Memory Efficiency: Minimal object allocation during normal operation
Extension Patterns:

Custom Type Stringification:

builder.addStringifier(LocalDateTime.class, (dt, conv) -> dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

Custom Collection Handling:

builder.addListifier(MyCustomCollection.class, (coll, conv) -> coll.stream().map(conv::swap).toList());

Custom Object Transformation:

builder.addSwapper(LazyValue.class, (lazy, conv) -> lazy.isEvaluated() ? lazy.getValue() : "<unevaluated>");

Integration with BCT:

This class is used internally by all BCT assertion methods in BctAssertions:

See Also:
  • Field Details

  • Constructor Details

  • Method Details

    • builder

      public static BasicBeanConverter.Builder builder()
      Creates a new builder for configuring a BasicBeanConverter instance.

      The builder allows registration of custom stringifiers, listifiers, and swappers, as well as configuration of various formatting settings before building the converter.

      Returns:
      A new Builder instance
    • stringify

      public String stringify(Object o)
      Description copied from interface: BeanConverter
      Converts an object to its string representation for testing purposes.
      Specified by:
      stringify in interface BeanConverter
      Parameters:
      o - The object to stringify
      Returns:
      The string representation of the object
    • swap

      public Object swap(Object o)
      Description copied from interface: BeanConverter
      Pre-processes objects before conversion operations.
      Specified by:
      swap in interface BeanConverter
      Parameters:
      o - The object to swap
      Returns:
      The swapped object, or the original object if no swapping is needed
    • listify

      public List<Object> listify(Object o)
      Description copied from interface: BeanConverter
      Converts a collection-like object to a standardized List<Object> format.
      Specified by:
      listify in interface BeanConverter
      Parameters:
      o - The object to convert to a list. Must not be null.
      Returns:
      A List containing the elements
    • canListify

      public boolean canListify(Object o)
      Description copied from interface: BeanConverter
      Determines if an object can be converted to a list.
      Specified by:
      canListify in interface BeanConverter
      Parameters:
      o - The object to test. May be null.
      Returns:
      True if the object can be listified, false if null or cannot be listified
    • getProperty

      public Object getProperty(Object object, String name)
      Description copied from interface: BeanConverter
      Accesses a named property or field from an object.
      Specified by:
      getProperty in interface BeanConverter
      Parameters:
      object - The object to access properties from
      name - The property/field name to access
      Returns:
      The property value
    • getNested

      public String getNested(Object o, NestedTokenizer.Token token)
      Description copied from interface: BeanConverter
      Extracts a nested property value using structured field access syntax.
      Specified by:
      getNested in interface BeanConverter
      Parameters:
      o - The object to extract nested properties from. May be null.
      token - The parsed token containing the property access structure. Must not be null.
      Returns:
      A formatted string representation of the extracted nested values
    • getSetting

      public <T> T getSetting(String key, T def)
      Description copied from interface: BeanConverter
      Retrieves a configuration setting value with a fallback default.
      Specified by:
      getSetting in interface BeanConverter
      Type Parameters:
      T - The type of the setting value
      Parameters:
      key - The setting key to retrieve
      def - The value to return if the setting is not found
      Returns:
      The setting value if found, otherwise the default value