This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 024909ddc New juneau-bct module
024909ddc is described below

commit 024909ddcd729e9e856b0b193827304d1de05587
Author: James Bognar <[email protected]>
AuthorDate: Fri Sep 12 15:28:59 2025 -0400

    New juneau-bct module
---
 build-and-push.sh                                  |  68 +++++++
 juneau-core/juneau-bct/.gitignore                  |   6 +
 {juneau-utest => juneau-core/juneau-bct}/pom.xml   |  85 +-------
 .../org/apache/juneau/junit/bct/AssertionArgs.java |   0
 .../juneau/junit/bct/BasicBeanConverter.java       |   0
 .../org/apache/juneau/junit/bct/BctAssertions.java |   0
 .../org/apache/juneau/junit/bct/BeanConverter.java |   0
 .../org/apache/juneau/junit/bct/Listifier.java     |   0
 .../org/apache/juneau/junit/bct/Listifiers.java    |   0
 .../apache/juneau/junit/bct/NestedTokenizer.java   |   0
 .../apache/juneau/junit/bct/PropertyExtractor.java |   0
 .../juneau/junit/bct/PropertyExtractors.java       |   0
 .../junit/bct/PropertyNotFoundException.java       |   0
 .../org/apache/juneau/junit/bct/Stringifier.java   |   0
 .../org/apache/juneau/junit/bct/Stringifiers.java  |   0
 .../java/org/apache/juneau/junit/bct/Swapper.java  |   0
 .../java/org/apache/juneau/junit/bct/Swappers.java |   0
 .../apache/juneau/junit/bct/ThrowingSupplier.java  |   0
 .../java/org/apache/juneau/junit/bct/Utils.java    |   0
 .../org/apache/juneau/junit/bct/package-info.java  | 221 +++++++++++++++++++++
 .../apache/juneau/common/internal/StringUtils.java |  20 +-
 .../juneau/common/internal/ThrowingSupplier.java   |   7 +
 .../org/apache/juneau/common/internal/Utils.java   | 190 ++++++++++++++----
 juneau-core/pom.xml                                |   1 +
 juneau-utest/pom.xml                               |   5 +
 25 files changed, 486 insertions(+), 117 deletions(-)

diff --git a/build-and-push.sh b/build-and-push.sh
new file mode 100755
index 000000000..56657be0d
--- /dev/null
+++ b/build-and-push.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+# 
***************************************************************************************************************************
+# * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+# * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+# * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+# * with the License.  You may obtain a copy of the License at                 
                                             *
+# *                                                                            
                                             *
+# *  http://www.apache.org/licenses/LICENSE-2.0                                
                                             *
+# *                                                                            
                                             *
+# * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+# * specific language governing permissions and limitations under the License. 
                                             *
+# 
***************************************************************************************************************************
+
+# Build and Push Script for Juneau
+# Usage: ./build-and-push.sh "commit message"
+
+set -e  # Exit immediately if a command exits with a non-zero status
+
+# Check if commit message is provided
+if [ -z "$1" ]; then
+    echo "โŒ Error: Commit message is required"
+    echo "Usage: $0 \"commit message\""
+    exit 1
+fi
+
+COMMIT_MESSAGE="$1"
+
+echo "๐Ÿš€ Starting build and push process..."
+
+echo "๐Ÿงช Step 1: Running tests..."
+if ! mvn test; then
+    echo "โŒ Step 1 FAILED: Tests failed! Aborting build process."
+    exit 1
+fi
+echo "โœ… Step 1: All tests passed."
+
+echo "๐Ÿ—๏ธ  Step 2: Building and installing project..."
+if ! mvn clean package install; then
+    echo "โŒ Step 2 FAILED: Build failed! Aborting."
+    exit 1
+fi
+echo "โœ… Step 2: Build and install completed."
+
+echo "๐Ÿ“š Step 3: Generating Javadocs..."
+if ! mvn javadoc:javadoc; then
+    echo "โŒ Step 3 FAILED: Javadoc generation failed! Aborting."
+    exit 1
+fi
+echo "โœ… Step 3: Javadoc generation completed."
+
+echo "๐Ÿ“ Step 4: Committing changes to Git..."
+git add .
+if ! git commit -m "$COMMIT_MESSAGE"; then
+    echo "โŒ Step 4 FAILED: Git commit failed! Aborting."
+    exit 1
+fi
+echo "โœ… Step 4: Git commit completed."
+
+echo "๐Ÿš€ Step 5: Pushing changes to remote repository..."
+if ! git push; then
+    echo "โŒ Step 5 FAILED: Git push failed!"
+    exit 1
+fi
+echo "โœ… Step 5: Git push completed."
+
+echo "๐ŸŽ‰ All operations completed successfully!"
+echo "๐Ÿ“ฆ Commit message: $COMMIT_MESSAGE"
diff --git a/juneau-core/juneau-bct/.gitignore 
b/juneau-core/juneau-bct/.gitignore
new file mode 100644
index 000000000..34acf885c
--- /dev/null
+++ b/juneau-core/juneau-bct/.gitignore
@@ -0,0 +1,6 @@
+/target/
+**/.DS_Store
+.classpath
+.project
+/.settings/
+/bin/
diff --git a/juneau-utest/pom.xml b/juneau-core/juneau-bct/pom.xml
similarity index 58%
copy from juneau-utest/pom.xml
copy to juneau-core/juneau-bct/pom.xml
index 9b6d38505..567dc2d1e 100644
--- a/juneau-utest/pom.xml
+++ b/juneau-core/juneau-bct/pom.xml
@@ -19,85 +19,29 @@
 
        <parent>
                <groupId>org.apache.juneau</groupId>
-               <artifactId>juneau</artifactId>
+               <artifactId>juneau-core</artifactId>
                <version>9.2.0-SNAPSHOT</version>
        </parent>
 
-       <artifactId>juneau-utest</artifactId>
-       <name>juneau/utest</name>
-       <description>Apache Juneau Core API Unit Tests</description>
+       <artifactId>juneau-bct</artifactId>
+       <name>juneau/core/bct</name>
+       <description>Apache Juneau Bean-Centric Testing API</description>
        <packaging>bundle</packaging>
 
        <properties>
                
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-               <!-- Skip javadoc generation since we generate them in the 
aggregate pom -->
-               <maven.javadoc.skip>true</maven.javadoc.skip>
        </properties>
 
        <dependencies>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-marshall</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-config</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-bean-atom</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-bean-common</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-bean-html5</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-bean-jsonschema</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-bean-openapi3</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-rest-mock</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
                <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter</artifactId>
                        <version>5.13.4</version>
-                       <scope>test</scope>
                </dependency>
                <dependency>
                        <groupId>org.opentest4j</groupId>
                        <artifactId>opentest4j</artifactId>
                        <version>1.3.0</version>
-                       <scope>test</scope>
-               </dependency>
-               <dependency>
-                       <groupId>org.openjdk.jmh</groupId>
-                       <artifactId>jmh-core</artifactId>
-                       <version>1.36</version>
-                       <scope>test</scope>
-               </dependency>
-               <dependency>
-                       <groupId>org.openjdk.jmh</groupId>
-                       <artifactId>jmh-generator-annprocess</artifactId>
-                       <version>1.36</version>
-                       <scope>test</scope>
                </dependency>
        </dependencies>
 
@@ -109,7 +53,7 @@
                                <extensions>true</extensions>
                                <configuration>
                                        <instructions>
-                                               
<Automatic-Module-Name>org.apache.juneau.core.test</Automatic-Module-Name>
+                                               
<Automatic-Module-Name>org.apache.juneau.assertions</Automatic-Module-Name>
                                        </instructions>
                                </configuration>
                        </plugin>
@@ -129,25 +73,6 @@
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-jar-plugin</artifactId>
-                               <executions>
-                                       <execution>
-                                               <goals>
-                                                       <goal>test-jar</goal>
-                                               </goals>
-                                       </execution>
-                               </executions>
-                       </plugin>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-surefire-plugin</artifactId>
-                               <configuration>
-                                       <includes>
-                                               
<include>**/*Test.class</include>
-                                       </includes>
-                                       <systemPropertyVariables>
-                                               
<java.locale.providers>JRE,COMPAT,SPI,CLDR</java.locale.providers>
-                                       </systemPropertyVariables>
-                               </configuration>
                        </plugin>
                        <plugin>
                                <groupId>org.jacoco</groupId>
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/AssertionArgs.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/AssertionArgs.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/AssertionArgs.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/AssertionArgs.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/BasicBeanConverter.java
 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/BasicBeanConverter.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/BasicBeanConverter.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/BasicBeanConverter.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/BctAssertions.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/BctAssertions.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/BctAssertions.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/BctAssertions.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/BeanConverter.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/BeanConverter.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/BeanConverter.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/BeanConverter.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Listifier.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Listifier.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/Listifier.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Listifier.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Listifiers.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Listifiers.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/Listifiers.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Listifiers.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/NestedTokenizer.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/NestedTokenizer.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/NestedTokenizer.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/NestedTokenizer.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/PropertyExtractor.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/PropertyExtractor.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/PropertyExtractor.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/PropertyExtractor.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/PropertyExtractors.java
 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/PropertyExtractors.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/PropertyExtractors.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/PropertyExtractors.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/PropertyNotFoundException.java
 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/PropertyNotFoundException.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/PropertyNotFoundException.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/PropertyNotFoundException.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Stringifier.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Stringifier.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/Stringifier.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Stringifier.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Stringifiers.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Stringifiers.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/Stringifiers.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Stringifiers.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Swapper.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Swapper.java
similarity index 100%
rename from juneau-utest/src/test/java/org/apache/juneau/junit/bct/Swapper.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Swapper.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Swappers.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Swappers.java
similarity index 100%
rename from juneau-utest/src/test/java/org/apache/juneau/junit/bct/Swappers.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Swappers.java
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/ThrowingSupplier.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/ThrowingSupplier.java
similarity index 100%
rename from 
juneau-utest/src/test/java/org/apache/juneau/junit/bct/ThrowingSupplier.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/ThrowingSupplier.java
diff --git a/juneau-utest/src/test/java/org/apache/juneau/junit/bct/Utils.java 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Utils.java
similarity index 100%
rename from juneau-utest/src/test/java/org/apache/juneau/junit/bct/Utils.java
rename to 
juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/Utils.java
diff --git 
a/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/package-info.java
 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/package-info.java
new file mode 100644
index 000000000..15d49b289
--- /dev/null
+++ 
b/juneau-core/juneau-bct/src/main/java/org/apache/juneau/junit/bct/package-info.java
@@ -0,0 +1,221 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+
+/**
+ * Bean-Centric Testing Framework.
+ *
+ * <p>This package provides a comprehensive testing framework that extends 
JUnit with streamlined assertion methods
+ * for Java objects. The Bean-Centric Testing (BCT) framework eliminates 
verbose test code while providing
+ * comprehensive object introspection and comparison capabilities.</p>
+ *
+ * <h5 class='section'>Key Features:</h5>
+ * <ul>
+ *    <li><b>Concise Assertions:</b> Replace multiple lines of manual property 
extraction with single assertion calls</li>
+ *    <li><b>Powerful Property Access:</b> Nested objects, collections, 
arrays, and maps with unified syntax</li>
+ *    <li><b>Flexible Comparison:</b> Support for custom converters, 
formatters, and comparison logic</li>
+ *    <li><b>Type Safety:</b> Comprehensive error messages with clear property 
paths</li>
+ *    <li><b>Extensible:</b> Custom property extractors, stringifiers, and 
conversion logic</li>
+ * </ul>
+ *
+ * <h5 class='section'>Core Classes:</h5>
+ * <ul>
+ *    <li><b>{@link BctAssertions}:</b> Main assertion methods for BCT</li>
+ *    <li><b>{@link BeanConverter}:</b> Interface for object conversion and 
property access</li>
+ *    <li><b>{@link BasicBeanConverter}:</b> Default implementation with 
extensible type handlers</li>
+ *    <li><b>{@link AssertionArgs}:</b> Configuration for assertions with 
custom messages and converters</li>
+ * </ul>
+ *
+ * <h5 class='section'>Quick Start:</h5>
+ * <p class='bjava'>
+ *    <jk>import static</jk> com.sfdc.junit.bct.BctAssertions.*;
+ *
+ *    <ja>@Test</ja>
+ *    <jk>void</jk> testUser() {
+ *       User <jv>user</jv> = <jk>new</jk> User(<js>"Alice"</js>, 25, 
<jk>true</jk>);
+ *
+ *       <jc>// Test multiple properties at once</jc>
+ *       <jsm>assertBean</jsm>(<jv>user</jv>, <js>"name,age,active"</js>, 
<js>"Alice,25,true"</js>);
+ *
+ *       <jc>// Test nested objects</jc>
+ *       <jsm>assertBean</jsm>(<jv>user</jv>, <js>"address{street,city}"</js>, 
<js>"{123 Main St,Springfield}"</js>);
+ *    }
+ * </p>
+ *
+ * <h5 class='section'>Assertion Method Examples:</h5>
+ *
+ * <h6 class='figure'>1. {@link BctAssertions#assertBean(Object,String,String) 
assertBean()}</h6>
+ * <p>Tests object properties with support for nested syntax and collection 
iteration.</p>
+ * <p class='bjava'>
+ *    User <jv>user</jv> = <jk>new</jk> User(<js>"Bob"</js>, 30);
+ *    <jv>user</jv>.setAddress(<jk>new</jk> Address(<js>"456 Oak Ave"</js>, 
<js>"Denver"</js>));
+ *
+ *    <jc>// Test simple properties</jc>
+ *    <jsm>assertBean</jsm>(<jv>user</jv>, <js>"name"</js>, <js>"Bob"</js>);
+ *    <jsm>assertBean</jsm>(<jv>user</jv>, <js>"name,age"</js>, 
<js>"Bob,30"</js>);
+ *
+ *    <jc>// Test nested properties</jc>
+ *    <jsm>assertBean</jsm>(<jv>user</jv>, <js>"address.street"</js>, <js>"456 
Oak Ave"</js>);
+ *    <jsm>assertBean</jsm>(<jv>user</jv>, <js>"address{street,city}"</js>, 
<js>"{456 Oak Ave,Denver}"</js>);
+ * </p>
+ *
+ * <h6 class='figure'>2. {@link 
BctAssertions#assertBeans(Object,String,String...) assertBeans()}</h6>
+ * <p>Tests collections of objects by extracting and comparing specific 
fields.</p>
+ * <p class='bjava'>
+ *    List&lt;User&gt; <jv>users</jv> = Arrays.<jsm>asList</jsm>(
+ *       <jk>new</jk> User(<js>"Alice"</js>, 25),
+ *       <jk>new</jk> User(<js>"Bob"</js>, 30),
+ *       <jk>new</jk> User(<js>"Carol"</js>, 35)
+ *    );
+ *
+ *    <jc>// Test single field across collection</jc>
+ *    <jsm>assertBeans</jsm>(<jv>users</jv>, <js>"name"</js>, 
<js>"Alice"</js>, <js>"Bob"</js>, <js>"Carol"</js>);
+ *
+ *    <jc>// Test multiple fields</jc>
+ *    <jsm>assertBeans</jsm>(<jv>users</jv>, <js>"name,age"</js>, 
<js>"Alice,25"</js>, <js>"Bob,30"</js>, <js>"Carol,35"</js>);
+ * </p>
+ *
+ * <h6 class='figure'>3. {@link 
BctAssertions#assertMapped(Object,java.util.function.BiFunction,String,String) 
assertMapped()}</h6>
+ * <p>Tests custom property access using BiFunction for non-standard 
objects.</p>
+ * <p class='bjava'>
+ *    Map&lt;String,Object&gt; <jv>data</jv> = <jk>new</jk> HashMap&lt;&gt;();
+ *    <jv>data</jv>.put(<js>"name"</js>, <js>"Alice"</js>);
+ *    <jv>data</jv>.put(<js>"score"</js>, 95);
+ *
+ *    <jc>// Custom property extractor for Map objects</jc>
+ *    <jsm>assertMapped</jsm>(<jv>data</jv>, (obj, key) -&gt; obj.get(key), 
<js>"name,score"</js>, <js>"Alice,95"</js>);
+ * </p>
+ *
+ * <h6 class='figure'>4. {@link BctAssertions#assertList(Object,Object...) 
assertList()}</h6>
+ * <p>Tests list/collection elements with varargs for expected values.</p>
+ * <p class='bjava'>
+ *    List&lt;String&gt; <jv>names</jv> = 
Arrays.<jsm>asList</jsm>(<js>"Alice"</js>, <js>"Bob"</js>, <js>"Carol"</js>);
+ *    String[] <jv>colors</jv> = {<js>"red"</js>, <js>"green"</js>, 
<js>"blue"</js>};
+ *
+ *    <jc>// Test list contents</jc>
+ *    <jsm>assertList</jsm>(<jv>names</jv>, <js>"Alice"</js>, <js>"Bob"</js>, 
<js>"Carol"</js>);
+ *    <jsm>assertList</jsm>(<jv>colors</jv>, <js>"red"</js>, <js>"green"</js>, 
<js>"blue"</js>);
+ * </p>
+ *
+ * <h6 class='figure'>5. {@link BctAssertions#assertContains(String,Object) 
assertContains()}</h6>
+ * <p>Tests that a string appears somewhere within the stringified object.</p>
+ * <p class='bjava'>
+ *    User <jv>user</jv> = <jk>new</jk> User(<js>"Alice Smith"</js>, 25);
+ *    List&lt;String&gt; <jv>items</jv> = 
Arrays.<jsm>asList</jsm>(<js>"apple"</js>, <js>"banana"</js>, 
<js>"cherry"</js>);
+ *
+ *    <jc>// Test substring presence</jc>
+ *    <jsm>assertContains</jsm>(<js>"Alice"</js>, <jv>user</jv>);
+ *    <jsm>assertContains</jsm>(<js>"banana"</js>, <jv>items</jv>);
+ * </p>
+ *
+ * <h6 class='figure'>6. {@link 
BctAssertions#assertContainsAll(Object,String...) assertContainsAll()}</h6>
+ * <p>Tests that all specified strings appear within the stringified 
object.</p>
+ * <p class='bjava'>
+ *    User <jv>user</jv> = <jk>new</jk> User(<js>"Alice Smith"</js>, 25);
+ *    <jv>user</jv>.setEmail(<js>"[email protected]"</js>);
+ *
+ *    <jc>// Test multiple substrings</jc>
+ *    <jsm>assertContainsAll</jsm>(<jv>user</jv>, <js>"Alice"</js>, 
<js>"Smith"</js>, <js>"25"</js>);
+ *    <jsm>assertContainsAll</jsm>(<jv>user</jv>, <js>"alice"</js>, 
<js>"example.com"</js>);
+ * </p>
+ *
+ * <h6 class='figure'>7. {@link BctAssertions#assertEmpty(Object) 
assertEmpty()}</h6>
+ * <p>Tests that collections, arrays, maps, or strings are empty.</p>
+ * <p class='bjava'>
+ *    List&lt;String&gt; <jv>emptyList</jv> = <jk>new</jk> ArrayList&lt;&gt;();
+ *    String[] <jv>emptyArray</jv> = {};
+ *    Map&lt;String,String&gt; <jv>emptyMap</jv> = <jk>new</jk> 
HashMap&lt;&gt;();
+ *    String <jv>emptyString</jv> = <js>""</js>;
+ *
+ *    <jc>// Test empty collections</jc>
+ *    <jsm>assertEmpty</jsm>(<jv>emptyList</jv>);
+ *    <jsm>assertEmpty</jsm>(<jv>emptyArray</jv>);
+ *    <jsm>assertEmpty</jsm>(<jv>emptyMap</jv>);
+ *    <jsm>assertEmpty</jsm>(<jv>emptyString</jv>);
+ * </p>
+ *
+ * <h6 class='figure'>8. {@link BctAssertions#assertNotEmpty(Object) 
assertNotEmpty()}</h6>
+ * <p>Tests that collections, arrays, maps, or strings are not empty.</p>
+ * <p class='bjava'>
+ *    List&lt;String&gt; <jv>names</jv> = 
Arrays.<jsm>asList</jsm>(<js>"Alice"</js>);
+ *    String[] <jv>colors</jv> = {<js>"red"</js>};
+ *    Map&lt;String,String&gt; <jv>config</jv> = 
Map.<jsm>of</jsm>(<js>"key"</js>, <js>"value"</js>);
+ *    String <jv>message</jv> = <js>"Hello"</js>;
+ *
+ *    <jc>// Test non-empty collections</jc>
+ *    <jsm>assertNotEmpty</jsm>(<jv>names</jv>);
+ *    <jsm>assertNotEmpty</jsm>(<jv>colors</jv>);
+ *    <jsm>assertNotEmpty</jsm>(<jv>config</jv>);
+ *    <jsm>assertNotEmpty</jsm>(<jv>message</jv>);
+ * </p>
+ *
+ * <h6 class='figure'>9. {@link BctAssertions#assertSize(int,Object) 
assertSize()}</h6>
+ * <p>Tests the size/length of collections, arrays, maps, or strings.</p>
+ * <p class='bjava'>
+ *    List&lt;String&gt; <jv>names</jv> = 
Arrays.<jsm>asList</jsm>(<js>"Alice"</js>, <js>"Bob"</js>, <js>"Carol"</js>);
+ *    String[] <jv>colors</jv> = {<js>"red"</js>, <js>"green"</js>};
+ *    Map&lt;String,Integer&gt; <jv>scores</jv> = 
Map.<jsm>of</jsm>(<js>"Alice"</js>, 95, <js>"Bob"</js>, 87);
+ *    String <jv>message</jv> = <js>"Hello"</js>;
+ *
+ *    <jc>// Test collection sizes</jc>
+ *    <jsm>assertSize</jsm>(3, <jv>names</jv>);
+ *    <jsm>assertSize</jsm>(2, <jv>colors</jv>);
+ *    <jsm>assertSize</jsm>(2, <jv>scores</jv>);
+ *    <jsm>assertSize</jsm>(5, <jv>message</jv>);
+ * </p>
+ *
+ * <h6 class='figure'>10. {@link BctAssertions#assertString(String,Object) 
assertString()}</h6>
+ * <p>Tests the string representation of an object using the configured 
converter.</p>
+ * <p class='bjava'>
+ *    User <jv>user</jv> = <jk>new</jk> User(<js>"Alice"</js>, 25);
+ *    List&lt;Integer&gt; <jv>numbers</jv> = Arrays.<jsm>asList</jsm>(1, 2, 3);
+ *    Date <jv>date</jv> = <jk>new</jk> Date(1609459200000L); <jc>// 
2021-01-01</jc>
+ *
+ *    <jc>// Test string representations</jc>
+ *    <jsm>assertString</jsm>(<js>"User(name=Alice, age=25)"</js>, 
<jv>user</jv>);
+ *    <jsm>assertString</jsm>(<js>"[1, 2, 3]"</js>, <jv>numbers</jv>);
+ *    <jsm>assertString</jsm>(<js>"2021-01-01"</js>, <jv>date</jv>);
+ * </p>
+ *
+ * <h6 class='figure'>11. {@link 
BctAssertions#assertMatchesGlob(String,Object) assertMatchesGlob()}</h6>
+ * <p>Tests that the stringified object matches a glob-style pattern (* and ? 
wildcards).</p>
+ * <p class='bjava'>
+ *    User <jv>user</jv> = <jk>new</jk> User(<js>"Alice Smith"</js>, 25);
+ *    String <jv>filename</jv> = <js>"report.pdf"</js>;
+ *    String <jv>email</jv> = <js>"[email protected]"</js>;
+ *
+ *    <jc>// Test pattern matching</jc>
+ *    <jsm>assertMatchesGlob</jsm>(<js>"*Alice*"</js>, <jv>user</jv>);
+ *    <jsm>assertMatchesGlob</jsm>(<js>"*.pdf"</js>, <jv>filename</jv>);
+ *    <jsm>assertMatchesGlob</jsm>(<js>"*@*.com"</js>, <jv>email</jv>);
+ *    <jsm>assertMatchesGlob</jsm>(<js>"User(name=Alice*, age=25)"</js>, 
<jv>user</jv>);
+ * </p>
+ *
+ * <h5 class='section'>Custom Configuration with {@link AssertionArgs}:</h5>
+ * <p>All assertion methods support custom configuration through {@link 
AssertionArgs}:</p>
+ * <p class='bjava'>
+ *    <jc>// Custom error message</jc>
+ *    <jsm>assertBean</jsm>(<jsm>args</jsm>(<js>"User validation 
failed"</js>), <jv>user</jv>, <js>"name,age"</js>, <js>"Alice,25"</js>);
+ *
+ *    <jc>// Custom converter configuration</jc>
+ *    AssertionArgs <jv>args</jv> = <jsm>args</jsm>()
+ *       
.setConverter(BasicBeanConverter.<jsm>builder</jsm>().<jsm>defaultSettings</jsm>()
+ *          .setSetting(<js>"nullValue"</js>, <js>"&lt;empty&gt;"</js>)
+ *          .build());
+ *    <jsm>assertBean</jsm>(<jv>args</jv>, <jv>user</jv>, 
<js>"name,nickname"</js>, <js>"Alice,&lt;empty&gt;"</js>);
+ * </p>
+ *
+ * @see BctAssertions
+ * @see BeanConverter
+ * @see BasicBeanConverter
+ */
+package org.apache.juneau.junit.bct;
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/StringUtils.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/StringUtils.java
index 8f288879c..834b19ce1 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/StringUtils.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/StringUtils.java
@@ -1690,6 +1690,12 @@ public final class StringUtils {
                return sb.toString();
        }
 
+       /**
+        * Converts the contents of the specified input stream to a hex string.
+        * 
+        * @param is The input stream to convert.
+        * @return The hex string representation of the input stream contents, 
or <jk>null</jk> if the stream is <jk>null</jk>.
+        */
        public static String toHex(InputStream is) {
                return safe(()->is == null ? null : toHex(readBytes(is)));
        }
@@ -1817,10 +1823,22 @@ public final class StringUtils {
                }
        }
 
+       /**
+        * Converts the specified byte array to a UTF-8 string.
+        * 
+        * @param b The byte array to convert.
+        * @return The UTF-8 string representation, or <jk>null</jk> if the 
array is <jk>null</jk>.
+        */
        public static String toUtf8(byte[] b) {
                return b == null ? null : new String(b, IOUtils.UTF8);
        }
 
+       /**
+        * Converts the contents of the specified input stream to a UTF-8 
string.
+        * 
+        * @param is The input stream to convert.
+        * @return The UTF-8 string representation of the input stream 
contents, or <jk>null</jk> if the stream is <jk>null</jk>.
+        */
        public static String toUtf8(InputStream is) {
                return safe(()->is == null ? null : new String(readBytes(is), 
IOUtils.UTF8));
        }
@@ -2134,4 +2152,4 @@ public final class StringUtils {
         * Constructor.
         */
        protected StringUtils() {}
-}
\ No newline at end of file
+}
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/ThrowingSupplier.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/ThrowingSupplier.java
index f2733a17c..81e9b29a1 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/ThrowingSupplier.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/ThrowingSupplier.java
@@ -17,5 +17,12 @@ package org.apache.juneau.common.internal;
  */
 @FunctionalInterface
 public interface ThrowingSupplier<T> {
+
+       /**
+        * Gets a result.
+        * 
+        * @return A result.
+        * @throws Exception If an error occurs.
+        */
        T get() throws Exception;
 }
\ No newline at end of file
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/Utils.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/Utils.java
index 1b7146bfb..bb442fe50 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/Utils.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/internal/Utils.java
@@ -28,7 +28,11 @@ import java.util.stream.*;
 
 import org.apache.juneau.common.utils.*;
 
-
+/**
+ * Common utility methods.
+ * 
+ * <p>This class contains various static utility methods for working with 
collections, strings, objects, and other common operations.
+ */
 public class Utils {
 
        private static final Map<Class<?>,Function<String,?>> ENV_FUNCTIONS = 
new IdentityHashMap<>();
@@ -42,6 +46,10 @@ public class Utils {
 
        /**
         * Creates an array of objects.
+        * 
+        * @param <T> The component type of the array.
+        * @param x The objects to place in the array.
+        * @return A new array containing the specified objects.
         */
        @SafeVarargs
        public static <T> T[] a(T...x) {
@@ -53,7 +61,7 @@ public class Utils {
         *
         * @param <T> The element type.
         * @param o The object to traverse.
-        * @param c The consumer of the objects.
+        * @return A list containing all accumulated elements.
         */
        public static <T> List<T> accumulate(Object o) {
                var l = list();
@@ -63,6 +71,10 @@ public class Utils {
 
        /**
         * Shortcut for creating an unmodifiable list out of an array of values.
+        * 
+        * @param <T> The element type.
+        * @param values The values to add to the list.
+        * @return An unmodifiable list containing the specified values, or 
<jk>null</jk> if the input is <jk>null</jk>.
         */
        @SafeVarargs
        public static <T> List<T> alist(T...values) {  // NOSONAR
@@ -276,6 +288,10 @@ public class Utils {
 
        /**
         * Null-safe {@link String#contains(CharSequence)} operation.
+        * 
+        * @param s The string to check.
+        * @param values The characters to check for.
+        * @return <jk>true</jk> if the string contains any of the specified 
characters.
         */
        public static boolean contains(String s, char...values) {
                if (s == null || values == null || values.length == 0)
@@ -289,6 +305,10 @@ public class Utils {
 
        /**
         * Null-safe {@link String#contains(CharSequence)} operation.
+        * 
+        * @param s The string to check.
+        * @param values The substrings to check for.
+        * @return <jk>true</jk> if the string contains any of the specified 
substrings.
         */
        public static boolean contains(String s, String...values) {
                if (s == null || values == null || values.length == 0)
@@ -306,6 +326,10 @@ public class Utils {
 
        /**
         * Shortcut for creating an empty list of the specified type.
+        * 
+        * @param <T> The element type.
+        * @param type The element type class.
+        * @return An empty list.
         */
        public static <T> List<T> elist(Class<T> type) {
                return Collections.emptyList();
@@ -327,6 +351,9 @@ public class Utils {
 
        /**
         * Returns the specified string, or blank if that string is null.
+        * 
+        * @param value The value to convert to a string.
+        * @return The string representation of the value, or an empty string 
if <jk>null</jk>.
         */
        public static String emptyIfNull(Object value) {
                return value == null ? "" : value.toString();
@@ -410,7 +437,7 @@ public class Utils {
         * Example:
         * <code>
         *      public boolean equals(Object o)
-        *              return eq(this, (Role)o, (x,y)->eq(x.id,y.id) && 
eq(x.name,y.name) && eq(x.created,y.created) && eq(x.createdBy,y.createdBy));
+        *              return eq(this, (Role)o, (x,y)-&gt;eq(x.id,y.id) 
&amp;&amp; eq(x.name,y.name) &amp;&amp; eq(x.created,y.created) &amp;&amp; 
eq(x.createdBy,y.createdBy));
         *      }
         * </code>
         *
@@ -445,6 +472,10 @@ public class Utils {
 
        /**
         * Same as MessageFormat.format().
+        * 
+        * @param pattern The message pattern.
+        * @param args The arguments to substitute into the pattern.
+        * @return The formatted string.
         */
        public static String f(String pattern, Object...args) {
                if (args.length == 0)
@@ -530,6 +561,9 @@ public class Utils {
 
        /**
         * Shortcut for calling {@link Objects#hash(Object...)}.
+        * 
+        * @param values The values to hash.
+        * @return A hash code value for the given values.
         */
        public static final int hash(Object...values) {
                return Objects.hash(values);
@@ -537,6 +571,10 @@ public class Utils {
 
        /**
         * Creates an {@link IllegalArgumentException}.
+        * 
+        * @param msg The exception message.
+        * @param args The arguments to substitute into the message.
+        * @return A new IllegalArgumentException with the formatted message.
         */
        public static IllegalArgumentException illegalArg(String msg, 
Object...args) {
                return new IllegalArgumentException(args.length == 0 ? msg : 
f(msg, args));
@@ -576,7 +614,10 @@ public class Utils {
        }
 
        /**
-        * @return True if string is null or empty.
+        * Returns <jk>true</jk> if string is <jk>null</jk> or empty.
+        * 
+        * @param o The string to check.
+        * @return <jk>true</jk> if string is <jk>null</jk> or empty.
         */
        public static boolean isEmpty(String o) {
                return o == null || o.isEmpty();
@@ -611,7 +652,10 @@ public class Utils {
        }
 
        /**
-        * @return True if string is not null or empty.
+        * Returns <jk>true</jk> if string is not <jk>null</jk> and not empty.
+        * 
+        * @param o The string to check.
+        * @return <jk>true</jk> if string is not <jk>null</jk> and not empty.
         */
        public static boolean isNotEmpty(String o) {
                return ! isEmpty(o);
@@ -835,6 +879,10 @@ public class Utils {
 
        /**
         * Shortcut for creating a modifiable list out of an array of values.
+        * 
+        * @param <T> The element type.
+        * @param values The values to add to the list.
+        * @return A modifiable list containing the specified values.
         */
        @SafeVarargs
        public static <T> List<T> list(T...values) {  // NOSONAR
@@ -853,7 +901,12 @@ public class Utils {
        }
 
        /**
-        * Shortcut for creating a modifiable set out of an array of values.
+        * Shortcut for creating a modifiable map out of an array of key-value 
pairs.
+        * 
+        * @param <K> The key type.
+        * @param <V> The value type.
+        * @param values The key-value pairs (alternating keys and values).
+        * @return A modifiable LinkedHashMap containing the specified 
key-value pairs.
         */
        @SafeVarargs
        public static <K,V> LinkedHashMap<K,V> map(Object...values) {  // 
NOSONAR
@@ -872,7 +925,14 @@ public class Utils {
                return null;
        }
 
-       /** Not equals */
+       /**
+        * Null-safe not-equals check.
+        * 
+        * @param <T> The object type.
+        * @param s1 Object 1.
+        * @param s2 Object 2.
+        * @return <jk>true</jk> if the objects are not equal.
+        */
        public static <T> boolean ne(T s1, T s2) {
                return ! eq(s1, s2);
        }
@@ -908,23 +968,46 @@ public class Utils {
                return ! eqic(s1, s2);
        }
 
+       /**
+        * Returns a null list.
+        * 
+        * @param <T> The element type.
+        * @param type The element type class.
+        * @return <jk>null</jk>.
+        */
        public static <T> List<T> nlist(Class<T> type) {
                return null;
        }
 
+       /**
+        * Returns a null map.
+        * 
+        * @param <K> The key type.
+        * @param <V> The value type.
+        * @param keyType The key type class.
+        * @param valueType The value type class.
+        * @return <jk>null</jk>.
+        */
        public static <K,V> Map<K,V> nmap(Class<K> keyType, Class<V> valueType) 
{
                return null;
        }
 
        /**
-        * Null-safe {@link String#contains(CharSequence)} operation.
+        * Null-safe string not-contains operation.
+        * 
+        * @param s The string to check.
+        * @param values The characters to check for.
+        * @return <jk>true</jk> if the string does not contain any of the 
specified characters.
         */
        public static boolean notContains(String s, char...values) {
                return ! contains(s, values);
        }
 
        /**
-        * Returns the specified string, or null if that string is null or 
empty.
+        * Returns the specified string, or <jk>null</jk> if that string is 
<jk>null</jk> or empty.
+        * 
+        * @param value The string value to check.
+        * @return The string value, or <jk>null</jk> if the string is 
<jk>null</jk> or empty.
         */
        public static String nullIfEmpty(String value) {
                return isEmpty(value) ? null : value;
@@ -944,6 +1027,9 @@ public class Utils {
 
        /**
         * Returns an obfuscated version of the specified string.
+        * 
+        * @param s The string to obfuscate.
+        * @return The obfuscated string with most characters replaced by 
asterisks.
         */
        public static String obfuscate(String s) {
                if (s == null || s.length() < 2)
@@ -953,17 +1039,29 @@ public class Utils {
 
        /**
         * Shortcut for calling {@link Optional#ofNullable(Object)}.
+        * 
+        * @param <T> The object type.
+        * @param t The object to wrap in an Optional.
+        * @return An Optional containing the specified object, or empty if 
<jk>null</jk>.
         */
        public static final <T> Optional<T> opt(T t) {
                return Optional.ofNullable(t);
        }
 
+       /**
+        * Returns an empty Optional.
+        * 
+        * @param <T> The object type.
+        * @return An empty Optional.
+        */
        public static final <T> Optional<T> opte() {
                return Optional.empty();
        }
 
        /**
         * Prints all the specified lines to System.out.
+        * 
+        * @param lines The lines to print.
         */
        public static final void printLines(String[] lines) {
                for (var i = 0; i < lines.length; i++)
@@ -978,23 +1076,23 @@ public class Utils {
         * the Juneau framework for test assertions and debugging output.</p>
         *
          * <h5 class='section'>Type-Specific Formatting:</h5>
- * <ul>
- *     <li><b>null:</b> Returns <js>null</js></li>
- *     <li><b>Optional:</b> Recursively formats the contained value (or 
<js>null</js> if empty)</li>
- *     <li><b>Collections:</b> Formats as <js>"[item1,item2,item3]"</js> with 
comma-separated elements</li>
- *     <li><b>Maps:</b> Formats as <js>"{key1=value1,key2=value2}"</js> with 
comma-separated entries</li>
- *     <li><b>Map.Entry:</b> Formats as <js>"key=value"</js></li>
- *     <li><b>Arrays:</b> Converts to list format 
<js>"[item1,item2,item3]"</js></li>
- *     <li><b>Iterables/Iterators/Enumerations:</b> Converts to list and 
formats recursively</li>
- *     <li><b>GregorianCalendar:</b> Formats as ISO instant timestamp</li>
- *     <li><b>Date:</b> Formats as ISO instant string (e.g., 
<js>"2023-12-25T10:30:00Z"</js>)</li>
- *     <li><b>InputStream:</b> Converts to hexadecimal representation</li>
- *     <li><b>Reader:</b> Reads content and returns as string</li>
- *     <li><b>File:</b> Reads file content and returns as string</li>
- *     <li><b>byte[]:</b> Converts to hexadecimal representation</li>
- *     <li><b>Enum:</b> Returns the enum name via {@link Enum#name()}</li>
- *     <li><b>All other types:</b> Uses {@link Object#toString()}</li>
- * </ul>
+        * <ul>
+        *      <li><b>null:</b> Returns <js>null</js></li>
+        *      <li><b>Optional:</b> Recursively formats the contained value 
(or <js>null</js> if empty)</li>
+        *      <li><b>Collections:</b> Formats as 
<js>"[item1,item2,item3]"</js> with comma-separated elements</li>
+        *      <li><b>Maps:</b> Formats as 
<js>"{key1=value1,key2=value2}"</js> with comma-separated entries</li>
+        *      <li><b>Map.Entry:</b> Formats as <js>"key=value"</js></li>
+        *      <li><b>Arrays:</b> Converts to list format 
<js>"[item1,item2,item3]"</js></li>
+        *      <li><b>Iterables/Iterators/Enumerations:</b> Converts to list 
and formats recursively</li>
+        *      <li><b>GregorianCalendar:</b> Formats as ISO instant 
timestamp</li>
+        *      <li><b>Date:</b> Formats as ISO instant string (e.g., 
<js>"2023-12-25T10:30:00Z"</js>)</li>
+        *      <li><b>InputStream:</b> Converts to hexadecimal 
representation</li>
+        *      <li><b>Reader:</b> Reads content and returns as string</li>
+        *      <li><b>File:</b> Reads file content and returns as string</li>
+        *      <li><b>byte[]:</b> Converts to hexadecimal representation</li>
+        *      <li><b>Enum:</b> Returns the enum name via {@link 
Enum#name()}</li>
+        *      <li><b>All other types:</b> Uses {@link Object#toString()}</li>
+        * </ul>
         *
         * <h5 class='section'>Examples:</h5>
         * <p class='bjava'>
@@ -1013,10 +1111,10 @@ public class Utils {
         *      r(List.of(Map.of("x", 1), Set.of("a", "b"))) <jc>// Returns: 
"[{x=1},[a,b]]"</jc>
         *
          *     <jc>// Special types</jc>
- *     r(Optional.of("test")) <jc>// Returns: "test"</jc>
- *     r(Optional.empty()) <jc>// Returns: null</jc>
- *     r(new Date(1640995200000L)) <jc>// Returns: "2022-01-01T00:00:00Z"</jc>
- *     r(MyEnum.FOO) <jc>// Returns: "FOO"</jc>
+        *      r(Optional.of("test")) <jc>// Returns: "test"</jc>
+        *      r(Optional.empty()) <jc>// Returns: null</jc>
+        *      r(new Date(1640995200000L)) <jc>// Returns: 
"2022-01-01T00:00:00Z"</jc>
+        *      r(MyEnum.FOO) <jc>// Returns: "FOO"</jc>
         * </p>
         *
         * <h5 class='section'>Recursive Processing:</h5>
@@ -1090,6 +1188,10 @@ public class Utils {
 
        /**
         * Creates a {@link RuntimeException}.
+        * 
+        * @param msg The exception message.
+        * @param args The arguments to substitute into the message.
+        * @return A new RuntimeException with the formatted message.
         */
        public static RuntimeException runtimeException(String msg, 
Object...args) {
                return new RuntimeException(args.length == 0 ? msg : f(msg, 
args));
@@ -1097,6 +1199,9 @@ public class Utils {
 
        /**
         * Shortcut for converting an object to a string.
+        * 
+        * @param val The object to convert.
+        * @return The string representation of the object, or <jk>null</jk> if 
the object is <jk>null</jk>.
         */
        public static String s(Object val) {
                return val == null ? null : val.toString();
@@ -1121,6 +1226,10 @@ public class Utils {
         * Used to wrap code that returns a value but throws an exception.
         * Useful in cases where you're trying to execute code in a fluent 
method call
         * or are trying to eliminate untestable catch blocks in code.
+        * 
+        * @param <T> The return type.
+        * @param s The supplier that may throw an exception.
+        * @return The result of the supplier execution.
         */
        public static <T> T safe(ThrowingSupplier<T> s) {
                try {
@@ -1152,6 +1261,10 @@ public class Utils {
 
        /**
         * Shortcut for creating a modifiable set out of an array of values.
+        * 
+        * @param <T> The element type.
+        * @param values The values to add to the set.
+        * @return A modifiable LinkedHashSet containing the specified values.
         */
        @SafeVarargs
        public static <T> LinkedHashSet<T> set(T...values) {  // NOSONAR
@@ -1160,6 +1273,9 @@ public class Utils {
 
        /**
         * Splits a comma-delimited list into a list of strings.
+        * 
+        * @param s The string to split.
+        * @return A list of split strings, or an empty list if the input is 
<jk>null</jk>.
         */
        public static List<String> split(String s) {
                return s == null ? Collections.emptyList() : split(s, ',');
@@ -1274,7 +1390,7 @@ public class Utils {
        }
 
        /**
-        * Same as {@link #split3(String)} but consumes the tokens instead of 
creating an array.
+        * Same as {@link #splita(String)} but consumes the tokens instead of 
creating an array.
         *
         * @param s The string to split.
         * @param consumer The consumer of the tokens.
@@ -1285,6 +1401,9 @@ public class Utils {
 
        /**
         * Splits a comma-delimited list into an array of strings.
+        * 
+        * @param s The string to split.
+        * @return An array of split strings.
         */
        public static String[] splita(String s) {
                return splita(s, ',');
@@ -1721,16 +1840,15 @@ public class Utils {
         *      assertList(toList(<jv>myQueue</jv>), <js>"first"</js>, 
<js>"second"</js>);
         * </p>
         *
-        * <h5 class='section'>Integration with assertList:</h5>
-        * <p>This method is specifically designed to work with {@link 
#assertList(List, Object...)} to provide
+        * <h5 class='section'>Integration with Testing:</h5>
+        * <p>This method is specifically designed to work with testing 
frameworks to provide
         * a unified testing approach for all collection-like types. Instead of 
having separate assertion methods
-        * for arrays, sets, and other collections, you can convert them all to 
Lists and use the single
-        * {@code assertList} method.</p>
+        * for arrays, sets, and other collections, you can convert them all to 
Lists and use standard
+        * list assertion methods.</p>
         *
         * @param o The object to convert to a List. Must not be null and must 
be a supported collection-like type.
         * @return A {@link List} containing the elements from the input object.
         * @throws IllegalArgumentException if the input object cannot be 
converted to a List.
-        * @see #assertList(List, Object...)
         * @see #arrayToList(Object)
         */
        public static final List<?> toList(Object o) {  // NOSONAR
diff --git a/juneau-core/pom.xml b/juneau-core/pom.xml
index f72907786..9a7fb83ec 100644
--- a/juneau-core/pom.xml
+++ b/juneau-core/pom.xml
@@ -33,5 +33,6 @@
                <module>juneau-marshall</module>
                <module>juneau-config</module>
                <module>juneau-assertions</module>
+               <module>juneau-bct</module>
        </modules>
 </project>
diff --git a/juneau-utest/pom.xml b/juneau-utest/pom.xml
index 9b6d38505..06b310aad 100644
--- a/juneau-utest/pom.xml
+++ b/juneau-utest/pom.xml
@@ -75,6 +75,11 @@
                        <artifactId>juneau-rest-mock</artifactId>
                        <version>${project.version}</version>
                </dependency>
+               <dependency>
+                       <groupId>org.apache.juneau</groupId>
+                       <artifactId>juneau-bct</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
                <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter</artifactId>


Reply via email to