Class BasicBeanConverter

java.lang.Object
org.apache.juneau.junit.bct.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

      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
    • 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
    • getNested

      public String getNested(Object o, org.apache.juneau.junit.bct.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
    • 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
    • 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
    • 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
    • size

      public int size(Object o)
      Description copied from interface: BeanConverter
      Computes the size of an object.

      This method determines the size of collection-like objects for test assertions. The size is computed based on registered Sizer implementations, with built-in support for collections, maps, arrays, and strings.

      Specified by:
      size in interface BeanConverter
      Parameters:
      o - The object to compute the size of. Must not be null.
      Returns:
      The size of the object.
    • 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)
      Builder class for configuring BasicBeanConverter instances.

      This builder provides a fluent interface for registering custom type handlers and configuring conversion settings. All registration methods support method chaining for convenient configuration.

      Handler Registration:
      • Stringifiers: Custom string conversion logic for specific types
      • Listifiers: Custom list conversion logic for collection-like types
      • Swappers: Pre-processing transformation logic for wrapper types
      Registration Order:

      Handlers are checked in reverse registration order (last registered wins). This allows overriding default handlers by registering more specific ones later.

      Inheritance Support:

      All handlers support class inheritance and interface implementation. When looking up a handler, the system checks:

      1. Exact class match
      2. Interface matches (in order of interface declaration)
      3. Superclass matches (walking up the inheritance hierarchy)
      Usage Example:

      var converter = BasicBeanConverter.builder() .defaultSettings() // Custom stringification for LocalDateTime .addStringifier(LocalDateTime.class, (dt, conv) -> dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) // Custom collection handling for custom type .addListifier(MyIterable.class, (iter, conv) -> iter.stream().collect(toList())) // Custom transformation for wrapper type .addSwapper(LazyValue.class, (lazy, conv) -> lazy.isComputed() ? lazy.get() : null) // Configure settings .addSetting(SETTING_nullValue, "<null>") .addSetting(SETTING_fieldSeparator, " | ") // Add default handlers for common types .defaultSettings() .build();

      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