You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2026/07/16 12:30:24 UTC

(juneau) branch master updated: Printf-only f()/fs() migration + mf()/mfs() split (10.0.0 breaking change)

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 6f10116cba Printf-only f()/fs() migration + mf()/mfs() split (10.0.0 breaking change)
6f10116cba is described below

commit 6f10116cbadb252f40e1e5fadbd391ddf6b835e6
Author: James Bognar <ja...@apache.org>
AuthorDate: Thu Jul 16 08:30:04 2026 -0400

    Printf-only f()/fs() migration + mf()/mfs() split (10.0.0 breaking change)
    
    Cut StringFormat over to printf-only semantics and split the message-format
    variants into dedicated mf()/mfs() helpers:
    
    - StringFormat: collapse to printf-only formatting; f()/fs() now delegate to
      String.format-style semantics, with mf()/mfs() carrying the legacy
      MessageFormat ({0}) behavior.
    - Convert {0}->%s across exception factories, assertions/verify helpers,
      Console, LinkString, and VarTemplateCompiler call sites.
    - Flip Logger/LogRecord onto printf-style formatting to match the new default.
    - TODO-246 marshaller-adoption sweep: replace *Serializer.DEFAULT usages with
      the instance-based marshaller API (Json5.of(...), etc.) reactor-wide.
    
    BREAKING CHANGE: f()/fs() now use printf (%s) semantics instead of
    MessageFormat ({0}). Callers relying on the old behavior must switch to
    mf()/mfs().
    
    Co-authored-by: Cursor <cu...@cursor.com>
---
 .gitignore                                         |   2 +-
 .../java/org/apache/juneau/bean/LinkString.java    |   6 +-
 .../apache/juneau/bean/common/LinkString_Test.java |   2 +-
 .../java/org/apache/juneau/bean/hal/HalLink.java   |   4 +-
 .../org/apache/juneau/bean/hal/HalResource.java    |   4 +-
 .../org/apache/juneau/ComboRoundTrip_Tester.java   |  18 +-
 .../juneau/bean/jsonapi/JsonApiDocument.java       |   4 +-
 .../apache/juneau/bean/jsonapi/JsonApiError.java   |   4 +-
 .../juneau/bean/jsonapi/JsonApiErrorSource.java    |   4 +-
 .../apache/juneau/bean/jsonapi/JsonApiLink.java    |   4 +-
 .../juneau/bean/jsonapi/JsonApiRelationship.java   |   4 +-
 .../juneau/bean/jsonapi/JsonApiResource.java       |   4 +-
 .../bean/jsonapi/JsonApiResourceIdentifier.java    |   4 +-
 .../apache/juneau/bean/jsonapi/JsonApiVersion.java |   4 +-
 .../juneau/bean/jsonpatch/JsonPatchOperation.java  |   4 +-
 .../apache/juneau/bean/jsonschema/JsonSchema.java  |  14 +-
 .../bean/jsonschema/JsonSchemaBeanGenerator.java   |   3 +-
 .../juneau/bean/jsonschema/JsonSchemaMap.java      |   4 +-
 .../bean/jsonschema/JsonSchemaValidator.java       |  42 ++-
 .../org/apache/juneau/bean/openapi3/Items.java     |   8 +-
 .../org/apache/juneau/bean/openapi3/OpenApi.java   |  10 +-
 .../juneau/bean/openapi3/OpenApiElement.java       |   8 +-
 .../org/apache/juneau/bean/openapi3/Parameter.java |   6 +-
 .../juneau/bean/openapi3/SecuritySchemeInfo.java   |   6 +-
 .../org/apache/juneau/bean/swagger/HeaderInfo.java |   6 +-
 .../java/org/apache/juneau/bean/swagger/Items.java |   6 +-
 .../apache/juneau/bean/swagger/ParameterInfo.java  |   8 +-
 .../apache/juneau/bean/swagger/SecurityScheme.java |   4 +-
 .../org/apache/juneau/bean/swagger/Swagger.java    |  10 +-
 .../apache/juneau/bean/swagger/SwaggerElement.java |   8 +-
 .../juneau/commons/InvalidAnnotationException.java |   4 +-
 .../org/apache/juneau/commons/bean/BeanMap.java    |   8 +-
 .../org/apache/juneau/commons/bean/BeanMeta.java   |  10 +-
 .../juneau/commons/bean/BeanPropertyMeta.java      |  36 +--
 .../commons/bean/BeanProxyInvocationHandler.java   |   4 +-
 .../apache/juneau/commons/collections/BidiMap.java |   8 +-
 .../juneau/commons/collections/FilteredList.java   |   4 +-
 .../juneau/commons/collections/FilteredMap.java    |   8 +-
 .../juneau/commons/collections/FilteredSet.java    |   4 +-
 .../apache/juneau/commons/collections/Lists.java   |   4 +-
 .../apache/juneau/commons/collections/Maps.java    |   8 +-
 .../apache/juneau/commons/collections/Sets.java    |   4 +-
 .../juneau/commons/collections/SimpleMap.java      |   4 +-
 .../juneau/commons/conversion/BasicConverter.java  |   2 +-
 .../juneau/commons/inject/BeanInstantiator.java    |  18 +-
 .../java/org/apache/juneau/commons/io/Console.java |  16 +-
 .../apache/juneau/commons/lang/StringFormat.java   | 256 +++-------------
 .../apache/juneau/commons/logging/LogRecord.java   |  15 +-
 .../org/apache/juneau/commons/logging/Logger.java  |  23 +-
 .../juneau/commons/reflect/AnnotationProvider.java |   8 +-
 .../apache/juneau/commons/reflect/ClassInfo.java   |  12 +-
 .../apache/juneau/commons/reflect/ElementInfo.java |   2 +-
 .../apache/juneau/commons/reflect/FieldInfo.java   |   4 +-
 .../juneau/commons/reflect/ParameterInfo.java      |   6 +-
 .../juneau/commons/reflect/ReflectionMap.java      |   6 +-
 .../juneau/commons/runtime/ManifestFile.java       |   4 +-
 .../apache/juneau/commons/settings/Settings.java   |   2 +-
 .../org/apache/juneau/commons/svl/ArgCoercer.java  |  10 +-
 .../apache/juneau/commons/svl/ScriptSegment.java   |   4 +-
 .../apache/juneau/commons/svl/TemplateSegment.java |   2 +-
 .../apache/juneau/commons/svl/TypedFunction.java   |   8 +-
 .../juneau/commons/svl/VarTemplateCompiler.java    |  10 +-
 .../commons/svl/functions/RandomFunctions.java     |   4 +-
 .../juneau/commons/time/GranularZonedDateTime.java |   2 +-
 .../juneau/commons/utils/AssertionUtils.java       |  12 +-
 .../juneau/commons/utils/CollectionUtils.java      |   6 +-
 .../org/apache/juneau/commons/utils/FileUtils.java |  14 +-
 .../org/apache/juneau/commons/utils/IoUtils.java   |   4 +-
 .../org/apache/juneau/commons/utils/Shorts.java    |  31 +-
 .../apache/juneau/commons/utils/StringUtils.java   |  96 +++---
 .../org/apache/juneau/commons/io/Console_Test.java |  63 ++--
 .../juneau/commons/lang/StringFormat_Test.java     | 340 +++++----------------
 .../commons/logging/LogRecordCapture_Test.java     |   2 +-
 .../juneau/commons/logging/LogRecord_Test.java     |  12 +-
 .../apache/juneau/commons/logging/Logger_Test.java |  30 +-
 .../commons/reflect/BeanRuntimeException_Test.java |   6 +-
 .../commons/reflect/ExecutableException_Test.java  |   4 +-
 .../juneau/commons/utils/AssertionUtils_Test.java  |   8 +-
 .../apache/juneau/commons/utils/Shorts_Test.java   |  47 ++-
 .../juneau/commons/utils/StringUtils_Test.java     |  14 +-
 .../juneau/commons/utils/ThrowableUtils_Test.java  |  30 +-
 .../java/org/apache/juneau/config/Section.java     |  12 +-
 .../apache/juneau/config/internal/ConfigMap.java   |  16 +-
 .../apache/juneau/config/store/ConfigStore.java    |   4 +-
 .../org/apache/juneau/config/store/FileStore.java  |   4 +-
 .../juneau/config/store/ProfileConfigStore.java    |   2 +-
 .../juneau/marshall/jena/RdfParserSession.java     |  14 +-
 .../juneau/marshall/jena/RdfSerializerSession.java |   4 +-
 .../marshall/jena/RdfStreamParserSession.java      |  12 +-
 .../apache/juneau/marshall/AnnotationApplier.java  |   6 +-
 .../apache/juneau/marshall/BeanDictionaryMap.java  |   4 +-
 .../org/apache/juneau/marshall/BeanRegistry.java   |   6 +-
 .../apache/juneau/marshall/BigNumberFormat.java    |   4 +-
 .../org/apache/juneau/marshall/BinaryFormat.java   |   4 +-
 .../org/apache/juneau/marshall/BitSetFormat.java   |   2 +-
 .../org/apache/juneau/marshall/BooleanFormat.java  |   2 +-
 .../org/apache/juneau/marshall/ClassFormat.java    |   2 +-
 .../java/org/apache/juneau/marshall/ClassMeta.java |   6 +-
 .../java/org/apache/juneau/marshall/Context.java   |  10 +-
 .../org/apache/juneau/marshall/CurrencyFormat.java |   6 +-
 .../org/apache/juneau/marshall/EnumFormat.java     |   2 +-
 .../org/apache/juneau/marshall/FloatFormat.java    |   8 +-
 .../marshall/InvalidDataConversionException.java   |   4 +-
 .../marshall/MarshalledPropertyPostProcessor.java  |   6 +-
 .../apache/juneau/marshall/MarshallingContext.java |  10 +-
 .../apache/juneau/marshall/MarshallingSession.java |   8 +-
 .../marshall/MarshallingTraverseSession.java       |   6 +-
 .../org/apache/juneau/marshall/UuidFormat.java     |   2 +-
 .../juneau/marshall/bson/BsonInputStream.java      |  12 +-
 .../juneau/marshall/bson/BsonOutputStream.java     |   2 +-
 .../juneau/marshall/cbor/CborInputStream.java      |  10 +-
 .../juneau/marshall/cbor/CborOutputStream.java     |   2 +-
 .../juneau/marshall/cbor/CborParserSession.java    |  12 +-
 .../juneau/marshall/cbor/CborTokenReader.java      |   8 +-
 .../juneau/marshall/collections/JsonList.java      |   8 +-
 .../juneau/marshall/collections/JsonMap.java       |   6 +-
 .../juneau/marshall/collections/JsonPointer.java   |   6 +-
 .../juneau/marshall/collections/MarshalledMap.java |   4 +-
 .../juneau/marshall/cp/ContextBeanCreator.java     |   4 +-
 .../org/apache/juneau/marshall/cp/Messages.java    |   2 +-
 .../apache/juneau/marshall/csv/CsvCellParser.java  |   2 +-
 .../juneau/marshall/csv/CsvParserSession.java      |   4 +-
 .../juneau/marshall/encoders/EncoderSet.java       |   6 +-
 .../juneau/marshall/hjson/HjsonParserSession.java  |  10 +-
 .../juneau/marshall/hocon/HoconParserSession.java  |   8 +-
 .../juneau/marshall/hocon/HoconResolver.java       |   8 +-
 .../juneau/marshall/html/HtmlParserSession.java    |  14 +-
 .../marshall/html/HtmlSerializerSession.java       |   4 +-
 .../org/apache/juneau/marshall/html/HtmlTag.java   |   4 +-
 .../juneau/marshall/httppart/HttpPartSchema.java   |  22 +-
 .../juneau/marshall/ini/IniParserSession.java      |   4 +-
 .../juneau/marshall/ini/IniSerializerSession.java  |   2 +-
 .../juneau/marshall/internal/DelegateBeanMap.java  |   4 +-
 .../org/apache/juneau/marshall/jcs/JcsWriter.java  |   4 +-
 .../juneau/marshall/json/JsonParserSession.java    |  30 +-
 .../juneau/marshall/json/JsonTokenReader.java      |  24 +-
 .../apache/juneau/marshall/json5/Json5List.java    |   8 +-
 .../org/apache/juneau/marshall/json5/Json5Map.java |   6 +-
 .../juneau/marshall/json5/Json5ParserSession.java  |   2 +-
 .../juneau/marshall/json5/Json5TokenReader.java    |   4 +-
 .../jsonschema/JsonSchemaGeneratorSession.java     |   4 +-
 .../juneau/marshall/jsonschema/SchemaUtils.java    |   4 +-
 .../marshall/markdown/MarkdownParserSession.java   |  12 +-
 .../marshall/msgpack/MsgPackInputStream.java       |   6 +-
 .../marshall/msgpack/MsgPackOutputStream.java      |   6 +-
 .../marshall/msgpack/MsgPackParserSession.java     |  18 +-
 .../marshall/msgpack/MsgPackTokenReader.java       |   6 +-
 .../juneau/marshall/oapi/OpenApiParserSession.java |  10 +-
 .../marshall/objecttools/NumberMatcherFactory.java |   6 +-
 .../juneau/marshall/objecttools/PathTraversal.java |  34 +--
 .../juneau/marshall/objecttools/SearchArgs.java    |   4 +-
 .../marshall/objecttools/TimeMatcherFactory.java   |   6 +-
 .../marshall/parquet/ParquetParserSession.java     |  16 +-
 .../marshall/parquet/ParquetSchemaBuilder.java     |   8 +-
 .../marshall/parquet/ParquetSerializerSession.java |   8 +-
 .../apache/juneau/marshall/parser/ParserPipe.java  |   6 +-
 .../juneau/marshall/parser/ParserSession.java      |  26 +-
 .../apache/juneau/marshall/parser/ParserSet.java   |   8 +-
 .../marshall/protobuf/ProtobufParserSession.java   |   2 +-
 .../juneau/marshall/protobuf/ProtobufReader.java   |   4 +-
 .../apache/juneau/marshall/protobuf/WireType.java  |   2 +-
 .../marshall/prototext/PrototextParserSession.java |   2 +-
 .../marshall/serializer/SerializeException.java    |   4 +-
 .../juneau/marshall/serializer/SerializerPipe.java |   4 +-
 .../marshall/serializer/SerializerSession.java     |   6 +-
 .../juneau/marshall/serializer/SerializerSet.java  |   8 +-
 .../juneau/marshall/sse/SseParserSession.java      |   2 +-
 .../juneau/marshall/sse/SseSerializerSession.java  |   4 +-
 .../marshall/stream/StreamingArrayRecord.java      |   2 +-
 .../apache/juneau/marshall/swap/ObjectSwap.java    |   6 +-
 .../apache/juneau/marshall/swap/SurrogateSwap.java |   4 +-
 .../juneau/marshall/toml/TomlParserSession.java    |   2 +-
 .../juneau/marshall/uon/UonParserSession.java      |  14 +-
 .../org/apache/juneau/marshall/uon/UonReader.java  |   8 +-
 .../org/apache/juneau/marshall/uon/UonWriter.java  |   4 +-
 .../urlencoding/UrlEncodingParserSession.java      |   6 +-
 .../org/apache/juneau/marshall/xml/Namespace.java  |   8 +-
 .../apache/juneau/marshall/xml/XmlBeanMeta.java    |  16 +-
 .../juneau/marshall/xml/XmlBeanPropertyMeta.java   |   6 +-
 .../juneau/marshall/xml/XmlParserSession.java      |  12 +-
 .../org/apache/juneau/marshall/xml/XmlUtils.java   |   4 +-
 .../juneau/marshall/yaml/YamlParserSession.java    |  20 +-
 .../org/apache/juneau/ComboRoundTrip_Tester.java   |  18 +-
 .../org/apache/juneau/ComboSerialize_Tester.java   |   6 +-
 .../org/apache/juneau/MarshalledConfig_Test.java   |  42 +--
 .../java/org/apache/juneau/MaxIndent_Test.java     |   4 +-
 .../java/org/apache/juneau/cp/Messages_Test.java   |   8 +
 .../marshall/ClassMetaRuntimeException_Test.java   |   2 +-
 .../juneau/marshall/html/BasicHtml_Test.java       |  16 +-
 .../httppart/SchemaValidationException_Test.java   |   4 +-
 .../marshall/json/JsonParserEdgeCases_Test.java    |   6 +-
 .../marshall/objecttools/PathTraversal_Test.java   |   4 +-
 .../marshall/serializer/UriResolution_Test.java    |   6 +-
 .../transforms/OneWayStringSwap_Tester.java        |   6 +-
 .../transforms/RoundTripObjectSwap_Tester.java     |  10 +-
 .../marshall/transforms/StringSwap_Tester.java     |  10 +-
 .../apache/juneau/marshall/xml/BasicXml_Test.java  |  14 +-
 .../marshall/xml/XmlIgnoreComments_Test.java       |  10 +-
 .../utils/UriContextResolutionCombo_Test.java      |   4 +-
 .../juneau/utils/UriContextUriCombo_Test.java      |  16 +-
 .../java/org/apache/juneau/BasicTestUtils.java     |   8 +-
 .../juneau/test/assertions/AssertionPredicate.java |   5 +-
 .../test/assertions/AssertionPredicates.java       |  31 +-
 .../test/assertions/BasicAssertionError.java       |  12 +-
 .../apache/juneau/test/bct/BasicBeanConverter.java |   8 +-
 .../org/apache/juneau/test/bct/BctAssertions.java  |  30 +-
 .../apache/juneau/test/bct/BctConfigExtension.java |   2 +-
 .../java/org/apache/juneau/test/bct/BctUtils.java  |   2 +-
 .../org/apache/juneau/test/bct/package-info.java   |   2 +-
 .../juneau/test/assertions/Messages.properties     | 130 ++++----
 .../juneau/test/assertions/AnyAssertion_Test.java  |   4 +-
 .../test/assertions/ArrayAssertion_Test.java       |   4 +-
 .../juneau/test/assertions/Assertion_Test.java     |   2 +-
 .../juneau/test/assertions/BeanAssertion_Test.java |   4 +-
 .../test/assertions/BeanListAssertion_Test.java    |   4 +-
 .../test/assertions/BooleanAssertion_Test.java     |   4 +-
 .../test/assertions/ByteArrayAssertion_Test.java   |   4 +-
 .../test/assertions/CollectionAssertion_Test.java  |   4 +-
 .../test/assertions/ComparableAssertion_Test.java  |   4 +-
 .../juneau/test/assertions/DateAssertion_Test.java |   4 +-
 .../test/assertions/IntegerAssertion_Test.java     |   4 +-
 .../juneau/test/assertions/ListAssertion_Test.java |   4 +-
 .../juneau/test/assertions/LongAssertion_Test.java |   4 +-
 .../juneau/test/assertions/MapAssertion_Test.java  |   4 +-
 .../test/assertions/ObjectAssertion_Test.java      |   4 +-
 .../assertions/PrimitiveArrayAssertion_Test.java   |   4 +-
 .../test/assertions/StringAssertion_Test.java      |   4 +-
 .../test/assertions/StringListAssertion_Test.java  |   4 +-
 .../test/assertions/ThrowableAssertion_Test.java   |   4 +-
 .../apache/juneau/test/assertions/Verify_Test.java |  10 +-
 .../test/assertions/VersionAssertion_Test.java     |   4 +-
 .../assertions/ZonedDateTimeAssertion_Test.java    |   4 +-
 .../apache/juneau/examples/bean/BeanExample.java   |   9 +-
 .../juneau/examples/bean/atom/AtomJsonExample.java |   8 +-
 .../apache/juneau/BasicRuntimeException_Test.java  |  24 +-
 .../test/java/org/apache/juneau/ComboInput.java    |   4 +-
 .../org/apache/juneau/ComboRoundTrip_Tester.java   |  18 +-
 .../org/apache/juneau/ComboSerialize_Tester.java   |   6 +-
 .../src/test/java/org/apache/juneau/TestUtils.java |   4 +-
 .../a/rttests/RoundTripLargeObjects_Test.java      |   6 +-
 .../http/classic/response/BadRequest_Test.java     |   6 +-
 .../http/classic/response/Conflict_Test.java       |   6 +-
 .../classic/response/ExpectationFailed_Test.java   |   6 +-
 .../classic/response/FailedDependency_Test.java    |   6 +-
 .../http/classic/response/Forbidden_Test.java      |   6 +-
 .../juneau/http/classic/response/Gone_Test.java    |   6 +-
 .../http/classic/response/HttpException_Test.java  |  10 +-
 .../response/HttpVersionNotSupported_Test.java     |   6 +-
 .../classic/response/InsufficentStorage_Test.java  |   6 +-
 .../classic/response/InternalServerError_Test.java |   6 +-
 .../http/classic/response/LengthRequired_Test.java |   6 +-
 .../juneau/http/classic/response/Locked_Test.java  |   6 +-
 .../http/classic/response/LoopDetected_Test.java   |   6 +-
 .../classic/response/MethodNotAllowed_Test.java    |   6 +-
 .../classic/response/MisdirectedRequest_Test.java  |   6 +-
 .../NetworkAuthenticationRequired_Test.java        |   6 +-
 .../http/classic/response/NotAcceptable_Test.java  |   6 +-
 .../http/classic/response/NotExtended_Test.java    |   6 +-
 .../http/classic/response/NotFound_Test.java       |   6 +-
 .../http/classic/response/NotImplemented_Test.java |   6 +-
 .../classic/response/PayloadTooLarge_Test.java     |   6 +-
 .../classic/response/PreconditionFailed_Test.java  |   6 +-
 .../response/PreconditionRequired_Test.java        |   6 +-
 .../classic/response/RangeNotSatisfiable_Test.java |   6 +-
 .../response/RequestHeaderFieldsTooLarge_Test.java |   6 +-
 .../classic/response/ServiceUnavailable_Test.java  |   6 +-
 .../classic/response/TooManyRequests_Test.java     |   6 +-
 .../http/classic/response/Unauthorized_Test.java   |   6 +-
 .../response/UnavailableForLegalReasons_Test.java  |   6 +-
 .../classic/response/UnprocessableEntity_Test.java |   6 +-
 .../response/UnsupportedMediaType_Test.java        |   6 +-
 .../classic/response/UpgradeRequired_Test.java     |   6 +-
 .../http/classic/response/UriTooLong_Test.java     |   6 +-
 .../response/VariantAlsoNegotiates_Test.java       |   6 +-
 .../client/classic/RestClient_BasicCalls_Test.java |   6 +-
 .../org/apache/juneau/rest/server/Path_Test.java   |  14 +-
 .../juneau/rest/server/ProblemMapper_Test.java     |  10 +-
 .../rest/server/RestOp_ClientVersion_Test.java     |  14 +-
 .../juneau/rest/server/RestOp_Throws_Test.java     | 136 ++++-----
 .../server/Rest_ProblemDetails_OptIn_Test.java     |   6 +-
 .../server/Rest_ProblemDetails_PerOp_Test.java     |   8 +-
 .../juneau/rest/server/arg/ArgException_Test.java  |   2 +-
 .../server/auth/AuthenticationException_Test.java  |   4 +-
 .../processor/AsyncResponseProcessor_Test.java     |   2 +-
 .../rest/server/servlet/RestServlet_Test.java      |   6 +-
 .../microservice/examples/DirectoryResource.java   |   4 +-
 .../juneau/microservice/examples/LogsResource.java |   4 +-
 .../examples/DirectoryResource_Action_Test.java    |   6 +-
 .../examples/LogsResource_Action_Test.java         |   6 +-
 .../microservice/jetty/JettyServerComponent.java   |   8 +-
 .../juneau/microservice/jetty/JettySettings.java   |   2 +-
 .../microservice/tomcat/TomcatServerComponent.java |   6 +-
 .../apache/juneau/microservice/Microservice.java   |   8 +-
 .../petstore/rest/PetFreemarkerViewResource.java   |   2 +-
 .../juneau/petstore/rest/PetHtmlResource.java      |   2 +-
 .../petstore/rest/PetMustacheViewResource.java     |   2 +-
 .../juneau/petstore/rest/PetSecureResource.java    |   2 +-
 .../juneau/petstore/rest/PetStoreResource.java     |  12 +-
 .../apache/juneau/petstore/service/PetStore.java   |   8 +-
 .../rest/client/classic/ResponseContent.java       |  10 +-
 .../juneau/rest/client/classic/ResponseHeader.java |   6 +-
 .../juneau/rest/client/classic/RestClient.java     |  12 +-
 .../juneau/rest/client/classic/RestRequest.java    |  18 +-
 .../juneau/rest/client/classic/RestResponse.java   |   2 +-
 .../juneau/rest/client/RecordStreamBody.java       |   4 +-
 .../apache/juneau/rest/client/ResponseBody.java    |   2 +-
 .../juneau/rest/client/remote/RemoteClient.java    |  12 +-
 .../apache/juneau/http/classic/HttpHeaders.java    |   4 +-
 .../org/apache/juneau/http/classic/HttpParts.java  |   4 +-
 .../http/classic/header/BasicIntegerHeader.java    |   4 +-
 .../http/classic/header/BasicLongHeader.java       |   4 +-
 .../juneau/http/classic/header/HeaderBeanMeta.java |   6 +-
 .../juneau/http/classic/header/HeaderList.java     |   4 +-
 .../apache/juneau/http/classic/header/IfRange.java |   4 +-
 .../juneau/http/classic/header/RetryAfter.java     |   4 +-
 .../http/classic/header/SerializedHeader.java      |   6 +-
 .../apache/juneau/http/classic/part/BasicPart.java |   4 +-
 .../juneau/http/classic/part/PartBeanMeta.java     |   6 +-
 .../apache/juneau/http/classic/part/PartList.java  |   4 +-
 .../juneau/http/classic/part/SerializedPart.java   |   6 +-
 .../http/classic/response/BasicHttpException.java  |   2 +-
 .../http/classic/response/BasicHttpResponse.java   |   2 +-
 .../juneau/http/MediaRanges_FindMatch_Test.java    |   4 +-
 .../classic/header/ContentType_Match_Test.java     |   4 +-
 .../classic/response/ClassicResponse_Test.java     |   2 +-
 .../apache/juneau/http/HttpProtocolVersion.java    |   4 +-
 .../apache/juneau/http/header/CacheControl.java    |   8 +-
 .../juneau/http/header/ContentDisposition.java     |   2 +-
 .../apache/juneau/http/header/ContentRange.java    |   6 +-
 .../org/apache/juneau/http/header/EntityTag.java   |   4 +-
 .../juneau/http/header/HttpIntegerHeader.java      |   2 +-
 .../apache/juneau/http/header/HttpLongHeader.java  |   2 +-
 .../org/apache/juneau/http/header/IfRange.java     |   2 +-
 .../java/org/apache/juneau/http/header/Range.java  |   8 +-
 .../org/apache/juneau/http/header/RetryAfter.java  |   2 +-
 .../org/apache/juneau/http/header/Warning.java     |   2 +-
 .../apache/juneau/http/part/HttpIntegerPart.java   |   2 +-
 .../org/apache/juneau/http/part/HttpLongPart.java  |   2 +-
 .../juneau/http/remote/RrpcInterfaceMeta.java      |   8 +-
 .../http/remote/RrpcInterfaceMethodMeta.java       |   8 +-
 .../juneau/httppart/bean/MethodInfoUtils.java      |  12 +-
 .../juneau/bean/rfc7807/ProblemAdapters_Test.java  |   6 +-
 .../apache/juneau/rest/mock/MockPathResolver.java  |   8 +-
 .../juneau/rest/mock/MockServletRequest.java       |   4 +-
 .../rest/server/auth/oidc/rp/EphemeralStore.java   |   4 +-
 .../auth/oidc/rp/IdTokenValidatorAdapter.java      |   4 +-
 .../server/auth/oidc/rp/InMemorySessionStore.java  |   2 +-
 .../rest/server/auth/oidc/rp/OidcRelyingParty.java |   6 +-
 .../auth/oidc/rp/SignedCookieSessionStore.java     |   4 +-
 .../server/reactive/ReactiveResponseProcessor.java |   4 +-
 .../view/freemarker/FreemarkerDispatcher.java      |   4 +-
 .../server/view/freemarker/FreemarkerView.java     |   6 +-
 .../view/freemarker/FreemarkerViewRenderer.java    |   2 +-
 .../juneau/rest/server/view/jsp/JspDispatcher.java |   4 +-
 .../juneau/rest/server/view/jsp/JspView.java       |   6 +-
 .../rest/server/view/jsp/JspViewRenderer.java      |   6 +-
 .../server/view/mustache/MustacheDispatcher.java   |   4 +-
 .../rest/server/view/mustache/MustacheView.java    |   6 +-
 .../server/view/mustache/MustacheViewRenderer.java |   2 +-
 .../server/view/thymeleaf/ThymeleafDispatcher.java |   4 +-
 .../rest/server/view/thymeleaf/ThymeleafView.java  |   6 +-
 .../view/thymeleaf/ThymeleafViewRenderer.java      |   2 +-
 .../apache/juneau/rest/server/RestChildren.java    |   2 +-
 .../org/apache/juneau/rest/server/RestContext.java |  36 +--
 .../org/apache/juneau/rest/server/RestEndCall.java |   4 +-
 .../apache/juneau/rest/server/RestOpInvoker.java   |   4 +-
 .../apache/juneau/rest/server/RestOperations.java  |   6 +-
 .../apache/juneau/rest/server/RestPostCall.java    |   2 +-
 .../org/apache/juneau/rest/server/RestPreCall.java |   2 +-
 .../org/apache/juneau/rest/server/RestRequest.java |  20 +-
 .../apache/juneau/rest/server/RestResponse.java    |   8 +-
 .../apache/juneau/rest/server/arg/DefaultArg.java  |   4 +-
 .../org/apache/juneau/rest/server/arg/PathArg.java |   2 +-
 .../juneau/rest/server/arg/RecordReaderArg.java    |   4 +-
 .../juneau/rest/server/arg/RecordWriterArg.java    |   4 +-
 .../juneau/rest/server/arg/TokenReaderArg.java     |   4 +-
 .../juneau/rest/server/arg/TokenWriterArg.java     |   4 +-
 .../juneau/rest/server/beans/BeanDescription.java  |   4 +-
 .../rest/server/converter/Introspectable.java      |   4 +-
 .../juneau/rest/server/guard/RateLimitGuard.java   |   2 +-
 .../rest/server/httppart/RequestContent.java       |   8 +-
 .../rest/server/httppart/RequestFormParamList.java |   4 +-
 .../rest/server/httppart/RequestHeaderList.java    |   4 +-
 .../rest/server/httppart/RequestHttpPart.java      |   4 +-
 .../rest/server/httppart/RequestPathParamList.java |   4 +-
 .../server/httppart/RequestQueryParamList.java     |   4 +-
 .../rest/server/management/LoggersMixin.java       |   2 +-
 .../rest/server/management/LoggersResource.java    |   2 +-
 .../openapi/BasicOpenApiProviderSession.java       |   2 +-
 .../server/processor/ProblemDetailsProcessor.java  |   4 +-
 .../server/processor/ResponseBeanProcessor.java    |   8 +-
 .../server/processor/ResponseProcessorList.java    |   4 +-
 .../server/processor/SerializedPojoProcessor.java  |   4 +-
 .../juneau/rest/server/remote/RrpcServlet.java     |   8 +-
 .../juneau/rest/server/rrpc/RrpcRestOpContext.java |   6 +-
 .../juneau/rest/server/servlet/RestServlet.java    |   4 +-
 .../juneau/rest/server/sse/SseResponseSupport.java |   3 +-
 .../juneau/rest/server/stats/MethodInvoker.java    |   4 +-
 .../swagger/BasicSwaggerProviderSession.java       |  46 +--
 .../apache/juneau/rest/server/util/RestUtils.java  |   8 +-
 .../juneau/rest/server/vars/RequestSwaggerVar.java |   6 +-
 .../server/auth/AuthenticationException_Test.java  |   4 +-
 402 files changed, 1783 insertions(+), 2063 deletions(-)

diff --git a/.gitignore b/.gitignore
index 79369d320b..e5d61d5b40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,7 +25,7 @@ AGENTS.md
 .cursor/
 /agents/
 /.claude/
-/todo/
+/.work/
 
 # Maven Shade Plugin generated files
 **/dependency-reduced-pom.xml
diff --git a/juneau-bean/juneau-bean-common/src/main/java/org/apache/juneau/bean/LinkString.java b/juneau-bean/juneau-bean-common/src/main/java/org/apache/juneau/bean/LinkString.java
index 543839beb4..7b6095d40b 100644
--- a/juneau-bean/juneau-bean-common/src/main/java/org/apache/juneau/bean/LinkString.java
+++ b/juneau-bean/juneau-bean-common/src/main/java/org/apache/juneau/bean/LinkString.java
@@ -18,8 +18,6 @@ package org.apache.juneau.bean;
 
 import static org.apache.juneau.commons.utils.Shorts.*;
 
-import java.text.*;
-
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.commons.httppart.*;
 import org.apache.juneau.marshall.html.*;
@@ -55,7 +53,7 @@ public class LinkString implements Comparable<LinkString> {
 	 *
 	 * @param name Corresponds to the text inside of the <xt>&lt;A&gt;</xt> element.
 	 * @param uri Corresponds to the value of the <xa>href</xa> attribute of the <xt>&lt;A&gt;</xt> element.
-	 * @param uriArgs Optional arguments for {@link MessageFormat} style arguments in the href.
+	 * @param uriArgs Optional printf-style ({@link String#format(String, Object...)}) arguments in the href.
 	 */
 	public LinkString(String name, String uri, Object...uriArgs) {
 		setName(name);
@@ -157,7 +155,7 @@ public class LinkString implements Comparable<LinkString> {
 	 * @param value
 	 * 	The new value for this property.
 	 * 	<br>Can be <jk>null</jk> to unset the property.
-	 * @param args {@link MessageFormat}-style arguments in the URL.
+	 * @param args Optional printf-style ({@link String#format(String, Object...)}) arguments in the URL.
 	 * @return This object.
 	 */
 	public LinkString setUri(String value, Object...args) {
diff --git a/juneau-bean/juneau-bean-common/src/test/java/org/apache/juneau/bean/common/LinkString_Test.java b/juneau-bean/juneau-bean-common/src/test/java/org/apache/juneau/bean/common/LinkString_Test.java
index 746316272c..58056aa1aa 100644
--- a/juneau-bean/juneau-bean-common/src/test/java/org/apache/juneau/bean/common/LinkString_Test.java
+++ b/juneau-bean/juneau-bean-common/src/test/java/org/apache/juneau/bean/common/LinkString_Test.java
@@ -39,7 +39,7 @@ class LinkString_Test extends TestBase {
 	}
 
 	@Test void a03_constructorWithFormatArgs() {
-		var a = new LinkString("Item", "/items/{0}", "abc");
+		var a = new LinkString("Item", "/items/%s", "abc");
 		assertEquals("Item", a.getName());
 		assertEquals("/items/abc", a.getUri().toString());
 	}
diff --git a/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalLink.java b/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalLink.java
index 6f49a56425..f1cf74980e 100644
--- a/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalLink.java
+++ b/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalLink.java
@@ -17,7 +17,7 @@
 package org.apache.juneau.bean.hal;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a HAL Link Object as defined by
@@ -231,6 +231,6 @@ public class HalLink {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalResource.java b/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalResource.java
index b777eafc62..8bb4fb1eee 100644
--- a/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalResource.java
+++ b/juneau-bean/juneau-bean-hal/src/main/java/org/apache/juneau/bean/hal/HalResource.java
@@ -24,7 +24,7 @@ import java.util.*;
 
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a HAL Resource Object as defined by
@@ -275,6 +275,6 @@ public class HalResource {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-html5/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java b/juneau-bean/juneau-bean-html5/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
index b2fba485a9..33f3552264 100644
--- a/juneau-bean/juneau-bean-html5/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
+++ b/juneau-bean/juneau-bean-html5/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
@@ -265,7 +265,7 @@ public class ComboRoundTrip_Tester<T> {
 		for (var v : verify) {
 			var s = v.apply(o);
 			if (ine(s)) {
-				throw new BasicAssertionError("Verification failed on test {0}/{1}: {2}", label, testName, s);
+				throw new BasicAssertionError("Verification failed on test %s/%s: %s", label, testName, s);
 			}
 		}
 	}
@@ -288,14 +288,14 @@ public class ComboRoundTrip_Tester<T> {
 				System.out.println(r);
 			}
 
-			assertEquals(exp, r, fs("{0}/{1} serialize-normal failed.", label, testName));
+			assertEquals(exp, r, fs("%s/%s serialize-normal failed.", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -312,14 +312,14 @@ public class ComboRoundTrip_Tester<T> {
 			o = postConvert.apply((T)o);
 			r = s.serializeToString(o);
 
-			assertEquals(exp, r, fs("{0}/{1} parse-normal failed", label, testName));
+			assertEquals(exp, r, fs("%s/%s parse-normal failed", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Throwable e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -340,7 +340,7 @@ public class ComboRoundTrip_Tester<T> {
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -355,14 +355,14 @@ public class ComboRoundTrip_Tester<T> {
 			var r = s.serializeToString(in.get());
 			var o = p.parse(r, type);
 			r = jsonForEquivalency.serialize(o);
-			assertEquals(exp, r, fs("{0}/{1} parse-normal failed on JSON equivalency", label, testName));
+			assertEquals(exp, r, fs("%s/%s parse-normal failed on JSON equivalency", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -371,4 +371,4 @@ public class ComboRoundTrip_Tester<T> {
 	public String toString() {
 		return "ComboRoundTripTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiDocument.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiDocument.java
index eff78c2d41..0278693d84 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiDocument.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiDocument.java
@@ -23,7 +23,7 @@ import java.util.*;
 
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents the top-level JSON:API document as defined by
@@ -254,6 +254,6 @@ public class JsonApiDocument {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiError.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiError.java
index f05d85533c..5c9f150e6e 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiError.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiError.java
@@ -20,7 +20,7 @@ import java.util.*;
 
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a JSON:API Error Object as defined by
@@ -206,6 +206,6 @@ public class JsonApiError {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiErrorSource.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiErrorSource.java
index 1dfb13b4ed..e6be8f8794 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiErrorSource.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiErrorSource.java
@@ -17,7 +17,7 @@
 package org.apache.juneau.bean.jsonapi;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents the {@code source} sub-object of a JSON:API Error Object.
@@ -95,6 +95,6 @@ public class JsonApiErrorSource {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiLink.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiLink.java
index 7f86c2900a..d598054159 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiLink.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiLink.java
@@ -19,7 +19,7 @@ package org.apache.juneau.bean.jsonapi;
 import java.util.*;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a JSON:API Link Object as defined by
@@ -193,6 +193,6 @@ public class JsonApiLink {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiRelationship.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiRelationship.java
index 97b17975ac..b841a88fc0 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiRelationship.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiRelationship.java
@@ -20,7 +20,7 @@ import java.util.*;
 
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a JSON:API Relationship Object as defined by
@@ -141,6 +141,6 @@ public class JsonApiRelationship {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResource.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResource.java
index ebe7d8b6ae..12b3126746 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResource.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResource.java
@@ -22,7 +22,7 @@ import java.util.*;
 
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a JSON:API Resource Object as defined by
@@ -226,6 +226,6 @@ public class JsonApiResource {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResourceIdentifier.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResourceIdentifier.java
index 508461ceec..e863b0b25d 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResourceIdentifier.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiResourceIdentifier.java
@@ -19,7 +19,7 @@ package org.apache.juneau.bean.jsonapi;
 import java.util.*;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents a JSON:API Resource Identifier Object as defined by
@@ -113,6 +113,6 @@ public class JsonApiResourceIdentifier {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiVersion.java b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiVersion.java
index df90f5e2ec..ed4976e01e 100644
--- a/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiVersion.java
+++ b/juneau-bean/juneau-bean-jsonapi/src/main/java/org/apache/juneau/bean/jsonapi/JsonApiVersion.java
@@ -19,7 +19,7 @@ package org.apache.juneau.bean.jsonapi;
 import java.util.*;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Represents the JSON:API top-level {@code jsonapi} member.
@@ -91,6 +91,6 @@ public class JsonApiVersion {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonpatch/src/main/java/org/apache/juneau/bean/jsonpatch/JsonPatchOperation.java b/juneau-bean/juneau-bean-jsonpatch/src/main/java/org/apache/juneau/bean/jsonpatch/JsonPatchOperation.java
index 7b428cc339..854ab1bf6f 100644
--- a/juneau-bean/juneau-bean-jsonpatch/src/main/java/org/apache/juneau/bean/jsonpatch/JsonPatchOperation.java
+++ b/juneau-bean/juneau-bean-jsonpatch/src/main/java/org/apache/juneau/bean/jsonpatch/JsonPatchOperation.java
@@ -17,7 +17,7 @@
 package org.apache.juneau.bean.jsonpatch;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Abstract base for a JSON Patch operation per
@@ -83,6 +83,6 @@ public abstract class JsonPatchOperation {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 }
diff --git a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchema.java b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchema.java
index 634bff0a37..4ef2aef362 100644
--- a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchema.java
+++ b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchema.java
@@ -28,7 +28,7 @@ import java.util.*;
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.commons.reflect.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 import org.apache.juneau.marshall.parser.*;
 import org.apache.juneau.marshall.serializer.*;
 import org.apache.juneau.marshall.swap.*;
@@ -1373,7 +1373,7 @@ public class JsonSchema {
 				this.additionalItemsSchemaArray = value2;
 				setMasterOn(this.additionalItemsSchemaArray);
 			} else {
-				throw brex(JsonSchemaProperty.class, "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  Boolean, JsonSchemaArray", cn(value));
+				throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in.  Must be one of the following:  Boolean, JsonSchemaArray", cn(value));
 			}
 		}
 		return this;
@@ -1399,7 +1399,7 @@ public class JsonSchema {
 				this.additionalPropertiesSchema = value2;
 				setMasterOn(this.additionalPropertiesSchema);
 			} else
-				throw brex(JsonSchemaProperty.class, "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  Boolean, JsonSchema", cn(value));
+				throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in.  Must be one of the following:  Boolean, JsonSchema", cn(value));
 		}
 		return this;
 	}
@@ -1751,7 +1751,7 @@ public class JsonSchema {
 				this.itemsSchemaArray = value2;
 				setMasterOn(this.itemsSchemaArray);
 			} else {
-				throw brex(JsonSchemaProperty.class, "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  JsonSchema, JsonSchemaArray", cn(value));
+				throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in.  Must be one of the following:  JsonSchema, JsonSchemaArray", cn(value));
 			}
 		}
 		return this;
@@ -2090,7 +2090,7 @@ public class JsonSchema {
 			else if (value instanceof JsonTypeArray value2)
 				this.typeJsonTypeArray = value2;
 			else
-				throw brex(JsonSchemaProperty.class, "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  SimpleType, SimpleTypeArray", cn(value));
+				throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in.  Must be one of the following:  SimpleType, SimpleTypeArray", cn(value));
 		}
 		return this;
 	}
@@ -2152,7 +2152,7 @@ public class JsonSchema {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 
 	private void setMasterOn(Collection<JsonSchema> ss) {
@@ -2231,4 +2231,4 @@ public class JsonSchema {
 		if (nn(else_))
 			else_.setMaster(master);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaBeanGenerator.java b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaBeanGenerator.java
index 2a561e0708..27f1de5bea 100644
--- a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaBeanGenerator.java
+++ b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaBeanGenerator.java
@@ -24,6 +24,7 @@ import java.lang.reflect.*;
 import org.apache.juneau.marshall.collections.*;
 import org.apache.juneau.marshall.json.*;
 import org.apache.juneau.marshall.jsonschema.*;
+import org.apache.juneau.marshall.marshaller.Json;
 import org.apache.juneau.marshall.parser.*;
 
 /**
@@ -131,7 +132,7 @@ public final class JsonSchemaBeanGenerator {
 	public static JsonSchema toBean(JsonMap schemaMap) {
 		assertArgNotNull("schemaMap", schemaMap);
 		try {
-			var json = JsonSerializer.DEFAULT.toString(schemaMap);
+			var json = Json.of(schemaMap);
 			return JsonParser.create().ignoreUnknownBeanProperties().build().parse(json, JsonSchema.class);
 		} catch (ParseException e) {
 			throw toRex(e);
diff --git a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaMap.java b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaMap.java
index 76c7276d0f..87252a5141 100644
--- a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaMap.java
+++ b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaMap.java
@@ -25,7 +25,7 @@ import java.net.*;
 import java.util.concurrent.*;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * A container for retrieving JSON {@link JsonSchema} objects by URI.
@@ -135,7 +135,7 @@ public abstract class JsonSchemaMap extends ConcurrentHashMap<URI,JsonSchema> {
 		try (var r = getReader(uri)) {
 			if (r == null)
 				return null;
-			return Json5Parser.DEFAULT.parse(r, JsonSchema.class);
+			return Json5.DEFAULT.read(r, JsonSchema.class);
 		} catch (Exception e) { // HTT - compiler-generated branch from try-with-resources null check
 			throw toRex(e);
 		}
diff --git a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaValidator.java b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaValidator.java
index f970da72aa..713bf22bae 100644
--- a/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaValidator.java
+++ b/juneau-bean/juneau-bean-jsonschema/src/main/java/org/apache/juneau/bean/jsonschema/JsonSchemaValidator.java
@@ -27,7 +27,7 @@ import java.util.regex.*;
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.commons.httppart.*;
 import org.apache.juneau.marshall.collections.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Validates values against a {@link JsonSchema} bean per the JSON Schema Draft 2020-12 specification.
@@ -108,8 +108,6 @@ import org.apache.juneau.marshall.json.*;
  */
 public final class JsonSchemaValidator implements PropertyValidator {
 
-	private static final JsonSerializer JSON_FOR_EQ = JsonSerializer.DEFAULT;
-
 	private final JsonSchema schema;
 	private final Pattern patternCache;
 
@@ -198,7 +196,7 @@ public final class JsonSchemaValidator implements PropertyValidator {
 			if (jsonEquals(e, value))
 				return;
 		}
-		throw new SchemaValidationException("Value ''{0}'' does not match one of the allowed enum values.", value);
+		throw new SchemaValidationException("Value '%s' does not match one of the allowed enum values.", value);
 	}
 
 	private static void validateConst(JsonSchema s, Object value) {
@@ -206,14 +204,14 @@ public final class JsonSchemaValidator implements PropertyValidator {
 		if (c == null)
 			return;  // const=null is indistinguishable from "not set" in the bean; treat as unset.
 		if (! jsonEquals(c, value))
-			throw new SchemaValidationException("Value ''{0}'' does not match required const ''{1}''.", value, c);
+			throw new SchemaValidationException("Value '%s' does not match required const '%s'.", value, c);
 	}
 
 	private static void validateType(JsonSchema s, Object value) {
 		var single = s.getTypeAsJsonType();
 		if (nn(single)) {
 			if (! matchesType(single, value))
-				throw new SchemaValidationException("Value of type ''{0}'' does not match expected schema type ''{1}''.", typeName(value), single);
+				throw new SchemaValidationException("Value of type '%s' does not match expected schema type '%s'.", typeName(value), single);
 			return;
 		}
 		var arr = s.getTypeAsJsonTypeArray();
@@ -223,7 +221,7 @@ public final class JsonSchemaValidator implements PropertyValidator {
 			if (matchesType(t, value))
 				return;
 		}
-		throw new SchemaValidationException("Value of type ''{0}'' does not match any expected schema types ''{1}''.", typeName(value), arr);
+		throw new SchemaValidationException("Value of type '%s' does not match any expected schema types '%s'.", typeName(value), arr);
 	}
 
 	@SuppressWarnings({
@@ -287,14 +285,14 @@ public final class JsonSchemaValidator implements PropertyValidator {
 		var maxL = s.getMaxLength();
 		var len = value.codePointCount(0, value.length());
 		if (nn(minL) && len < minL)
-			throw new SchemaValidationException("String length {0} is less than minLength {1}.", len, minL);
+			throw new SchemaValidationException("String length %s is less than minLength %s.", len, minL);
 		if (nn(maxL) && len > maxL)
-			throw new SchemaValidationException("String length {0} exceeds maxLength {1}.", len, maxL);
+			throw new SchemaValidationException("String length %s exceeds maxLength %s.", len, maxL);
 		var pattern = patternOverride;
 		if (pattern == null && nn(s.getPattern()))
 			pattern = Pattern.compile(s.getPattern());
 		if (pattern != null && ! pattern.matcher(value).find())
-			throw new SchemaValidationException("Value ''{0}'' does not match pattern ''{1}''.", value, s.getPattern());
+			throw new SchemaValidationException("Value '%s' does not match pattern '%s'.", value, s.getPattern());
 	}
 
 	// =================================================================================================================
@@ -309,21 +307,21 @@ public final class JsonSchemaValidator implements PropertyValidator {
 		try {
 			bd = toBigDecimal(value);
 		} catch (@SuppressWarnings("unused") NumberFormatException e) {
-			throw new SchemaValidationException("Value ''{0}'' is not a finite number.", value);
+			throw new SchemaValidationException("Value '%s' is not a finite number.", value);
 		}
 
 		if (nn(s.getMinimum()) && bd.compareTo(toBigDecimal(s.getMinimum())) < 0)
-			throw new SchemaValidationException("Value {0} is less than minimum {1}.", bd, s.getMinimum());
+			throw new SchemaValidationException("Value %s is less than minimum %s.", bd, s.getMinimum());
 		if (nn(s.getMaximum()) && bd.compareTo(toBigDecimal(s.getMaximum())) > 0)
-			throw new SchemaValidationException("Value {0} exceeds maximum {1}.", bd, s.getMaximum());
+			throw new SchemaValidationException("Value %s exceeds maximum %s.", bd, s.getMaximum());
 		if (nn(s.getExclusiveMinimum()) && bd.compareTo(toBigDecimal(s.getExclusiveMinimum())) <= 0)
-			throw new SchemaValidationException("Value {0} is not greater than exclusive minimum {1}.", bd, s.getExclusiveMinimum());
+			throw new SchemaValidationException("Value %s is not greater than exclusive minimum %s.", bd, s.getExclusiveMinimum());
 		if (nn(s.getExclusiveMaximum()) && bd.compareTo(toBigDecimal(s.getExclusiveMaximum())) >= 0)
-			throw new SchemaValidationException("Value {0} is not less than exclusive maximum {1}.", bd, s.getExclusiveMaximum());
+			throw new SchemaValidationException("Value %s is not less than exclusive maximum %s.", bd, s.getExclusiveMaximum());
 		if (nn(s.getMultipleOf())) {
 			var mof = toBigDecimal(s.getMultipleOf());
 			if (mof.signum() != 0 && bd.remainder(mof).compareTo(BigDecimal.ZERO) != 0)
-				throw new SchemaValidationException("Value {0} is not a multiple of {1}.", bd, mof);
+				throw new SchemaValidationException("Value %s is not a multiple of %s.", bd, mof);
 		}
 	}
 
@@ -336,9 +334,9 @@ public final class JsonSchemaValidator implements PropertyValidator {
 		var max = s.getMaxItems();
 		var size = value.size();
 		if (nn(min) && size < min)
-			throw new SchemaValidationException("Array size {0} is less than minItems {1}.", size, min);
+			throw new SchemaValidationException("Array size %s is less than minItems %s.", size, min);
 		if (nn(max) && size > max)
-			throw new SchemaValidationException("Array size {0} exceeds maxItems {1}.", size, max);
+			throw new SchemaValidationException("Array size %s exceeds maxItems %s.", size, max);
 		if (Boolean.TRUE.equals(s.getUniqueItems()) && hasDuplicates(value))
 			throw new SchemaValidationException("Array contains duplicate items but uniqueItems is true.");
 		var items = s.getItemsAsSchema();
@@ -382,14 +380,14 @@ public final class JsonSchemaValidator implements PropertyValidator {
 		var maxP = s.getMaxProperties();
 		var size = value.size();
 		if (nn(minP) && size < minP)
-			throw new SchemaValidationException("Object property count {0} is less than minProperties {1}.", size, minP);
+			throw new SchemaValidationException("Object property count %s is less than minProperties %s.", size, minP);
 		if (nn(maxP) && size > maxP)
-			throw new SchemaValidationException("Object property count {0} exceeds maxProperties {1}.", size, maxP);
+			throw new SchemaValidationException("Object property count %s exceeds maxProperties %s.", size, maxP);
 		var required = s.getRequired();
 		if (nn(required)) {
 			for (var key : required) {
 				if (! value.containsKey(key))
-					throw new SchemaValidationException("Required property ''{0}'' is missing.", key);
+					throw new SchemaValidationException("Required property '%s' is missing.", key);
 			}
 		}
 		var props = s.getProperties();
@@ -440,7 +438,7 @@ public final class JsonSchemaValidator implements PropertyValidator {
 		if (a.equals(b))
 			return true;
 		try {
-			return JSON_FOR_EQ.toString(a).equals(JSON_FOR_EQ.toString(b));
+			return Json.of(a).equals(Json.of(b));
 		} catch (@SuppressWarnings("unused") Exception e) {
 			return false;
 		}
diff --git a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
index f45be322f4..c854b503b7 100644
--- a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
+++ b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
@@ -28,7 +28,7 @@ import java.util.*;
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.commons.collections.*;
 import org.apache.juneau.marshall.collections.*;
-import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * A limited subset of JSON-Schema's items object.
@@ -478,7 +478,7 @@ public class Items extends OpenApiElement {
 	 */
 	public Items setCollectionFormat(String value) {
 		if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
-			throw rex("Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_COLLECTION_FORMATS));
+			throw rex("Invalid value passed in to setCollectionFormat(String).  Value='%s', valid values=[%s]", value, toCdl(VALID_COLLECTION_FORMATS));
 		collectionFormat = value;
 		return this;
 	}
@@ -752,7 +752,7 @@ public class Items extends OpenApiElement {
 	 */
 	public Items setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw iaex("Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}", value, Json5Serializer.DEFAULT.toString(VALID_TYPES));
+			throw iaex("Invalid value passed in to setType(String).  Value='%s', valid values=%s", value, Json5.of(VALID_TYPES));
 		type = value;
 		return this;
 	}
@@ -804,4 +804,4 @@ public class Items extends OpenApiElement {
 		super.strict();
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
index 282bf6aa9a..7e91cf5b8a 100644
--- a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
+++ b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
@@ -24,7 +24,7 @@ import static org.apache.juneau.marshall.internal.ConverterUtils.*;
 import java.util.*;
 
 import org.apache.juneau.commons.collections.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 import org.apache.juneau.marshall.objecttools.*;
 
 /**
@@ -275,11 +275,11 @@ public class OpenApi extends OpenApiElement {
 		assertArgNotNullOrBlank(ARG_ref, ref);
 		assertArgNotNull(ARG_c, c);
 		if (! ref.startsWith("#/"))
-			throw rex("Unsupported reference:  ''{0}''", ref);
+			throw rex("Unsupported reference:  '%s'", ref);
 		try {
 			return new PathTraversal(this).get(ref.substring(1), c);
 		} catch (Exception e) {
-			throw brex(e, c, "Reference ''{0}'' could not be converted to type ''{1}''.", ref, cn(c));
+			throw brex(e, c, "Reference '%s' could not be converted to type '%s'.", ref, cn(c));
 		}
 	}
 
@@ -515,6 +515,6 @@ public class OpenApi extends OpenApiElement {
 
 	@Override
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
index 85c03fe1e2..08e3f2046a 100644
--- a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
+++ b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApiElement.java
@@ -26,7 +26,7 @@ import java.util.*;
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.*;
 import org.apache.juneau.marshall.collections.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Root class for all Swagger beans.
@@ -134,7 +134,7 @@ public abstract class OpenApiElement {
 	public OpenApiElement set(String property, Object value) {
 		assertArgNotNull(ARG_property, property);
 		if (strict)
-			throw rex("Cannot set property ''{0}'' in strict mode.", property);
+			throw rex("Cannot set property '%s' in strict mode.", property);
 		if (extra == null)
 			extra = map();
 		extra.put(property, value);
@@ -143,7 +143,7 @@ public abstract class OpenApiElement {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 
 	/**
@@ -176,4 +176,4 @@ public abstract class OpenApiElement {
 		strict = nn(value) && toBoolean(value);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
index 5464114b53..8326935d5f 100644
--- a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
+++ b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
@@ -383,7 +383,7 @@ public class Parameter extends OpenApiElement {
 	 */
 	public Parameter setIn(String value) {
 		if (isStrict() && ! contains(value, VALID_IN))
-			throw rex("Invalid value passed in to setIn(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_IN));
+			throw rex("Invalid value passed in to setIn(String).  Value='%s', valid values=%s", value, Json5.of(VALID_IN));
 		in = value;
 		return this;
 	}
@@ -429,7 +429,7 @@ public class Parameter extends OpenApiElement {
 	 */
 	public Parameter setStyle(String value) {
 		if (isStrict() && ! contains(value, VALID_STYLES))
-			throw rex("Invalid value passed in to setStyle(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_STYLES));
+			throw rex("Invalid value passed in to setStyle(String).  Value='%s', valid values=%s", value, Json5.of(VALID_STYLES));
 		style = value;
 		return this;
 	}
@@ -445,4 +445,4 @@ public class Parameter extends OpenApiElement {
 		super.strict(value);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
index 2249b6381e..7210e707d7 100644
--- a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
+++ b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
@@ -363,7 +363,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 */
 	public SecuritySchemeInfo setIn(String value) {
 		if (isStrict() && ! contains(value, VALID_IN))
-			throw rex("Invalid value passed in to setIn(String).  Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_IN));
+			throw rex("Invalid value passed in to setIn(String).  Value='%s', valid values=[%s]", value, toCdl(VALID_IN));
 		in = value;
 		return this;
 	}
@@ -453,7 +453,7 @@ public class SecuritySchemeInfo extends OpenApiElement {
 	 */
 	public SecuritySchemeInfo setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw rex("Invalid value passed in to setType(String).  Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_TYPES));
+			throw rex("Invalid value passed in to setType(String).  Value='%s', valid values=[%s]", value, toCdl(VALID_TYPES));
 		type = value;
 		return this;
 	}
@@ -469,4 +469,4 @@ public class SecuritySchemeInfo extends OpenApiElement {
 		super.strict();
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/HeaderInfo.java b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/HeaderInfo.java
index b8e27e5cf6..9b2e473b8e 100644
--- a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/HeaderInfo.java
+++ b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/HeaderInfo.java
@@ -496,7 +496,7 @@ public class HeaderInfo extends SwaggerElement {
 	 */
 	public HeaderInfo setCollectionFormat(String value) {
 		if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
-			throw rex("Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_COLLECTION_FORMATS));
+			throw rex("Invalid value passed in to setCollectionFormat(String).  Value='%s', valid values=%s", value, Json5.of(VALID_COLLECTION_FORMATS));
 		collectionFormat = value;
 		return this;
 	}
@@ -780,7 +780,7 @@ public class HeaderInfo extends SwaggerElement {
 	 */
 	public HeaderInfo setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw rex("Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_TYPES));
+			throw rex("Invalid value passed in to setType(String).  Value='%s', valid values=%s", value, Json5.of(VALID_TYPES));
 		type = value;
 		return this;
 	}
@@ -803,4 +803,4 @@ public class HeaderInfo extends SwaggerElement {
 		super.strict();
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Items.java b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Items.java
index a5fa4760bb..454a142ddc 100644
--- a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Items.java
+++ b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Items.java
@@ -469,7 +469,7 @@ public class Items extends SwaggerElement {
 	 */
 	public Items setCollectionFormat(String value) {
 		if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
-			throw rex("Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_COLLECTION_FORMATS));
+			throw rex("Invalid value passed in to setCollectionFormat(String).  Value='%s', valid values=%s", value, Json5.of(VALID_COLLECTION_FORMATS));
 		collectionFormat = value;
 		return this;
 	}
@@ -724,7 +724,7 @@ public class Items extends SwaggerElement {
 	 */
 	public Items setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw rex("Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_TYPES));
+			throw rex("Invalid value passed in to setType(String).  Value='%s', valid values=%s", value, Json5.of(VALID_TYPES));
 		type = value;
 		return this;
 	}
@@ -762,4 +762,4 @@ public class Items extends SwaggerElement {
 		super.strict(value);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ParameterInfo.java b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ParameterInfo.java
index e9d152a7da..1498969d02 100644
--- a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ParameterInfo.java
+++ b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/ParameterInfo.java
@@ -720,7 +720,7 @@ public class ParameterInfo extends SwaggerElement {
 	 */
 	public ParameterInfo setCollectionFormat(String value) {
 		if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
-			throw rex("Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_COLLECTION_FORMATS));
+			throw rex("Invalid value passed in to setCollectionFormat(String).  Value='%s', valid values=%s", value, Json5.of(VALID_COLLECTION_FORMATS));
 		collectionFormat = value;
 		return this;
 	}
@@ -881,7 +881,7 @@ public class ParameterInfo extends SwaggerElement {
 	 */
 	public ParameterInfo setIn(String value) {
 		if (isStrict() && ! contains(value, VALID_IN))
-			throw rex("Invalid value passed in to setIn(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_IN));
+			throw rex("Invalid value passed in to setIn(String).  Value='%s', valid values=%s", value, Json5.of(VALID_IN));
 		in = value;
 		if ("path".equals(value))
 			required = true;
@@ -1082,7 +1082,7 @@ public class ParameterInfo extends SwaggerElement {
 	 */
 	public ParameterInfo setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw rex("Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_TYPES));
+			throw rex("Invalid value passed in to setType(String).  Value='%s', valid values=%s", value, Json5.of(VALID_TYPES));
 		type = value;
 		return this;
 	}
@@ -1118,4 +1118,4 @@ public class ParameterInfo extends SwaggerElement {
 		super.strict(value);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
index 27ed5e2e3d..00a8a02a16 100644
--- a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
+++ b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SecurityScheme.java
@@ -440,7 +440,7 @@ public class SecurityScheme extends SwaggerElement {
 	 */
 	public SecurityScheme setType(String value) {
 		if (isStrict() && ! contains(value, VALID_TYPES))
-			throw rex("Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_TYPES));
+			throw rex("Invalid value passed in to setType(String).  Value='%s', valid values=%s", value, Json5.of(VALID_TYPES));
 		type = value;
 		return this;
 	}
@@ -465,4 +465,4 @@ public class SecurityScheme extends SwaggerElement {
 		super.strict(value);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
index 3e164ca3be..f613c5c039 100644
--- a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
+++ b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
@@ -26,7 +26,7 @@ import java.util.*;
 import org.apache.juneau.commons.collections.*;
 import org.apache.juneau.commons.http.*;
 import org.apache.juneau.marshall.collections.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 import org.apache.juneau.marshall.objecttools.*;
 
 /**
@@ -511,11 +511,11 @@ public class Swagger extends SwaggerElement {
 		assertArgNotNullOrBlank(ARG_ref, ref);
 		assertArgNotNull(ARG_c, c);
 		if (! ref.startsWith("#/"))
-			throw rex("Unsupported reference:  ''{0}''", ref);
+			throw rex("Unsupported reference:  '%s'", ref);
 		try {
 			return new PathTraversal(this).get(ref.substring(1), c);
 		} catch (Exception e) {
-			throw brex(e, c, "Reference ''{0}'' could not be converted to type ''{1}''.", ref, cn(c));
+			throw brex(e, c, "Reference '%s' could not be converted to type '%s'.", ref, cn(c));
 		}
 	}
 
@@ -1190,6 +1190,6 @@ public class Swagger extends SwaggerElement {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SwaggerElement.java b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SwaggerElement.java
index 7a641377aa..b8b1a0a24d 100644
--- a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SwaggerElement.java
+++ b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/SwaggerElement.java
@@ -25,7 +25,7 @@ import java.util.*;
 
 import org.apache.juneau.commons.bean.*;
 import org.apache.juneau.marshall.collections.*;
-import org.apache.juneau.marshall.json.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Root class for all Swagger beans.
@@ -135,7 +135,7 @@ public abstract class SwaggerElement {
 	public SwaggerElement set(String property, Object value) {
 		assertArgNotNull(ARG_property, property);
 		if (strict)
-			throw rex("Cannot set property ''{0}'' in strict mode.", property);
+			throw rex("Cannot set property '%s' in strict mode.", property);
 		if (extra == null)
 			extra = map();
 		extra.put(property, value);
@@ -144,7 +144,7 @@ public abstract class SwaggerElement {
 
 	@Override /* Overridden from Object */
 	public String toString() {
-		return JsonSerializer.DEFAULT.toString(this);
+		return Json.of(this);
 	}
 
 	/**
@@ -177,4 +177,4 @@ public abstract class SwaggerElement {
 		strict = toBoolean(value);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/InvalidAnnotationException.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/InvalidAnnotationException.java
index ca5bf5b24c..6790416b67 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/InvalidAnnotationException.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/InvalidAnnotationException.java
@@ -48,7 +48,7 @@ public class InvalidAnnotationException extends BasicRuntimeException {
 			.filter(Objects::nonNull)
 			.findFirst()
 			.ifPresent(a -> {
-				throw new InvalidAnnotationException("@{0} annotation cannot be used in a @{1} bean.  Method=''{2}''", cns(a), cns(onMethod.getDeclaringClass()), onMethod);
+				throw new InvalidAnnotationException("@%s annotation cannot be used in a @%s bean.  Method='%s'", cns(a), cns(onMethod.getDeclaringClass()), onMethod);
 			});
 		// @formatter:on
 	}
@@ -68,4 +68,4 @@ public class InvalidAnnotationException extends BasicRuntimeException {
 		super.setMessage(message, args);
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMap.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMap.java
index ecffa3134a..45cc784936 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMap.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMap.java
@@ -172,7 +172,7 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T
 		if (p == null) {
 			if (meta.getConfig().isIgnoreUnknownBeanProperties())
 				return;
-			throw brex(meta.getClassInfo(), "Bean property ''{0}'' not found.", property);
+			throw brex(meta.getClassInfo(), "Bean property '%s' not found.", property);
 		}
 		p.add(this, property, value);
 	}
@@ -520,7 +520,7 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T
 				propertyCache.forEach(this::put);
 				propertyCache = null;
 			} catch (IllegalArgumentException e) {
-				throw brex(e, meta.getBeanInfo().inner(), "IllegalArgumentException occurred on call to class constructor ''{0}'' with argument types ''{1}''", c.getNameSimple(),
+				throw brex(e, meta.getBeanInfo().inner(), "IllegalArgumentException occurred on call to class constructor '%s' with argument types '%s'", c.getNameSimple(),
 					Arrays.toString(getClasses(args)));
 			} catch (Exception e) {
 				throw brex(e);
@@ -735,7 +735,7 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T
 
 			p = getPropertyMeta("*");
 			if (p == null)
-				throw brex(meta.getClassInfo(), "Bean property ''{0}'' not found.", property);
+				throw brex(meta.getClassInfo(), "Bean property '%s' not found.", property);
 		}
 		return p.set(this, property, value);
 	}
@@ -800,4 +800,4 @@ public class BeanMap<T> extends AbstractMap<String,Object> implements Delegate<T
 	public int hashCode() {
 		return entrySet().hashCode();
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java
index 65dcaaa922..b69b61e2b8 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMeta.java
@@ -537,7 +537,7 @@ public class BeanMeta<T> {
 			}
 
 			// Check for missing properties.
-			fixedBeanProps.stream().filter(x -> ! normalProps.containsKey(x)).findFirst().ifPresent(x -> { throw brex(c, "The property ''{0}'' was defined on the @BeanType(properties=X) annotation of class ''{1}'' but was not found on the class definition.", x, ci.getNameSimple()); });
+			fixedBeanProps.stream().filter(x -> ! normalProps.containsKey(x)).findFirst().ifPresent(x -> { throw brex(c, "The property '%s' was defined on the @BeanType(properties=X) annotation of class '%s' but was not found on the class definition.", x, ci.getNameSimple()); });
 
 			// For records with renamed properties, remap constructor args to use the actual property names.
 			if (ci.isRecord() && ine(beanConstructor.args())) {
@@ -565,7 +565,7 @@ public class BeanMeta<T> {
 			for (var fp : beanConstructor.args()) {
 				var m = normalProps.get(fp);
 				if (m == null)
-					throw brex(c, "The property ''{0}'' was defined on the @BeanCtor(properties=X) annotation but was not found on the class definition.", fp);
+					throw brex(c, "The property '%s' was defined on the @BeanCtor(properties=X) annotation but was not found on the class definition.", fp);
 				m.setAsConstructorArg();
 			}
 
@@ -1159,7 +1159,7 @@ public class BeanMeta<T> {
 				args = con.getParameters().stream().map(x -> x.getName()).toList();
 				for (int i = 0; i < args.size(); i++) {
 					if (isBlank(args.get(i)))
-						throw brex(ci, "Could not find name for parameter #{0} of constructor ''{1}''", i, con.getNameFull());
+						throw brex(ci, "Could not find name for parameter #%s of constructor '%s'", i, con.getNameFull());
 				}
 			}
 			return new BeanConstructor(o(con), args);
@@ -1383,7 +1383,7 @@ public class BeanMeta<T> {
 				n = pn.getPropertyName(n);
 
 				if ("*".equals(bpName) && methodType == UNKNOWN)
-					throw brex(ci, "Found @BeanProp(\"*\") but could not determine method type on method ''{0}''.", m.getNameSimple());
+					throw brex(ci, "Found @BeanProp(\"*\") but could not determine method type on method '%s'.", m.getNameSimple());
 
 				if (methodType != UNKNOWN) {
 					if (nn(bpName) && ! bpName.isEmpty())
@@ -1658,4 +1658,4 @@ public class BeanMeta<T> {
 			.findFirst();
 		// @formatter:on
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanPropertyMeta.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanPropertyMeta.java
index c1b68a18f0..ed58788f2d 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanPropertyMeta.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanPropertyMeta.java
@@ -90,7 +90,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 	private static final String ARG_innerField = "innerField";
 
 	// Error message constants
-	private static final String MSG_getterOrFieldNotDefined = "Getter or public field not defined on property ''{0}''";
+	private static final String MSG_getterOrFieldNotDefined = "Getter or public field not defined on property '%s'";
 
 	/**
 	 * BeanPropertyMeta builder class.
@@ -607,7 +607,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 	public void add(BeanMap<?> m, String pName, Object value) throws BeanRuntimeException {
 
 		if (rawTypeMeta == null)
-			throw uoex("Property ''{0}'' was built via the bean-modeling-only path; Collection/array add operations require a marshalling context.", name);
+			throw uoex("Property '%s' was built via the bean-modeling-only path; Collection/array add operations require a marshalling context.", name);
 
 		// Read-only beans get their properties stored in a cache.
 		if (m.bean == null) {
@@ -623,7 +623,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 		var isArray = rawTypeMeta.isArray();
 
 		if (! (isCollection || isArray))
-			throw brex(beanMeta.getBeanInfo(), "Attempt to add element to property ''{0}'' which is not a collection or array", name);
+			throw brex(beanMeta.getBeanInfo(), "Attempt to add element to property '%s' which is not a collection or array", name);
 
 		var bean = m.getBean(true);
 
@@ -710,7 +710,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 	public void add(BeanMap<?> m, String pName, String key, Object value) throws BeanRuntimeException {
 
 		if (rawTypeMeta == null)
-			throw uoex("Property ''{0}'' was built via the bean-modeling-only path; Map/bean add operations require a marshalling context.", name);
+			throw uoex("Property '%s' was built via the bean-modeling-only path; Map/bean add operations require a marshalling context.", name);
 
 		// Read-only beans get their properties stored in a cache.
 		if (m.bean == null) {
@@ -726,7 +726,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 		var isBean = rawTypeMeta.isBean();
 
 		if (! (isBean || isMap))
-			throw brex(beanMeta.getBeanInfo(), "Attempt to add key/value to property ''{0}'' which is not a map or bean", name);
+			throw brex(beanMeta.getBeanInfo(), "Attempt to add key/value to property '%s' which is not a map or bean", name);
 
 		var bean = m.getBean(true);
 
@@ -1017,7 +1017,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 				return rawTypeMeta.getPrimitiveDefault();
 			return null;
 		}
-		throw brex(e, beanMeta.getClassInfo(), "Exception occurred while getting property ''{0}''", name);
+		throw brex(e, beanMeta.getClassInfo(), "Exception occurred while getting property '%s'", name);
 	}
 	}
 
@@ -1142,7 +1142,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 			if ((! isDyna) && field == null && setter == null && ! (isMap || isCollection)) {
 				if ((value1 == null && config.isIgnoreUnknownNullBeanProperties()) || config.isIgnoreMissingSetters())
 					return null;
-				throw brex(beanMeta.getClassInfo(), "Setter or public field not defined on property ''{0}''", name);
+				throw brex(beanMeta.getClassInfo(), "Setter or public field not defined on property '%s'", name);
 			}
 
 			var bean = m.getBean(true);  // Don't use getBean() because it triggers array creation!
@@ -1180,7 +1180,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					if (value1 instanceof CharSequence value21)
 						value1 = session.parseToMap(value21);
 					else
-						throw brex(beanMeta.getBeanInfo(), "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}''", name, propertyClass.getName(), cn(value1));
+						throw brex(beanMeta.getBeanInfo(), "Cannot set property '%s' of type '%s' to object of type '%s'", name, propertyClass.getName(), cn(value1));
 				}
 
 				var valueMap = (Map)value1;
@@ -1194,7 +1194,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					if (propMap == null) {
 						if (setter == null && field == null)
 							throw brex(beanMeta.getBeanInfo(),
-								"Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined, and the current value is null", name,
+								"Cannot set property '%s' of type '%s' to object of type '%s' because no setter or public field is defined, and the current value is null", name,
 								propertyClass.getName(), cn(value1));
 
 						if (propertyClass.isInstance(valueMap)) {
@@ -1214,7 +1214,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 							return r;
 						}
 						throw brex(beanMeta.getBeanInfo(),
-							"Cannot set property ''{0}'' of type ''{2}'' to object of type ''{2}'' because the assigned map cannot be converted to the specified type because the property type is abstract, and the property value is currently null",
+							"Cannot set property '%1$s' of type '%3$s' to object of type '%3$s' because the assigned map cannot be converted to the specified type because the property type is abstract, and the property value is currently null",
 							name, propertyClass.getName(), cn(value1));
 					}
 				} else {
@@ -1244,7 +1244,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					if (value1 instanceof CharSequence value2)
 						value1 = session.parseToList(value2);
 					else
-						throw brex(beanMeta.getBeanInfo(), "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}''", name, propertyClass.getName(), cn(value1));
+						throw brex(beanMeta.getBeanInfo(), "Cannot set property '%s' of type '%s' to object of type '%s'", name, propertyClass.getName(), cn(value1));
 				}
 
 				var valueList = (Collection)value1;
@@ -1257,7 +1257,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					if (propList == null) {
 						if (setter == null && field == null)
 							throw brex(beanMeta.getBeanInfo(),
-								"Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined, and the current value is null", name,
+								"Cannot set property '%s' of type '%s' to object of type '%s' because no setter or public field is defined, and the current value is null", name,
 								propertyClass.getName(), cn(value1));
 
 						if (propertyClass.isInstance(valueList) || (nn(setter) && setter.getParameterTypes().get(0).is(Collection.class))) {
@@ -1314,7 +1314,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					return rawTypeMeta.getPrimitiveDefault();
 				return null;
 			}
-			throw brex(e1, beanMeta.getBeanInfo(), "Error occurred trying to set property ''{0}''", name);
+			throw brex(e1, beanMeta.getBeanInfo(), "Error occurred trying to set property '%s'", name);
 		}
 	}
 
@@ -1359,7 +1359,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					return rawTypeMeta.getPrimitiveDefault();
 				return null;
 			}
-			throw brex(e, beanMeta.getClassInfo(), "Exception occurred while getting property ''{0}''", name);
+			throw brex(e, beanMeta.getClassInfo(), "Exception occurred while getting property '%s'", name);
 		}
 	}
 
@@ -1393,7 +1393,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 			else if (nn(getter))
 				m = (Map<String,Object>)getter.invoke(bean);
 			else
-				throw brex(beanMeta.getClassInfo(), "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter is defined on this property, and the existing property value is null",
+				throw brex(beanMeta.getClassInfo(), "Cannot set property '%s' of type '%s' to object of type '%s' because no setter is defined on this property, and the existing property value is null",
 					name, classNameForError(), cn(val));
 			return (m == null ? null : m.put(pName, val));
 		}
@@ -1403,7 +1403,7 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 			field.set(bean, val);
 			return null;
 		}
-		throw brex(beanMeta.getClassInfo(), "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter is defined on this property, and the existing property value is null", name,
+		throw brex(beanMeta.getClassInfo(), "Cannot set property '%s' of type '%s' to object of type '%s' because no setter is defined on this property, and the existing property value is null", name,
 			classNameForError(), cn(val));
 	}
 
@@ -1491,8 +1491,8 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 	 */
 	protected void setArray(Object bean, List l) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
 		if (rawTypeMeta == null)
-			throw uoex("Property ''{0}'' was built via the bean-modeling-only path; setArray requires a marshalling context.", name);
+			throw uoex("Property '%s' was built via the bean-modeling-only path; setArray requires a marshalling context.", name);
 		var array = toArray(l, this.rawTypeMeta.getElementType().inner());
 		invokeSetter(bean, name, array);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProxyInvocationHandler.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProxyInvocationHandler.java
index f7474c307c..fbcd3fe57d 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProxyInvocationHandler.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanProxyInvocationHandler.java
@@ -158,6 +158,6 @@ public class BeanProxyInvocationHandler<T> implements InvocationHandler {
 			return null;
 		}
 
-		throw uoex("Unsupported bean method.  method=''{0}''", method);
+		throw uoex("Unsupported bean method.  method='%s'", method);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java
index e7047177e3..2d237eb200 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java
@@ -128,7 +128,7 @@ public class BidiMap<K,V> implements Map<K,V> {
 					// Key is being overwritten with a different value, remove old value from tracking
 					values.remove(existingValue);
 				}
-				assertArg(! (values.contains(value) && ! value.equals(existingValue)), "Value ''{0}'' is already mapped to a different key in this BidiMap.", value);
+				assertArg(! (values.contains(value) && ! value.equals(existingValue)), "Value '%s' is already mapped to a different key in this BidiMap.", value);
 				values.add(value);
 			}
 			map.put(key, value);
@@ -304,7 +304,7 @@ public class BidiMap<K,V> implements Map<K,V> {
 	@Override /* Map */
 	public V put(K key, V value) {
 		var existingKeyForValue = reverse.get(value);
-		assertArg(! (nn(existingKeyForValue) && ! existingKeyForValue.equals(key)), "Value ''{0}'' is already mapped to key ''{1}'' in this BidiMap.", value, existingKeyForValue);
+		assertArg(! (nn(existingKeyForValue) && ! existingKeyForValue.equals(key)), "Value '%s' is already mapped to key '%s' in this BidiMap.", value, existingKeyForValue);
 		var oldValue = forward.put(key, value);
 		if (nn(oldValue)) {
 			reverse.remove(oldValue);
@@ -330,7 +330,7 @@ public class BidiMap<K,V> implements Map<K,V> {
 			var key = entry.getKey();
 			var value = entry.getValue();
 			var existingKeyForValue = reverse.get(value);
-			assertArg(! (nn(existingKeyForValue) && ! existingKeyForValue.equals(key)), "Value ''{0}'' is already mapped to key ''{1}'' in this BidiMap.", value, existingKeyForValue);
+			assertArg(! (nn(existingKeyForValue) && ! existingKeyForValue.equals(key)), "Value '%s' is already mapped to key '%s' in this BidiMap.", value, existingKeyForValue);
 		}
 		// All checks passed, now perform the updates
 		for (var entry : m.entrySet()) {
@@ -425,4 +425,4 @@ public class BidiMap<K,V> implements Map<K,V> {
 	public int hashCode() {
 		return entrySet().hashCode();
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
index c00f33f470..5f6c58948f 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredList.java
@@ -627,12 +627,12 @@ public class FilteredList<E> extends AbstractList<E> {
 		if (element == null) {
 			// Allow null for non-primitive types
 			if (elementType.isPrimitive())
-				throw rex("Cannot set null element for primitive type {0}", elementType.getName());
+				throw rex("Cannot set null element for primitive type %s", elementType.getName());
 			return null;
 		}
 		if (elementType.isInstance(element))
 			return elementType.cast(element);
-		throw rex("Object of type {0} could not be converted to element type {1}", cn(element), cn(elementType));
+		throw rex("Object of type %s could not be converted to element type %s", cn(element), cn(elementType));
 	}
 
 	@Override
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
index a80b4c84ee..183c0ff6fa 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredMap.java
@@ -672,12 +672,12 @@ public class FilteredMap<K,V> extends AbstractMap<K,V> {
 		if (key == null) {
 			// Allow null for non-primitive types
 			if (keyType.isPrimitive())
-				throw rex("Cannot set null key for primitive type {0}", keyType.getName());
+				throw rex("Cannot set null key for primitive type %s", keyType.getName());
 			return null;
 		}
 		if (keyType.isInstance(key))
 			return keyType.cast(key);
-		throw rex("Object of type {0} could not be converted to key type {1}", cn(key), cn(keyType));
+		throw rex("Object of type %s could not be converted to key type %s", cn(key), cn(keyType));
 	}
 
 	private V convertValue(Object value) {
@@ -687,12 +687,12 @@ public class FilteredMap<K,V> extends AbstractMap<K,V> {
 		if (value == null) {
 			// Allow null for non-primitive types
 			if (valueType.isPrimitive())
-				throw rex("Cannot set null value for primitive type {0}", valueType.getName());
+				throw rex("Cannot set null value for primitive type %s", valueType.getName());
 			return null;
 		}
 		if (valueType.isInstance(value))
 			return valueType.cast(value);
-		throw rex("Object of type {0} could not be converted to value type {1}", cn(value), cn(valueType));
+		throw rex("Object of type %s could not be converted to value type %s", cn(value), cn(valueType));
 	}
 
 	@Override
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
index 8288953c31..0a7ced97bd 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/FilteredSet.java
@@ -572,12 +572,12 @@ public class FilteredSet<E> extends AbstractSet<E> {
 		if (element == null) {
 			// Allow null for non-primitive types
 			if (elementType.isPrimitive())
-				throw rex("Cannot set null element for primitive type {0}", elementType.getName());
+				throw rex("Cannot set null element for primitive type %s", elementType.getName());
 			return null;
 		}
 		if (elementType.isInstance(element))
 			return elementType.cast(element);
-		throw rex("Object of type {0} could not be converted to element type {1}", cn(element), cn(elementType));
+		throw rex("Object of type %s could not be converted to element type %s", cn(element), cn(elementType));
 	}
 
 	@Override
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Lists.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Lists.java
index cfe46c6a69..8009e198b6 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Lists.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Lists.java
@@ -258,7 +258,7 @@ public class Lists<E> {
 						if (converted != null) {
 							add(converted);
 						} else {
-							throw rex("Object of type {0} could not be converted to type {1}", cn(o), cn(elementType));
+							throw rex("Object of type %s could not be converted to type %s", cn(o), cn(elementType));
 						}
 					}
 				}
@@ -603,4 +603,4 @@ public class Lists<E> {
 			return elementFunction.apply(o);
 		return null;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Maps.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Maps.java
index 3ce1078889..50a2ab05a1 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Maps.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Maps.java
@@ -269,7 +269,7 @@ public class Maps<K,V> {
 						add(key, value);
 					});
 				} else {
-					throw rex("Object of type {0} could not be converted to type {1}", cn(o), "Map");
+					throw rex("Object of type %s could not be converted to type %s", cn(o), "Map");
 				}
 			}
 		}
@@ -757,7 +757,7 @@ public class Maps<K,V> {
 			return (K)o;
 		if (nn(keyFunction))
 			return keyFunction.apply(o);
-		throw rex("Object of type {0} could not be converted to key type {1}", cn(o), cn(keyType));
+		throw rex("Object of type %s could not be converted to key type %s", cn(o), cn(keyType));
 	}
 
 	/**
@@ -774,6 +774,6 @@ public class Maps<K,V> {
 			return (V)o;
 		if (nn(valueFunction))
 			return valueFunction.apply(o);
-		throw rex("Object of type {0} could not be converted to value type {1}", cn(o), cn(valueType));
+		throw rex("Object of type %s could not be converted to value type %s", cn(o), cn(valueType));
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Sets.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Sets.java
index 03e8e9f450..30d75658eb 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Sets.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Sets.java
@@ -257,7 +257,7 @@ public class Sets<E> {
 						if (converted != null) {
 							add(converted);
 						} else {
-							throw rex("Object of type {0} could not be converted to type {1}", cn(o), cn(elementType));
+							throw rex("Object of type %s could not be converted to type %s", cn(o), cn(elementType));
 						}
 					}
 				}
@@ -723,4 +723,4 @@ public class Sets<E> {
 			return elementFunction.apply(o);
 		return null;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/SimpleMap.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/SimpleMap.java
index 48fea2af3a..c928334ed4 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/SimpleMap.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/SimpleMap.java
@@ -218,13 +218,13 @@ public class SimpleMap<K,V> extends AbstractMap<K,V> {
 	})
 	public SimpleMap(K[] keys, V[] values) {
 		assertArgsNotNull(ARG_keys, keys, ARG_values, values);
-		assertArg(keys.length == values.length, "keys ''{0}'' and values ''{1}'' array lengths differ", keys.length, values.length);
+		assertArg(keys.length == values.length, "keys '%s' and values '%s' array lengths differ", keys.length, values.length);
 
 		// Check for duplicate keys
 		for (var i = 0; i < keys.length; i++) {
 			for (var j = i + 1; j < keys.length; j++) {
 				if (Shorts.eq(keys[i], keys[j])) {
-					throw iaex("Duplicate key found: {0}", keys[i]);
+					throw iaex("Duplicate key found: %s", keys[i]);
 				}
 			}
 		}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
index 45e314ecc3..61b2140f55 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/BasicConverter.java
@@ -300,7 +300,7 @@ public class BasicConverter extends CachingConverter {
 			return (in, memberOf, session, args) -> {
 				var s = in.toString();
 				if (s.length() != 1)
-					throw iaex("Cannot convert string of length {0} to char: ''{1}''", s.length(), s);
+					throw iaex("Cannot convert string of length %s to char: '%s'", s.length(), s);
 				return (O) Character.valueOf(s.charAt(0));
 			};
 		if (Number.class.isAssignableFrom(inType))
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java
index ed154a3a64..a563f3849d 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/inject/BeanInstantiator.java
@@ -696,7 +696,7 @@ public class BeanInstantiator<T> {
 	public Builder<T> type(Class<? extends T> value) {
 		assertArgNotNull(ARG_value, value);
 		beanSubType = info(value);
-		assertArg(beanType.isAssignableFrom(beanSubType), "type must be a subclass of beanType. beanType={0}, type={1}", cn(beanType), cn(beanSubType));
+		assertArg(beanType.isAssignableFrom(beanSubType), "type must be a subclass of beanType. beanType=%s, type=%s", cn(beanType), cn(beanSubType));
 		reset();
 		return this;
 	}
@@ -753,7 +753,7 @@ public class BeanInstantiator<T> {
 	public Builder<T> builder(Class<?> value) {
 		explicitBuilderType = info(assertArgNotNull(ARG_value, value));
 		builderType.set(explicitBuilderType);
-		assertArg(isValidBuilderType(explicitBuilderType), "Invalid builder type {0} for bean type {1}. Builder must have a build(), create(), or get() method that returns {1} (or a parent of {1}). The method may have @Inject annotation to allow injected parameters; otherwise, it must have no parameters.", cn(explicitBuilderType), cn(beanType));
+		assertArg(isValidBuilderType(explicitBuilderType), "Invalid builder type %1$s for bean type %2$s. Builder must have a build(), create(), or get() method that returns %2$s (or a parent of %2$s). The method may have @Inject annotation to allow injected parameters; otherwise, it must have no parameters.", cn(explicitBuilderType), cn(beanType));
 		builderTypes.get();  // Triggers validation on type hierarchy.
 		reset();
 		return this;
@@ -1780,7 +1780,7 @@ public class BeanInstantiator<T> {
 				// Builder method must return the exact beanSubType
 				if (!returnType.is(beanSubType.inner())) {
 					log("Builder method %s returns %s, but must return %s", method.getNameFull(), returnType.getName(), beanSubType.getName());
-					throw exex("Builder method {0} returns {1}, but must return {2}. Builder build methods must always return the exact bean subtype being created.", method.getNameFull(), returnType.getName(), beanSubType.getName());
+					throw exex("Builder method %s returns %s, but must return %s. Builder build methods must always return the exact bean subtype being created.", method.getNameFull(), returnType.getName(), beanSubType.getName());
 				}
 				bean = (T)beanType.cast(builtBean);
 
@@ -1830,7 +1830,7 @@ public class BeanInstantiator<T> {
 				}
 
 				log("Failed to create bean using builder");
-				throw exex("Could not instantiate class {0} using builder type {1}. Builder must have a build(), create(), or get() method that returns {0}. The method may have @Inject annotation to allow injected parameters.", beanSubType.getName(), builderTypeInfo != null ? builderTypeInfo.getName() : cn(builder2));
+				throw exex("Could not instantiate class %1$s using builder type %2$s. Builder must have a build(), create(), or get() method that returns %1$s. The method may have @Inject annotation to allow injected parameters.", beanSubType.getName(), builderTypeInfo != null ? builderTypeInfo.getName() : cn(builder2));
 			} else {
 				// Builder type is invalid and was auto-detected - fall through to factory methods/constructors
 				log("Builder detected but builder type is invalid. Builder type: %s. Falling back to factory methods/constructors.", cn(builder2));
@@ -1944,7 +1944,7 @@ public class BeanInstantiator<T> {
 				runPostCreateHooks(fallbackBean);
 				return fallbackBean;
 			}
-			throw exex("Could not instantiate class {0}: {1}.", beanSubType.getName(), "Class is an interface");
+			throw exex("Could not instantiate class %s: %s.", beanSubType.getName(), "Class is an interface");
 		}
 
 		if (beanSubType.isAbstract()) {
@@ -1955,7 +1955,7 @@ public class BeanInstantiator<T> {
 				runPostCreateHooks(fallbackBean);
 				return fallbackBean;
 			}
-			throw exex("Could not instantiate class {0}: {1}.", beanSubType.getName(), "Class is abstract");
+			throw exex("Could not instantiate class %s: %s.", beanSubType.getName(), "Class is abstract");
 		}
 
 		if (fallbackSupplier != null) {
@@ -1966,7 +1966,7 @@ public class BeanInstantiator<T> {
 		}
 
 		log("Failed to create bean: no methods/constructors found with matching parameters");
-		throw exex("Could not instantiate class {0}:  No methods/constructors found with matching parameters", beanSubType.getName());
+		throw exex("Could not instantiate class %s:  No methods/constructors found with matching parameters", beanSubType.getName());
 	}
 
 	/**
@@ -2010,7 +2010,7 @@ public class BeanInstantiator<T> {
 
 		// This should never happen if beanSubType validation is correct, but check anyway
 		if (result.isEmpty() || !result.get(result.size() - 1).is(beanType.inner())) {
-			throw iaex("beanType {0} was not found in the parent hierarchy of beanSubType {1}. This indicates a validation error.", beanType.getName(), beanSubType.getName());
+			throw iaex("beanType %s was not found in the parent hierarchy of beanSubType %s. This indicates a validation error.", beanType.getName(), beanSubType.getName());
 		}
 
 		return result;
@@ -2431,4 +2431,4 @@ public class BeanInstantiator<T> {
 		return bean;
 	}
 	} // class Builder
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/Console.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/Console.java
index a49b078148..113f7b3365 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/Console.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/Console.java
@@ -18,13 +18,11 @@ package org.apache.juneau.commons.io;
 
 import static org.apache.juneau.commons.utils.Shorts.*;
 
-import java.text.*;
-
 /**
  * A utility for logging formatted messages to the console.
  *
  * <p>
- * Uses {@link MessageFormat} for formatting messages with arguments.
+ * Uses printf-style ({@code %s}/{@code %d}/…) formatting for messages with arguments.
  */
 @SuppressWarnings({
 	"java:S106", // System.err/out usage is intentional for console output utility
@@ -43,17 +41,17 @@ public class Console {
 	 * Prints a message with arguments to {@link System#err}.
 	 *
 	 * <p>
-	 * Arguments are formatted using {@link MessageFormat}.
+	 * Arguments are formatted using printf-style ({@code %s}) placeholders.
 	 *
 	 * <p>
 	 * Useful for debug messages.
 	 *
 	 * <h5 class='figure'>Example:</h5>
 	 * <p class='bjava'>
-	 * 	Console.<jsm>err</jsm>(<js>"myPojo={0}"</js>, <jv>myPojo</jv>);
+	 * 	Console.<jsm>err</jsm>(<js>"myPojo=%s"</js>, <jv>myPojo</jv>);
 	 * </p>
 	 *
-	 * @param msg The {@link MessageFormat}-styled message.
+	 * @param msg The printf-styled message.
 	 * @param args The arguments sent to the formatter.
 	 */
 	public static final void err(String msg, Object...args) {
@@ -64,17 +62,17 @@ public class Console {
 	 * Prints a message with arguments to {@link System#out}.
 	 *
 	 * <p>
-	 * Arguments are formatted using {@link MessageFormat}.
+	 * Arguments are formatted using printf-style ({@code %s}) placeholders.
 	 *
 	 * <p>
 	 * Useful for debug messages.
 	 *
 	 * <h5 class='figure'>Example:</h5>
 	 * <p class='bjava'>
-	 * 	Console.<jsm>out</jsm>(<js>"myPojo={0}"</js>, <jv>myPojo</jv>);
+	 * 	Console.<jsm>out</jsm>(<js>"myPojo=%s"</js>, <jv>myPojo</jv>);
 	 * </p>
 	 *
-	 * @param msg The {@link MessageFormat}-styled message.
+	 * @param msg The printf-styled message.
 	 * @param args The arguments sent to the formatter.
 	 */
 	public static final void out(String msg, Object...args) {
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/lang/StringFormat.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/lang/StringFormat.java
index 91e59f22f8..d902b41cdc 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/lang/StringFormat.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/lang/StringFormat.java
@@ -21,7 +21,6 @@ import static org.apache.juneau.commons.utils.AssertionUtils.*;
 import static org.apache.juneau.commons.utils.Shorts.*;
 import static org.apache.juneau.commons.utils.SystemUtils.*;
 
-import java.text.*;
 import java.util.*;
 import java.util.stream.*;
 
@@ -29,59 +28,40 @@ import org.apache.juneau.commons.collections.*;
 import org.apache.juneau.commons.utils.*;
 
 /**
- * Unified string formatter supporting both MessageFormat-style and printf-style formatting in the same pattern.
+ * Printf-style string formatter with a small cache and lenient argument handling.
  *
  * <p>
- * This class provides a thread-safe, cacheable formatter that can handle mixed format styles in a single pattern.
- * It supports both MessageFormat syntax (<js>"{0}"</js>, <js>"{1,number}"</js>) and printf syntax (<js>"%s"</js>, <js>"%d"</js>)
- * within the same string.
+ * This class provides a thread-safe, cacheable formatter for printf-style ({@link java.util.Formatter}) patterns
+ * (<js>"%s"</js>, <js>"%d"</js>, <js>"%.2f"</js>, <js>"%1$s"</js>, etc.). MessageFormat-style (<js>"{0}"</js>)
+ * patterns are <b>not</b> recognized here — <c>{</c> and <c>'</c> are treated as literal text. For MessageFormat
+ * rendering use {@link StringUtils#mformat(String, Object...)} / {@code Shorts.mf(...)}/{@code Shorts.mfs(...)}
+ * (backed by {@link java.text.MessageFormat}).
  *
  * <h5 class='section'>Features:</h5>
  * <ul>
- *   <li><b>Dual Format Support:</b> Mix MessageFormat and printf-style placeholders in the same pattern</li>
+ *   <li><b>Printf grammar:</b> <js>"%s"</js>, <js>"%d"</js>, <js>"%.2f"</js>, <js>"%1$s"</js>, etc.</li>
  *   <li><b>Thread-Safe:</b> Immutable class, safe for concurrent use</li>
- *   <li><b>Cacheable:</b> Use {@link #of(String)} for cached instances</li>
- *   <li><b>Argument Sharing:</b> Both format styles share the same argument array</li>
- * </ul>
- *
- * <h5 class='section'>Format Style Detection:</h5>
- * <p>
- * The formatter automatically detects which style to use for each placeholder:
- * <ul>
- *   <li><b>MessageFormat style:</b> <js>"{0}"</js>, <js>"{1,number}"</js>, <js>"{2,date}"</js>, etc.</li>
- *   <li><b>Printf style:</b> <js>"%s"</js>, <js>"%d"</js>, <js>"%.2f"</js>, <js>"%1$s"</js>, etc.</li>
- * </ul>
- *
- * <h5 class='section'>Argument Mapping:</h5>
- * <p>
- * Arguments are processed in order of appearance:
- * <ul>
- *   <li><b>MessageFormat placeholders:</b> Use explicit indices (e.g., <js>"{0}"</js> uses <c>args[0]</c>)</li>
- *   <li><b>Printf placeholders:</b> Use sequential indices starting after the highest MessageFormat index</li>
+ *   <li><b>Cacheable:</b> Use {@link #ofPrintf(String)} for cached instances</li>
+ *   <li><b>Lenient null handling:</b> <jk>null</jk> arguments render as <js>"null"</js> for string conversions
+ *       (rather than throwing) and a fast path avoids {@link java.util.Formatter} for simple <js>"%s"</js> tokens</li>
  * </ul>
  *
  * <h5 class='section'>Examples:</h5>
  * <p class='bjava'>
- * 	<jc>// Mixed format styles</jc>
- * 	StringFormat <jv>fmt</jv> = StringFormat.<jsm>of</jsm>(<js>"Hello {0}, you have %d items"</js>);
+ * 	<jc>// Simple printf</jc>
+ * 	StringFormat <jv>fmt</jv> = StringFormat.<jsm>ofPrintf</jsm>(<js>"Hello %s, you have %d items"</js>);
  * 	String <jv>result</jv> = <jv>fmt</jv>.<jsm>format</jsm>(<js>"John"</js>, 5);
  * 	<jc>// Returns: "Hello John, you have 5 items"</jc>
  *
- * 	<jc>// MessageFormat with explicit indices, printf with sequential</jc>
- * 	StringFormat <jv>fmt2</jv> = StringFormat.<jsm>of</jsm>(<js>"User {0} has %s and {1} items"</js>);
- * 	String <jv>result2</jv> = <jv>fmt2</jv>.<jsm>format</jsm>(<js>"Alice"</js>, 10, <js>"admin"</js>);
- * 	<jc>// Returns: "User Alice has admin and 10 items"</jc>
- * 	<jc>// {0} -> "Alice", {1} -> 10, %s -> "admin"</jc>
- *
- * 	<jc>// Printf with explicit indices</jc>
- * 	StringFormat <jv>fmt3</jv> = StringFormat.<jsm>of</jsm>(<js>"%1$s loves %2$s, and {0} also loves %3$s"</js>);
- * 	String <jv>result3</jv> = <jv>fmt3</jv>.<jsm>format</jsm>(<js>"Alice"</js>, <js>"Bob"</js>, <js>"Charlie"</js>);
+ * 	<jc>// Argument index (reuse arguments)</jc>
+ * 	StringFormat <jv>fmt2</jv> = StringFormat.<jsm>ofPrintf</jsm>(<js>"%1$s loves %2$s, and %1$s also loves %3$s"</js>);
+ * 	String <jv>result2</jv> = <jv>fmt2</jv>.<jsm>format</jsm>(<js>"Alice"</js>, <js>"Bob"</js>, <js>"Charlie"</js>);
  * 	<jc>// Returns: "Alice loves Bob, and Alice also loves Charlie"</jc>
  * </p>
  *
  * <h5 class='section'>Caching:</h5>
  * <p>
- * Use {@link #of(String)} to get cached instances. The cache is thread-safe and limited to 1000 entries.
+ * Use {@link #ofPrintf(String)} to get cached instances. The cache is thread-safe and limited to 1000 entries.
  * For uncached instances, use the constructor directly.
  * </p>
  *
@@ -91,6 +71,7 @@ import org.apache.juneau.commons.utils.*;
  * </p>
  *
  * @see StringUtils#format(String, Object...)
+ * @see StringUtils#mformat(String, Object...)
  */
 @SuppressWarnings({
 	"java:S115" // Constants use UPPER_snakeCase convention
@@ -121,97 +102,6 @@ public final class StringFormat {
 		}
 	}
 
-	/**
-	 * MessageFormat-style token (e.g., {0}, {1,number}).
-	 */
-	private static final class MessageFormatToken extends Token {
-		private final char format;
-		private final String content; // null for simple tokens, normalized pattern like "{0,number}" for complex tokens
-		private final int index; // 0-based index
-		private final String placeholder; // Original placeholder text like "{0}" or "{0,number}"
-
-		/**
-		 * @param content - The variable content such as "{}" or "{0}", or "{0,number}"
-		 * 	The content should have the curly-braces already removed so that we're only looking at the inner parts.
-		 * @param index - The zero-based index of the variable in the message (used for sequential {} placeholders).
-		 */
-		MessageFormatToken(String content, int index) {
-			if (content.isBlank()) {
-				this.content = null;
-				this.index = index;
-				this.format = 's';
-				this.placeholder = "{" + index + "}";
-			} else if (content.indexOf(',') == -1) {
-				this.content = null;
-				this.index = parseIndex(content);
-				this.format = 's';
-				this.placeholder = "{" + this.index + "}";
-			} else {
-				var tokens = content.split(",", 2);
-				this.index = parseIndex(tokens[0]);
-				this.content = "{0," + tokens[1] + "}";
-				this.format = 'o';
-				this.placeholder = "{" + this.index + "," + tokens[1] + "}";
-			}
-		}
-
-		/**
-		 * Parses the index from a MessageFormat content string.
-		 *
-		 * @param s The content string (e.g., "0", "1").
-		 * @return The parsed index.
-		 * @throws IllegalArgumentException If the string is not a valid number.
-		 */
-		private static int parseIndex(String s) {
-			if (! s.matches("\\d+")) throw new IllegalArgumentException("can't parse argument number: " + s);
-			return Integer.parseInt(s);
-		}
-
-		/**
-		 * Creates a MessageFormatToken and adds it to the tokens list.
-		 *
-		 * @param tokens The list of tokens to add to.
-		 * @param pattern The pattern string.
-		 * @param start The start index in the pattern.
-		 * @param end The end index in the pattern.
-		 * @param index The token index.
-		 */
-		static void create(List<Token> tokens, String pattern, int start, int end, int index) {
-			tokens.add(new MessageFormatToken(pattern.substring(start, end), index));
-		}
-
-		@Override
-		public String toString() {
-			return "[M:" + format + index + (content == null ? "" : (':' + content)) + "]";
-		}
-
-		@Override
-		void append(StringBuilder sb, Object[] args, Locale locale) {
-			// MessageFormat inserts the placeholder text if argument is missing
-			if (args == null || index >= args.length || index < 0) {
-				sb.append(placeholder);
-				return;
-			}
-			var o = args[index];
-			var l = locale == null ? Locale.getDefault() : locale;
-			if (format == 's') {
-				if (o == null) {
-					sb.append("null");
-				} else if (o instanceof Number o2) {
-					sb.append(NUMBER_FORMAT_CACHE.get(l).format(o2));
-				} else if (o instanceof Date o2) {
-					sb.append(DATE_FORMAT_CACHE.get(l).format(o2));
-				} else {
-					sb.append(o.toString());
-				}
-			} else {
-				// Use Cache2 with Locale and content as separate keys to avoid string concatenation
-				var mf = MESSAGE_FORMAT_CACHE.get(l, content);
-				sb.append(mf.format(a(o)));
-			}
-		}
-	}
-
 	/**
 	 * Printf-style token (e.g., %s, %d, %.2f).
 	 */
@@ -437,68 +327,57 @@ public final class StringFormat {
 	private static final CacheMode CACHE_MODE = env("juneau.StringFormat.caching", CacheMode.FULL);
 
 	private static final Cache<String,StringFormat> CACHE = Cache.of(String.class, StringFormat.class).maxSize(1000).cacheMode(CACHE_MODE).build();
-	private static final Cache2<Locale,String,MessageFormat> MESSAGE_FORMAT_CACHE = Cache2.of(Locale.class, String.class, MessageFormat.class).maxSize(100).threadLocal().cacheMode(CACHE_MODE)
-		.supplier((locale, content) -> new MessageFormat(content, locale)).build();
-
-	private static final Cache<Locale,NumberFormat> NUMBER_FORMAT_CACHE = Cache.of(Locale.class, NumberFormat.class).maxSize(50).threadLocal().cacheMode(CACHE_MODE).supplier(NumberFormat::getInstance)
-		.build();
-
-	private static final Cache<Locale,DateFormat> DATE_FORMAT_CACHE = Cache.of(Locale.class, DateFormat.class).maxSize(50).threadLocal().cacheMode(CACHE_MODE)
-		.supplier(locale -> DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale)).build();
 
 	private static final AsciiSet PRINTF_CONVERSION_CHARS = AsciiSet.of("bBhHsScCdoxXeEfgGaAtTn%");
 
 	private static final AsciiSet PRINTF_FORMAT_CHARS = AsciiSet.of("-+ 0(#.*$");
 
 	/**
-	 * Formats a pattern string with the given arguments using the specified locale.
+	 * Formats a pattern string with the given arguments using printf-style semantics.
 	 *
 	 * <p>
-	 * This is a convenience method that creates a StringFormat instance and formats it.
+	 * <c>{</c> and <c>'</c> are literal text, matching {@link java.util.Formatter} semantics.
 	 * If no arguments are passed in, the pattern is returned as-is.
 	 *
 	 * @param pattern The format pattern.
-	 * @param locale The locale to use for formatting. If <jk>null</jk>, uses the default locale.
 	 * @param args The arguments to format.
 	 * @return The formatted string.
 	 * @throws IllegalArgumentException If the pattern is <jk>null</jk> or format specifiers are invalid.
 	 */
-	public static String format(String pattern, Locale locale, Object...args) {
+	public static String formatPrintf(String pattern, Object...args) {
 		if (args.length == 0)
 			return pattern;
-		return of(pattern).format(locale, args);
+		return ofPrintf(pattern).format(args);
 	}
 
 	/**
-	 * Formats a pattern string with the given arguments using the default locale.
-	 *
-	 * <p>
-	 * This is a convenience method that creates a StringFormat instance and formats it.
-	 * If no arguments are passed in, the pattern is simply returned as-is.
+	 * Formats a pattern string with the given arguments using printf-style semantics and the specified locale.
 	 *
 	 * @param pattern The format pattern.
+	 * @param locale The locale to use for formatting. If <jk>null</jk>, uses the default locale.
 	 * @param args The arguments to format.
 	 * @return The formatted string.
 	 * @throws IllegalArgumentException If the pattern is <jk>null</jk> or format specifiers are invalid.
 	 */
-	public static String format(String pattern, Object...args) {
+	public static String formatPrintf(String pattern, Locale locale, Object...args) {
 		if (args.length == 0)
 			return pattern;
-		return of(pattern).format(args);
+		return ofPrintf(pattern).format(locale, args);
 	}
 
 	/**
-	 * Returns a cached StringFormat instance for the given pattern.
+	 * Returns a cached printf StringFormat instance for the given pattern.
 	 *
 	 * <p>
 	 * This method uses a thread-safe cache to avoid recreating StringFormat instances for the same pattern.
-	 * The cache is limited to 1000 entries.
+	 * The cache is limited to 1000 entries. <c>{</c> and <c>'</c> are treated as literal text (genuine
+	 * {@link java.util.Formatter} semantics); only printf-style placeholders are recognized.
 	 *
 	 * @param pattern The format pattern.
 	 * @return A cached or new StringFormat instance.
 	 * @throws IllegalArgumentException If the pattern is <jk>null</jk>.
 	 */
-	public static StringFormat of(String pattern) {
+	public static StringFormat ofPrintf(String pattern) {
 		assertArgNotNull(ARG_pattern, pattern);
 		return CACHE.get(pattern, () -> new StringFormat(pattern));
 	}
@@ -535,19 +414,10 @@ public final class StringFormat {
 		// %[argument_index$][flags][width]conversion
 		// %[flags][width]conversion
 
-		// Possible MessageFormat variable formats:
-		// {}
-		// {#,formatType}
-		// {#,formatType,formatStyle}
-
-		// S1 - In literal, looking for %, {, or '
+		// S1 - In literal, looking for %
 		// S2 - Found %, looking for conversion char or t or T
-		// S3 - Found {, looking for }
-		// S4 - Found ', in quoted section (MessageFormat single quotes escape special chars), looking for '
 		var state = S1;
 
-		var nestedBracketDepth = 0;
-
 		var mark = 0;
 		while (i < length) {
 			var ch = pattern.charAt(i++);
@@ -557,16 +427,8 @@ public final class StringFormat {
 					lit(tokens, pattern, mark, i - 1);
 					state = S2;
 					mark = i;
-				} else if (ch == '{') {
-					lit(tokens, pattern, mark, i - 1);
-					state = S3;
-					mark = i - 1;
-				} else if (ch == '\'') {
-					lit(tokens, pattern, mark, i - 1);
-					state = S4;
-					mark = i;
 				}
-			} else if (state == S2) {
+			} else /* if (state == S2) */ {
 				if (ch == '%') {
 					tokens.add(new LiteralToken("%"));
 					state = S1;
@@ -593,47 +455,16 @@ public final class StringFormat {
 					state = S1;
 					mark = i;
 				}
-			} else if (state == S3) {
-				if (ch == '{') {
-					nestedBracketDepth++;
-				} else if (ch == '}') {
-					if (nestedBracketDepth > 0) {
-						nestedBracketDepth--;
-					} else {
-						MessageFormatToken.create(tokens, pattern, mark + 1, i - 1, sequentialIndex++);
-						state = S1;
-						mark = i;
-					}
-				}
-			} else /* if (state == S4) */ {
-				if (ch == '\'') {
-					if (mark == i - 1) {
-						lit(tokens, pattern, mark, i);  // '' becomes '
-						state = S1;
-						mark = i;
-					} else {
-						lit(tokens, pattern, mark, i - 1);
-						state = S1;
-						mark = i;
-					}
-				}
 			}
 		}
 
 		// Process remaining content based on final state
 		if (state == S1) {
 			lit(tokens, pattern, mark);
-		} else if (state == S2) {
+		} else /* if (state == S2) */ {
 			// Dangling '%' without conversion - throw exception to match String.format() behavior
 			// UnknownFormatConversionException constructor takes just the conversion character
 			throw new UnknownFormatConversionException("%");
-		} else if (state == S3) {
-			// Unmatched '{' - throw exception to match MessageFormat behavior
-			throw new IllegalArgumentException("Unmatched braces in the pattern.");
-		} else /* if (state == S4) */ {
-			// Unmatched quote - MessageFormat treats it as ending the quoted section
-			// Add the quoted content as literal (from mark to end of pattern)
-			lit(tokens, pattern, mark);
 		}
 
 		return tokens;
@@ -652,9 +483,13 @@ public final class StringFormat {
 	private final Token[] tokens;
 
 	/**
-	 * Creates a new StringFormat instance.
+	 * Creates a new printf StringFormat instance.
 	 *
-	 * @param pattern The format pattern. Can contain both MessageFormat and printf-style placeholders.
+	 * <p>
+	 * <c>{</c> and <c>'</c> are treated as literal text (genuine {@link java.util.Formatter} semantics); only
+	 * printf-style placeholders are recognized.
+	 *
+	 * @param pattern The format pattern.
 	 * @throws IllegalArgumentException If the pattern is <jk>null</jk>.
 	 */
 	public StringFormat(String pattern) {
@@ -671,11 +506,7 @@ public final class StringFormat {
 	 * Formats the pattern with the given arguments using the specified locale.
 	 *
 	 * <p>
-	 * The locale affects both MessageFormat and printf-style formatting:
-	 * <ul>
-	 *   <li><b>MessageFormat:</b> Locale-specific number, date, and time formatting</li>
-	 *   <li><b>Printf:</b> Locale-specific number formatting (decimal separators, etc.)</li>
-	 * </ul>
+	 * The locale affects locale-specific printf number formatting (decimal separators, etc.).
 	 *
 	 * @param locale The locale to use for formatting. If <jk>null</jk>, uses the default locale.
 	 * @param args The arguments to format.
@@ -714,8 +545,6 @@ public final class StringFormat {
 	 * It returns a string showing each token in the format:
 	 * <ul>
 	 *   <li><b>Literal tokens:</b> <js>"[L:text]"</js> - Literal text</li>
-	 *   <li><b>MessageFormat tokens (simple):</b> <js>"[M:s0]"</js> - Simple MessageFormat placeholder (format='s', index=0)</li>
-	 *   <li><b>MessageFormat tokens (complex):</b> <js>"[M:o0:{0,number,currency}]"</js> - Complex MessageFormat placeholder (format='o', index=0, content)</li>
 	 *   <li><b>StringFormat tokens (simple):</b> <js>"[S:s0:%s]"</js> - Simple printf placeholder (format='s', index=0, content)</li>
 	 *   <li><b>StringFormat tokens (complex):</b> <js>"[S:z0:%.2f]"</js> - Complex printf placeholder (format='z', index=0, content)</li>
 	 * </ul>
@@ -723,18 +552,17 @@ public final class StringFormat {
 	 * <h5 class='section'>Token Format:</h5>
 	 * <ul>
 	 *   <li><b>L</b> = Literal token</li>
-	 *   <li><b>M</b> = MessageFormat token</li>
 	 *   <li><b>S</b> = StringFormat (printf) token</li>
-	 *   <li><b>Format character:</b> 's' = simple, 'o' = other/complex, 'z' = complex printf</li>
+	 *   <li><b>Format character:</b> 's' = simple, 'z' = complex printf</li>
 	 *   <li><b>Index:</b> 0-based argument index</li>
 	 *   <li><b>Content:</b> The format string content (for complex tokens)</li>
 	 * </ul>
 	 *
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bjava'>
-	 * 	StringFormat <jv>fmt</jv> = StringFormat.<jsm>of</jsm>(<js>"Hello {0}, you have %d items"</js>);
+	 * 	StringFormat <jv>fmt</jv> = StringFormat.<jsm>ofPrintf</jsm>(<js>"Hello %s, you have %d items"</js>);
 	 * 	<jv>fmt</jv>.<jsm>toPattern</jsm>();
-	 * 	<jc>// Returns: "[L:Hello ][M:s0][L:, you have ][S:d1:%d][L: items]"</jc>
+	 * 	<jc>// Returns: "[L:Hello ][S:s0:%s][L:, you have ][S:d1:%d][L: items]"</jc>
 	 * </p>
 	 *
 	 * @return A debug string showing the parsed token structure.
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecord.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecord.java
index dbf2a54cf9..43a8f259e9 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecord.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/LogRecord.java
@@ -35,8 +35,8 @@ import org.apache.juneau.commons.utils.*;
  *
  * <p>
  * This class extends {@link java.util.logging.LogRecord java.util.logging.LogRecord} and overrides {@link #getMessage()} to use
- * {@link org.apache.juneau.commons.utils.StringUtils#format(String, Object...)} for lazy formatting.
- * The message is only formatted when {@link #getMessage()} is actually called.
+ * {@link org.apache.juneau.commons.utils.StringUtils#format(String, Object...)} (printf-style <js>"%s"</js>/<js>"%d"</js>) for
+ * lazy formatting. The message is only formatted when {@link #getMessage()} is actually called.
  *
  * <h5 class='section'>Usage:</h5>
  * <p>
@@ -45,6 +45,17 @@ import org.apache.juneau.commons.utils.*;
  * accessed (e.g., by a Handler or Formatter).
  * </p>
  *
+ * <h5 class='section'>Formatting contract:</h5>
+ * <p>
+ * Juneau {@link Logger} patterns are <b>printf-style</b> (rendered here via {@link org.apache.juneau.commons.utils.StringUtils#format(String, Object...)}).
+ * Because this override returns the already-substituted message, downstream {@link java.util.logging.Handler Handlers} and
+ * {@link java.util.logging.Formatter Formatters} that call {@link #getMessage()} see fully-rendered text and never re-apply
+ * formatting — so the printf-vs-MessageFormat choice is purely internal. The JDK's {@link java.text.MessageFormat}
+ * parameter contract of {@link java.util.logging.LogRecord} only resurfaces if a record is serialized and consumed as a
+ * plain {@link java.util.logging.LogRecord} by a non-Juneau handler; such a consumer would apply MessageFormat to the raw
+ * <c>{0}</c> pattern, so printf patterns are not intended for that scenario.
+ * </p>
+ *
  * <h5 class='section'>See Also:</h5><ul>
  * 	<li class='jc'>{@link Logger}
  * 	<li class='jc'>{@link org.apache.juneau.commons.utils.StringUtils#format(String, Object...)}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/Logger.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/Logger.java
index d03705b983..8fce1c03e6 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/Logger.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/logging/Logger.java
@@ -41,27 +41,34 @@ import java.util.logging.*;
  * 	<li>All standard {@link java.util.logging.Logger} functionality via delegation
  * 	<li>Convenience methods for formatted logging at all log levels
  * 	<li>Lazy evaluation of formatted messages using {@link org.apache.juneau.commons.utils.Shorts#fs(String, Object...)}
- * 	<li>Support for both MessageFormat-style and printf-style formatting
+ * 	<li>Printf-style formatting (rendered via {@link org.apache.juneau.commons.utils.StringUtils#format(String, Object...)})
  * </ul>
  *
  * <h5 class='section'>Format Support:</h5>
  * <p>
- * The formatting methods support both MessageFormat-style and printf-style formatting:
+ * The formatting methods use printf-style ({@link java.util.Formatter}) placeholders. MessageFormat-style
+ * (<js>"{0}"</js>) patterns are <b>not</b> expanded here — use {@link org.apache.juneau.commons.utils.Shorts#mf(String, Object...)} /
+ * {@link org.apache.juneau.commons.utils.StringUtils#mformat(String, Object...)} for those:
  * </p>
  * <ul>
- * 	<li><b>Printf-style:</b> <js>"%s"</js>, <js>"%d"</js>, <js>"%.2f"</js>, etc.
- * 	<li><b>MessageFormat-style:</b> <js>"{0}"</js>, <js>"{1,number}"</js>, etc.
- * 	<li><b>Un-numbered MessageFormat:</b> <js>"{}"</js> - Sequential placeholders
+ * 	<li><b>Printf-style:</b> <js>"%s"</js>, <js>"%d"</js>, <js>"%1$s"</js>, etc.
  * </ul>
  *
+ * <p>
+ * Juneau {@link Logger} patterns are printf-style. Because {@link LogRecord#getMessage()} returns the
+ * already-substituted message, the {@link java.text.MessageFormat} parameter contract of the underlying
+ * {@link java.util.logging.LogRecord} only surfaces if a record is serialized and consumed as a plain
+ * {@link java.util.logging.LogRecord} by a non-Juneau handler.
+ * </p>
+ *
  * <h5 class='section'>Example:</h5>
  * <p class='bjava'>
  * 	Logger <jv>logger</jv> = Logger.getLogger(MyClass.<jk>class</jk>.getName());
  *
- * 	<jc>// Formatted logging at different levels</jc>
- * 	<jv>logger</jv>.severe(<js>"Error processing user {0}: {1}"</js>, userId, error);
+ * 	<jc>// Formatted logging at different levels (printf-style placeholders)</jc>
+ * 	<jv>logger</jv>.severe(<js>"Error processing user %s: %s"</js>, userId, error);
  * 	<jv>logger</jv>.warning(<js>"Failed to connect to %s after %d attempts"</js>, hostname, attempts);
- * 	<jv>logger</jv>.info(<js>"Processing {} items"</js>, count);
+ * 	<jv>logger</jv>.info(<js>"Processing %s items"</js>, count);
  * 	<jv>logger</jv>.fine(<js>"Debug value: %s"</js>, debugValue);
  * </p>
  *
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationProvider.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationProvider.java
index 42ee98447b..b6f9f16f40 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationProvider.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationProvider.java
@@ -351,14 +351,14 @@ public class AnnotationProvider {
 
 					ci.getPublicMethod(x -> x.hasName("onClass")).ifPresent(mi -> {
 						if (! mi.getReturnType().is(Class[].class))
-							throw brex("Invalid annotation @{0} used in runtime annotations.  Annotation must define an onClass() method that returns a Class array.", cns(a));
+							throw brex("Invalid annotation @%s used in runtime annotations.  Annotation must define an onClass() method that returns a Class array.", cns(a));
 						for (var c : (Class<?>[])mi.accessible().invoke(a))
 							runtimeAnnotations.append(c.getName(), annotationToStore);
 					});
 
 					ci.getPublicMethod(x -> x.hasName("on")).ifPresent(mi -> {
 						if (! mi.getReturnType().is(String[].class))
-							throw brex("Invalid annotation @{0} used in runtime annotations.  Annotation must define an on() method that returns a String array.", cns(a));
+							throw brex("Invalid annotation @%s used in runtime annotations.  Annotation must define an on() method that returns a String array.", cns(a));
 						for (var s : (String[])mi.accessible().invoke(a))
 							runtimeAnnotations.append(s, annotationToStore);
 					});
@@ -366,7 +366,7 @@ public class AnnotationProvider {
 				} catch (BeanRuntimeException e) {
 					throw e;
 				} catch (Exception e) {
-					throw brex(e, (Class<?>)null, "Invalid annotation @{0} used in runtime annotations.", cn(a));
+					throw brex(e, (Class<?>)null, "Invalid annotation @%s used in runtime annotations.", cn(a));
 				}
 			}
 			return this;
@@ -1113,4 +1113,4 @@ public class AnnotationProvider {
 		}
 		throw uoex();
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
index 76eb96f373..9735e5e3de 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
@@ -1385,16 +1385,16 @@ public non-sealed class ClassInfo extends ElementInfo implements Annotatable, Ty
 		while (pt != cc.getSuperclass()) {
 			extractTypes(typeMap, cc);
 			cc = cc.getSuperclass();
-			assertArg(nn(cc), "Class ''{0}'' is not a subclass of parameterized type ''{1}''", inner.getSimpleName(), pt.getSimpleName());
+			assertArg(nn(cc), "Class '%s' is not a subclass of parameterized type '%s'", inner.getSimpleName(), pt.getSimpleName());
 		}
 
 		Type gsc = cc.getGenericSuperclass();
 
-		assertArg(gsc instanceof ParameterizedType, "Class ''{0}'' is not a parameterized type", pt.getSimpleName());
+		assertArg(gsc instanceof ParameterizedType, "Class '%s' is not a parameterized type", pt.getSimpleName());
 
 		var cpt = (ParameterizedType)gsc;
 		Type[] atArgs = cpt.getActualTypeArguments();
-		assertArg(index < atArgs.length, "Invalid type index. index={0}, argsLength={1}", index, atArgs.length);
+		assertArg(index < atArgs.length, "Invalid type index. index=%s, argsLength=%s", index, atArgs.length);
 		Type actualType = cpt.getActualTypeArguments()[index];
 
 		if (typeMap.containsKey(actualType))
@@ -1428,7 +1428,7 @@ public non-sealed class ClassInfo extends ElementInfo implements Annotatable, Ty
 		} else if (actualType instanceof ParameterizedType actualType2) {
 			return (Class<?>)actualType2.getRawType();
 		}
-		throw iaex("Could not resolve variable ''{0}'' to a type.", actualType.getTypeName());
+		throw iaex("Could not resolve variable '%s' to a type.", actualType.getTypeName());
 	}
 
 	/**
@@ -2585,7 +2585,7 @@ public non-sealed class ClassInfo extends ElementInfo implements Annotatable, Ty
 	 */
 	public Object newInstance() throws ExecutableException {
 		if (inner == null)
-			throw exex("Type ''{0}'' cannot be instantiated", getNameFull());
+			throw exex("Type '%s' cannot be instantiated", getNameFull());
 		try {
 			return inner.getDeclaredConstructor().newInstance();
 		} catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) {
@@ -3108,4 +3108,4 @@ public non-sealed class ClassInfo extends ElementInfo implements Annotatable, Ty
 		return JsrSupport.isInjectAnnotation(ai) || JsrSupport.isValueAnnotation(ai);
 	}
 
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ElementInfo.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ElementInfo.java
index 3943eb953f..2e8ef23824 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ElementInfo.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ElementInfo.java
@@ -118,7 +118,7 @@ public abstract sealed class ElementInfo permits ClassInfo, ParameterInfo, Acces
 			case INTERFACE -> isInterface();
 			case ABSTRACT -> isAbstract();
 			case NOT_ABSTRACT -> isNotAbstract();
-			default -> throw rex("Invalid flag for element: {0}", flag);
+			default -> throw rex("Invalid flag for element: %s", flag);
 		};
 	}
 
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
index 4be4d1ec70..77407bdb6a 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/FieldInfo.java
@@ -675,11 +675,11 @@ public final class FieldInfo extends AccessibleInfo implements Comparable<FieldI
 			} else if (o2.isPresent()) {
 				value = o2.get();
 			} else {
-				throw exex("Could not resolve value for field {0}", this);
+				throw exex("Could not resolve value for field %s", this);
 			}
 		}
 
 		set(bean, value);
 		return bean;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
index a5cc25248f..12daa3ec21 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ParameterInfo.java
@@ -933,7 +933,7 @@ public final class ParameterInfo extends ElementInfo implements Annotatable {
 					return System.identityHashCode(proxy);
 				if (eq(method.getName(), "equals") && method.getParameterCount() == 1)
 					return proxy == args[0];
-				throw exex("Unsupported provider method: {0}", method.getName());
+				throw exex("Unsupported provider method: %s", method.getName());
 			};
 			return Proxy.newProxyInstance(providerType.getClassLoader(), new Class<?>[] {providerType}, handler);
 		}
@@ -1018,7 +1018,7 @@ public final class ParameterInfo extends ElementInfo implements Annotatable {
 		if (r.isPresent())
 			return r.get();
 
-		throw exex("Could not resolve value for parameter {0}", this);
+		throw exex("Could not resolve value for parameter %s", this);
 	}
 
 	/**
@@ -1045,4 +1045,4 @@ public final class ParameterInfo extends ElementInfo implements Annotatable {
 			return enclosingInstance;
 		return resolveValue(beanStore, otherBeans);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ReflectionMap.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ReflectionMap.java
index 2f8c21319c..801ab3ffff 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ReflectionMap.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ReflectionMap.java
@@ -263,7 +263,7 @@ public class ReflectionMap<V> {
 		 */
 		public Builder<V> append(String key, V value) {
 			if (Shorts.ie(key))  // NOAI
-				throw rex("Invalid reflection signature: [{0}]", key);
+				throw rex("Invalid reflection signature: [%s]", key);
 			try {
 				splitNames(key, k -> {
 					if (k.endsWith(")")) {
@@ -287,7 +287,7 @@ public class ReflectionMap<V> {
 					}
 			});
 			} catch (@SuppressWarnings("unused") IndexOutOfBoundsException e) {
-			throw rex("Invalid reflection signature: [{0}]", key);
+			throw rex("Invalid reflection signature: [%s]", key);
 			}
 
 			return this;
@@ -782,4 +782,4 @@ public class ReflectionMap<V> {
 	public String toString() {
 		return r(properties());
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/runtime/ManifestFile.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/runtime/ManifestFile.java
index e66377efd5..4f9d0eaf86 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/runtime/ManifestFile.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/runtime/ManifestFile.java
@@ -92,7 +92,7 @@ public class ManifestFile {
 			mf = new Manifest();
 			mf.read(fis);
 		} catch (IOException e) {
-			throw ioex(e, "Problem detected in MANIFEST.MF.  Contents below:\n{0}", read(f));
+			throw ioex(e, "Problem detected in MANIFEST.MF.  Contents below:\n%s", read(f));
 		}
 		this.mainAttributes = readMain(mf);
 		this.sections = readSections(mf);
@@ -135,7 +135,7 @@ public class ManifestFile {
 			mf = new Manifest();
 			mf.read(in);
 		} catch (IOException e) {
-			throw ioex(e, "Problem detected in MANIFEST.MF.  Contents below:\n{0}", read(path));
+			throw ioex(e, "Problem detected in MANIFEST.MF.  Contents below:\n%s", read(path));
 		}
 		this.mainAttributes = readMain(mf);
 		this.sections = readSections(mf);
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
index eab855f4a7..0dbedd78ed 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
@@ -768,7 +768,7 @@ public class Settings {
 				toTypeFunctions.putIfAbsent(c, f);
 		}
 		if (f == null)
-			throw rex("Invalid env type: {0}", c);
+			throw rex("Invalid env type: %s", c);
 		return f.apply(s);
 	}
 }
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ArgCoercer.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ArgCoercer.java
index 86df55803f..90ff93e781 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ArgCoercer.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ArgCoercer.java
@@ -93,10 +93,10 @@ final class ArgCoercer {
 		var variadic = n > 0 && paramTypes[n - 1] == String[].class;
 		var fixedCount = variadic ? n - 1 : n;
 		if (args.size() < fixedCount)
-			throw iaex("Function ''{0}'' expected at least {1} arg(s), got {2}",
+			throw iaex("Function '%s' expected at least %s arg(s), got %s",
 				fnName, fixedCount, args.size());
 		if (!variadic && args.size() > n)
-			throw iaex("Function ''{0}'' expected at most {1} arg(s), got {2}",
+			throw iaex("Function '%s' expected at most %s arg(s), got %s",
 				fnName, n, args.size());
 
 		var out = new Object[n];
@@ -146,7 +146,7 @@ final class ArgCoercer {
 			if (target == Object.class)
 				return s;
 		} catch (@SuppressWarnings("unused") NumberFormatException e) {
-			throw iaex("Function ''{0}'' arg {1}: cannot coerce ''{2}'' to {3}",
+			throw iaex("Function '%s' arg %s: cannot coerce '%s' to %s",
 				fnName, argIndex, s, target.getSimpleName());
 		}
 		// Unrecognized target type: passthrough as String.
@@ -163,7 +163,7 @@ final class ArgCoercer {
 			return true;
 		if (t.isEmpty() || t.equalsIgnoreCase("false") || t.equals("0") || t.equalsIgnoreCase("no") || t.equalsIgnoreCase("off"))
 			return false;
-		throw iaex("Function ''{0}'' arg {1}: cannot coerce ''{2}'' to boolean (accepted: true/1/yes/on, false/0/no/off, empty)",
+		throw iaex("Function '%s' arg %s: cannot coerce '%s' to boolean (accepted: true/1/yes/on, false/0/no/off, empty)",
 			fnName, argIndex, s);
 	}
 
@@ -231,7 +231,7 @@ final class ArgCoercer {
 				i++;
 			if (i < len) {
 				if (body.charAt(i) != ',')
-					throw iaex("Function ''{0}'' arg {1}: malformed JSON array near offset {2}",
+					throw iaex("Function '%s' arg %s: malformed JSON array near offset %s",
 						fnName, argIndex, i);
 				i++;
 			}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ScriptSegment.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ScriptSegment.java
index 236ff0285c..fce50e4e14 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ScriptSegment.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/ScriptSegment.java
@@ -68,7 +68,7 @@ final class ScriptSegment extends TemplateSegment {
 	@Override
 	void resolve(VarResolverSession session, StringBuilder out) {
 		if (cachedFn == null)
-			throw iaex("No such function ''{0}''", name);
+			throw iaex("No such function '%s'", name);
 
 		// Resolve each arg template to a String, then dispatch to the function. TypedFunction
 		// handles ArgCoercer.coerce(...) internally; direct VarFunction implementations get the
@@ -80,7 +80,7 @@ final class ScriptSegment extends TemplateSegment {
 		var n = args.size();
 		if (n < cachedFn.minArity() || n > cachedFn.maxArity()) {
 			var maxStr = cachedFn.maxArity() == Integer.MAX_VALUE ? "any" : String.valueOf(cachedFn.maxArity());
-			throw iaex("Function ''{0}'' expected {1}..{2} arg(s), got {3}",
+			throw iaex("Function '%s' expected %s..%s arg(s), got %s",
 				name, cachedFn.minArity(), maxStr, n);
 		}
 
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TemplateSegment.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TemplateSegment.java
index 30e588ca0c..a643ed75cd 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TemplateSegment.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TemplateSegment.java
@@ -90,7 +90,7 @@ abstract sealed class TemplateSegment permits LiteralSegment, VarRefSegment, Scr
 	static VarResolverException wrapDispatchFailure(Exception e, String identifier, String sourceFragment) {
 		if (e instanceof VarResolverException e2)
 			return e2;
-		throw new VarResolverException(e, "Problem occurred resolving variable ''{0}'' in string ''{1}''", identifier, sourceFragment);
+		throw new VarResolverException(e, "Problem occurred resolving variable '%s' in string '%s'", identifier, sourceFragment);
 	}
 
 	/**
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TypedFunction.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TypedFunction.java
index 5b5a15e4d5..aa843f6bbc 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TypedFunction.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/TypedFunction.java
@@ -120,7 +120,7 @@ public abstract class TypedFunction implements VarFunction {
 			if (c.acceptsArity(n)) { o = c; break; }
 		}
 		if (o == null)
-			throw iaex("Function ''{0}'' has no overload accepting {1} argument(s)", name(), n);
+			throw iaex("Function '%s' has no overload accepting %s argument(s)", name(), n);
 
 		var coerced = ArgCoercer.coerce(name(), o.argTypes, args);
 		try {
@@ -138,9 +138,9 @@ public abstract class TypedFunction implements VarFunction {
 			var cause = e.getTargetException();
 			if (cause instanceof RuntimeException re)
 				throw re;
-			throw iaex("Function ''{0}'' threw {1}: {2}", name(), cns(cause), cause.getMessage());
+			throw iaex("Function '%s' threw %s: %s", name(), cns(cause), cause.getMessage());
 		} catch (IllegalAccessException e) {
-			throw iaex("Function ''{0}'' invoke method must be public: {1}", name(), e.getMessage());
+			throw iaex("Function '%s' invoke method must be public: %s", name(), e.getMessage());
 		}
 	}
 
@@ -160,7 +160,7 @@ public abstract class TypedFunction implements VarFunction {
 			found.add(new Overload(m, argTypes, takesSession, variadic));
 		}
 		if (found.isEmpty())
-			throw iaex("TypedFunction subclass {0} must declare a public invoke(...) method", cls.getName());
+			throw iaex("TypedFunction subclass %s must declare a public invoke(...) method", cls.getName());
 		// Sort by descending fixedCount so larger arity overloads get matched before any
 		// variadic overload they might overlap with.
 		found.sort((a, b) -> Integer.compare(b.fixedCount, a.fixedCount));
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/VarTemplateCompiler.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/VarTemplateCompiler.java
index 81d3abde14..0c134806e7 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/VarTemplateCompiler.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/VarTemplateCompiler.java
@@ -448,7 +448,7 @@ final class VarTemplateCompiler {
 				throw parseError("Expected function name");
 			var name = body.substring(start, pos);
 			if (!Character.isLetter(name.charAt(0)))
-				throw parseError("Function name must start with a letter (got ''{0}'')", name);
+				throw parseError("Function name must start with a letter (got ''%s'')", name);
 			skipWs();
 			return name;
 		}
@@ -538,7 +538,7 @@ final class VarTemplateCompiler {
 				}
 			}
 			if (pos >= body.length() || body.charAt(pos) != '{')
-				throw parseError("Expected ''{'' after ''{0}'' in nested marker", first);
+				throw parseError("Expected ''{'' after ''%s'' in nested marker", first);
 			pos++; // consume '{'
 			var depth = 1;
 			var inEscape = false;
@@ -559,7 +559,7 @@ final class VarTemplateCompiler {
 				}
 				pos++;
 			}
-			throw parseError("Unterminated nested marker starting at index {0}", start);
+			throw parseError("Unterminated nested marker starting at index %s", start);
 		}
 
 		/**
@@ -583,14 +583,14 @@ final class VarTemplateCompiler {
 		void expect(char c) {
 			skipWs();
 			if (pos >= body.length() || body.charAt(pos) != c)
-				throw parseError("Expected ''{0}''", c);
+				throw parseError("Expected ''%s''", c);
 			pos++;
 		}
 
 		void expectEnd() {
 			skipWs();
 			if (pos < body.length())
-				throw parseError("Unexpected trailing content ''{0}''", body.substring(pos));
+				throw parseError("Unexpected trailing content ''%s''", body.substring(pos));
 		}
 
 		char peek() {
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/functions/RandomFunctions.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/functions/RandomFunctions.java
index 209d35c531..6e5a0d46f5 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/functions/RandomFunctions.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/svl/functions/RandomFunctions.java
@@ -76,7 +76,7 @@ public final class RandomFunctions {
 			return String.valueOf(ThreadLocalRandom.current().nextInt(max));
 		}
 		public String invoke(int min, int max) {
-			if (min > max) throw iaex("randInt: min ({0}) must be <= max ({1})", min, max);
+			if (min > max) throw iaex("randInt: min (%s) must be <= max (%s)", min, max);
 			return String.valueOf(ThreadLocalRandom.current().nextLong(min, (long) max + 1));
 		}
 	}
@@ -85,7 +85,7 @@ public final class RandomFunctions {
 	public static class RandLong extends TypedFunction {
 		@Override public String name() { return "randLong"; }
 		public String invoke(long min, long max) {
-			if (min > max) throw iaex("randLong: min ({0}) must be <= max ({1})", min, max);
+			if (min > max) throw iaex("randLong: min (%s) must be <= max (%s)", min, max);
 			if (max == Long.MAX_VALUE)
 				return String.valueOf(ThreadLocalRandom.current().nextLong(min, max));
 			return String.valueOf(ThreadLocalRandom.current().nextLong(min, max + 1));
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/time/GranularZonedDateTime.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/time/GranularZonedDateTime.java
index 2e1050bf66..57e3dbacfd 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/time/GranularZonedDateTime.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/time/GranularZonedDateTime.java
@@ -884,7 +884,7 @@ public class GranularZonedDateTime {
 	 */
 	public GranularZonedDateTime roll(ChronoField field, int amount) {
 		var unit = toChronoUnit(field);
-		assertArg(unit != null, "Unsupported roll field: {0}", field);
+		assertArg(unit != null, "Unsupported roll field: %s", field);
 		var newZdt = zdt.plus(amount, unit);
 		return new GranularZonedDateTime(newZdt, precision);
 	}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
index cf4cd5f780..d94dfd1d7a 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
@@ -130,7 +130,7 @@ public class AssertionUtils {
 	 * @throws IllegalArgumentException Constructed exception.
 	 */
 	public static final <T> T assertArgNotNull(String name, T o) throws IllegalArgumentException {
-		assertArg(o != null, "Argument ''{0}'' cannot be null.", name);
+		assertArg(o != null, "Argument '%s' cannot be null.", name);
 		return o;
 	}
 
@@ -160,7 +160,7 @@ public class AssertionUtils {
 	 */
 	public static final String assertArgNotNullOrBlank(String name, String o) throws IllegalArgumentException {
 		assertArgNotNull(name, o);
-		assertArg(! o.isBlank(), "Argument ''{0}'' cannot be blank.", name);
+		assertArg(! o.isBlank(), "Argument '%s' cannot be blank.", name);
 		return o;
 	}
 
@@ -292,7 +292,7 @@ public class AssertionUtils {
 		assertArgNotNull(ARG_type, type);
 		assertArgNotNull(ARG_o, o);
 		if (! type.isInstance(o))
-			throw iaex("Object is not an instance of {0}: {1}", ClassUtils.className(type), ClassUtils.className(o));
+			throw iaex("Object is not an instance of %s: %s", ClassUtils.className(type), ClassUtils.className(o));
 		return (T)o;
 	}
 
@@ -345,7 +345,7 @@ public class AssertionUtils {
 	public static final <E> Class<E>[] assertClassArrayArgIsType(String name, Class<E> type, Class<?>[] value) throws IllegalArgumentException {
 		for (var i = 0; i < value.length; i++)
 			if (! type.isAssignableFrom(value[i]))
-				throw iaex("Arg {0} did not have arg of type {1} at index {2}: {3}", name, ClassUtils.className(type), i, ClassUtils.className(value[i]));
+				throw iaex("Arg %s did not have arg of type %s at index %s: %s", name, ClassUtils.className(type), i, ClassUtils.className(value[i]));
 		return (Class<E>[])value;
 	}
 
@@ -379,7 +379,7 @@ public class AssertionUtils {
 	public static final <T> T[] assertArgNoNulls(String name, T[] o) throws IllegalArgumentException {
 		assertArgNotNull(name, o);
 		for (var i = 0; i < o.length; i++)
-			assertArg(isNotNull(o[i]), "Argument ''{0}'' parameter {1} cannot be null.", name, i);
+			assertArg(isNotNull(o[i]), "Argument '%s' parameter %s cannot be null.", name, i);
 		return o;
 	}
 
@@ -407,7 +407,7 @@ public class AssertionUtils {
 		assertArgNotNull(name, collection);
 		var i = 0;
 		for (var element : collection)
-			assertArg(isNotNull(element), "Argument ''{0}'' element at index {1} cannot be null.", name, i++);
+			assertArg(isNotNull(element), "Argument '%s' element at index %s cannot be null.", name, i++);
 		return collection;
 	}
 
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
index e2b31a2f53..1bcdaab7ae 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
@@ -353,7 +353,7 @@ public class CollectionUtils {
 	})
 	public static List<Object> arrayToList(Object array) {
 		assertArgNotNull(ARG_array, array);
-		assertArg(ClassUtils.isArray(array), "Input must be an array but was {0}", ClassUtils.className(array));
+		assertArg(ClassUtils.isArray(array), "Input must be an array but was %s", ClassUtils.className(array));
 
 		var componentType = array.getClass().getComponentType();
 		var length = Array.getLength(array);
@@ -2046,7 +2046,7 @@ public class CollectionUtils {
 			return o2.isEmpty() ? Collections.emptyList() : Collections.singletonList(o2.get());
 		if (ClassUtils.isArray(o))
 			return arrayToList(o);
-		throw rex("Could not convert object of type {0} to a list", ClassUtils.className(o));
+		throw rex("Could not convert object of type %s to a list", ClassUtils.className(o));
 	}
 
 	/**
@@ -2202,7 +2202,7 @@ public class CollectionUtils {
 	 * @return A new stream.
 	 */
 	public static Stream<Object> toStream(Object array) {
-		assertArg(ClassUtils.isArray(array), "Arg was not an array.  Type: {0}", ClassUtils.className(array));
+		assertArg(ClassUtils.isArray(array), "Arg was not an array.  Type: %s", ClassUtils.className(array));
 		var length = Array.getLength(array);
 		return IntStream.range(0, length).mapToObj(i -> Array.get(array, i));
 	}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/FileUtils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/FileUtils.java
index 4df8a1353c..17257f75fc 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/FileUtils.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/FileUtils.java
@@ -63,7 +63,7 @@ public class FileUtils {
 	public static void create(File f) {
 		if (f.exists())
 			return;
-		safe(() -> optional(f.createNewFile()).filter(x -> x).orElseThrow(() -> rex("Could not create file ''{0}''", f.getAbsolutePath())));
+		safe(() -> optional(f.createNewFile()).filter(x -> x).orElseThrow(() -> rex("Could not create file '%s'", f.getAbsolutePath())));
 	}
 
 	/**
@@ -225,12 +225,12 @@ public class FileUtils {
 		assertArgNotNull(ARG_f, f);
 		if (f.exists()) {
 			if (clean) {
-				optional(deleteFile(f)).filter(x -> x).orElseThrow(() -> rex("Could not clean directory ''{0}''", f.getAbsolutePath()));
+				optional(deleteFile(f)).filter(x -> x).orElseThrow(() -> rex("Could not clean directory '%s'", f.getAbsolutePath()));
 			} else {
 				return f;
 			}
 		}
-		optional(f.mkdirs()).filter(x -> x).orElseThrow(() -> rex("Could not create directory ''{0}''", f.getAbsolutePath()));
+		optional(f.mkdirs()).filter(x -> x).orElseThrow(() -> rex("Could not create directory '%s'", f.getAbsolutePath()));
 		return f;
 	}
 
@@ -305,7 +305,7 @@ public class FileUtils {
 		} catch (@SuppressWarnings("unused") NoSuchFileException e) {
 			return emptyOptional();
 		} catch (IOException e) {
-			throw rex(e, "Could not canonicalize ''{0}''", target);
+			throw rex(e, "Could not canonicalize '%s'", target);
 		}
 		return optional(f);
 	}
@@ -421,10 +421,10 @@ public class FileUtils {
 		var l = System.currentTimeMillis();
 		if (lm == l)
 			l++;
-		optional(f.setLastModified(l)).filter(x -> x).orElseThrow(() -> rex("Could not modify timestamp on file ''{0}''", f.getAbsolutePath()));
+		optional(f.setLastModified(l)).filter(x -> x).orElseThrow(() -> rex("Could not modify timestamp on file '%s'", f.getAbsolutePath()));
 
 		// Linux only gives 1s precision, so set the date 1s into the future.
 		if (lm == f.lastModified())
-			optional(f.setLastModified(l + 1000)).filter(x -> x).orElseThrow(() -> rex("Could not modify timestamp on file ''{0}''", f.getAbsolutePath()));
+			optional(f.setLastModified(l + 1000)).filter(x -> x).orElseThrow(() -> rex("Could not modify timestamp on file '%s'", f.getAbsolutePath()));
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java
index a743ff0f6a..5d318f2202 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java
@@ -568,7 +568,7 @@ public class IoUtils {
 			return read(in2);
 		if (in instanceof byte[] in2)
 			return read(in2);
-		throw iaex("Invalid type passed to read:  {0}", ClassUtils.className(in));
+		throw iaex("Invalid type passed to read:  %s", ClassUtils.className(in));
 	}
 
 	/**
@@ -953,4 +953,4 @@ public class IoUtils {
 	 * Constructor.
 	 */
 	protected IoUtils() {}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Shorts.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Shorts.java
index 1998b2cde4..2d44b0e3a1 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Shorts.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Shorts.java
@@ -422,7 +422,9 @@ public class Shorts {
 	public static boolean ine(CharSequence s) { return StringUtils.isNotEmpty(s); }
 
 	/**
-	 * Formats a message using {@link java.text.MessageFormat}-style {0} placeholders.
+	 * Formats a message using printf-style ({@code %s}/{@code %d}/…) placeholders.
+	 *
+	 * <p>For MessageFormat-style ({@code {0}}) patterns, use {@link #mf(String,Object...)}.
 	 *
 	 * @param p The pattern.
 	 * @param a The arguments.
@@ -432,7 +434,9 @@ public class Shorts {
 	public static String f(String p, Object...a) { return StringUtils.format(p, a); }
 
 	/**
-	 * Returns a supplier that lazily formats a message (deferred until {@link Supplier#get()}).
+	 * Returns a supplier that lazily formats a printf-style message (deferred until {@link Supplier#get()}).
+	 *
+	 * <p>For MessageFormat-style ({@code {0}}) patterns, use {@link #mfs(String,Object...)}.
 	 *
 	 * @param p The pattern.
 	 * @param a The arguments.
@@ -441,6 +445,29 @@ public class Shorts {
 	 */
 	public static Supplier<String> fs(String p, Object...a) { return () -> StringUtils.format(p, a); }
 
+	/**
+	 * Formats a message using {@link java.text.MessageFormat}-style {0} placeholders.
+	 *
+	 * <p>MessageFormat counterpart to {@link #f(String,Object...)}, for patterns that genuinely need
+	 * MessageFormat semantics (e.g. externally-authored i18n {@code .properties} strings).
+	 *
+	 * @param p The pattern.
+	 * @param a The arguments.
+	 * @return The formatted string.
+	 * @see StringUtils#mformat(String,Object...)
+	 */
+	public static String mf(String p, Object...a) { return StringUtils.mformat(p, a); }
+
+	/**
+	 * Returns a supplier that lazily formats a MessageFormat-style message (deferred until {@link Supplier#get()}).
+	 *
+	 * @param p The pattern.
+	 * @param a The arguments.
+	 * @return A supplier of the formatted string.
+	 * @see StringUtils#mformat(String,Object...)
+	 */
+	public static Supplier<String> mfs(String p, Object...a) { return () -> StringUtils.mformat(p, a); }
+
 	/**
 	 * Returns a human-readable string representation of the specified object.
 	 *
diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
index d1e130b00e..38dc58be9f 100644
--- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
+++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java
@@ -2085,19 +2085,18 @@ public class StringUtils {
 	}
 
 	/**
-	 * Formats a string using printf-style and/or MessageFormat-style format specifiers.
+	 * Formats a string using printf-style format specifiers.
 	 *
 	 * <p>
-	 * This method provides unified string formatting that supports both printf-style formatting
-	 * (similar to C's <c>printf()</c> function and Java's {@link String#format(String, Object...)})
-	 * and MessageFormat-style formatting in the same pattern.
+	 * This method provides printf-style formatting (similar to C's <c>printf()</c> function and Java's
+	 * {@link String#format(String, Object...)}). As of 10.0.0 it is <b>printf-only</b>: <c>{</c> and
+	 * <c>'</c> are ordinary literal characters (no MessageFormat <c>{0}</c> placeholders, no single-quote
+	 * escaping). For MessageFormat-style (<js>"{0}"</js>) patterns — including externally-authored i18n
+	 * <c>.properties</c> strings — use {@link #mformat(String, Object...)} instead.
 	 *
 	 * <h5 class='section'>Format Support:</h5>
 	 * <ul>
 	 *   <li><b>Printf-style:</b> <js>"%s"</js>, <js>"%d"</js>, <js>"%.2f"</js>, <js>"%1$s"</js>, etc.</li>
-	 *   <li><b>MessageFormat-style:</b> <js>"{0}"</js>, <js>"{1,number}"</js>, <js>"{2,date}"</js>, etc.</li>
-	 *   <li><b>Un-numbered MessageFormat:</b> <js>"{}"</js> - Sequential placeholders that are automatically numbered</li>
-	 *   <li><b>Mixed formats:</b> Both styles can be used in the same pattern</li>
 	 * </ul>
 	 *
 	 * <h5 class='section'>Printf Format Specifiers:</h5>
@@ -2122,9 +2121,6 @@ public class StringUtils {
 	 * <p>
 	 * Printf format specifiers follow this pattern: <c>%[argument_index$][flags][width][.precision]conversion</c>
 	 * </p>
-	 * <p>
-	 * MessageFormat placeholders follow this pattern: <c>{argument_index[,format_type[,format_style]]}</c>
-	 * </p>
 	 *
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bjava'>
@@ -2136,18 +2132,6 @@ public class StringUtils {
 	 * 	format(<js>"Price: $%.2f"</js>, 19.99);
 	 * 	<jc>// Returns: "Price: $19.99"</jc>
 	 *
-	 * 	<jc>// MessageFormat-style formatting</jc>
-	 * 	format(<js>"Hello {0}, you have {1} items"</js>, <js>"John"</js>, 5);
-	 * 	<jc>// Returns: "Hello John, you have 5 items"</jc>
-	 *
-	 * 	<jc>// Un-numbered MessageFormat placeholders (sequential)</jc>
-	 * 	format(<js>"Hello {}, you have {} items"</js>, <js>"John"</js>, 5);
-	 * 	<jc>// Returns: "Hello John, you have 5 items"</jc>
-	 *
-	 * 	<jc>// Mixed format styles in the same pattern</jc>
-	 * 	format(<js>"User {0} has %d items and %s status"</js>, <js>"Alice"</js>, 10, <js>"active"</js>);
-	 * 	<jc>// Returns: "User Alice has 10 items and active status"</jc>
-	 *
 	 * 	<jc>// Width and alignment (printf)</jc>
 	 * 	format(<js>"Name: %-20s Age: %3d"</js>, <js>"John"</js>, 25);
 	 * 	<jc>// Returns: "Name: John                 Age:  25"</jc>
@@ -2157,21 +2141,16 @@ public class StringUtils {
 	 * 	<jc>// Returns: "Color: #FF5733"</jc>
 	 *
 	 * 	<jc>// Argument index (reuse arguments)</jc>
-	 * 	format(<js>"%1$s loves %2$s, and {0} also loves %3$s"</js>, <js>"Alice"</js>, <js>"Bob"</js>, <js>"Charlie"</js>);
+	 * 	format(<js>"%1$s loves %2$s, and %1$s also loves %3$s"</js>, <js>"Alice"</js>, <js>"Bob"</js>, <js>"Charlie"</js>);
 	 * 	<jc>// Returns: "Alice loves Bob, and Alice also loves Charlie"</jc>
 	 * </p>
 	 *
 	 * <h5 class='section'>Comparison with mformat():</h5>
-	 * <p>
-	 * This method supports both MessageFormat-style and printf-style formats.
-	 * </p>
 	 * <p class='bjava'>
-	 * 	<jc>// Both styles supported (this method)</jc>
+	 * 	<jc>// Printf style (this method)</jc>
 	 * 	format(<js>"Hello %s, you have %d items"</js>, <js>"John"</js>, 5);
-	 * 	format(<js>"Hello {0}, you have {1} items"</js>, <js>"John"</js>, 5);
-	 * 	format(<js>"User {0} has %d items"</js>, <js>"Alice"</js>, 10);
 	 *
-	 * 	<jc>// MessageFormat style only</jc>
+	 * 	<jc>// MessageFormat style</jc>
 	 * 	mformat(<js>"Hello {0}, you have {1} items"</js>, <js>"John"</js>, 5);
 	 * </p>
 	 *
@@ -2181,16 +2160,51 @@ public class StringUtils {
 	 * or cause a {@link NullPointerException} for numeric conversions (consistent with {@link String#format(String, Object...)}).
 	 * </p>
 	 *
-	 * @param pattern The format string supporting both MessageFormat and printf-style placeholders.
+	 * @param pattern The printf-style format string.
 	 * @param args The arguments to format.
 	 * @return The formatted string.
 	 * @throws IllegalFormatException If the format string is invalid or arguments don't match the format specifiers.
-	 * @see StringFormat for detailed format specification
 	 * @see String#format(String, Object...)
+	 * @see #mformat(String, Object...)
 	 * @see StringFormat for detailed format specification
 	 */
 	public static String format(String pattern, Object...args) {
-		return StringFormat.format(pattern, args);
+		return StringFormat.formatPrintf(pattern, args);
+	}
+
+	/**
+	 * Formats a pattern string using {@link java.text.MessageFormat}-style placeholders only.
+	 *
+	 * <p>
+	 * This is the MessageFormat counterpart to {@link #format(String, Object...)}: it is intended for
+	 * patterns that use MessageFormat syntax (<js>"{0}"</js>, <js>"{1,number}"</js>, <js>"{2,date}"</js>,
+	 * <js>"''"</js>-quoting) — most importantly externally-authored patterns such as i18n
+	 * <c>.properties</c> resource-bundle strings. Use {@link #format(String, Object...)} for printf-style
+	 * (<js>"%s"</js>/<js>"%d"</js>) patterns.
+	 *
+	 * <p>
+	 * Rendering is delegated to {@link java.text.MessageFormat}. As a convenience, when no arguments are
+	 * supplied the pattern is returned verbatim (so <js>"''"</js>-quoting is left untouched for placeholder-free
+	 * strings).
+	 *
+	 * <h5 class='section'>Examples:</h5>
+	 * <p class='bjava'>
+	 * 	mformat(<js>"Hello {0}, you have {1} items"</js>, <js>"John"</js>, 5);
+	 * 	<jc>// Returns: "Hello John, you have 5 items"</jc>
+	 * </p>
+	 *
+	 * @param pattern The MessageFormat-style pattern.
+	 * @param args The arguments to format.
+	 * @return The formatted string.
+	 * @throws IllegalArgumentException If the pattern is <jk>null</jk> or contains invalid placeholders.
+	 * @see #format(String, Object...)
+	 * @see java.text.MessageFormat
+	 */
+	public static String mformat(String pattern, Object...args) {
+		assertArgNotNull("pattern", pattern);
+		if (args.length == 0)
+			return pattern;
+		return MessageFormat.format(pattern, args);
 	}
 
 	/**
@@ -2198,7 +2212,7 @@ public class StringUtils {
 	 *
 	 * <p>
 	 * Supports named MessageFormat-style variables: <js>"{key}"</js> where <c>key</c> is resolved by the function.
-	 * For un-numbered sequential placeholders <js>"{}"</js>, use {@link #format(String, Object...)} instead.
+	 * For numbered MessageFormat placeholders <js>"{0}"</js>, use {@link #mformat(String, Object...)} instead.
 	 *
 	 * <p>
 	 * Variable values are converted to strings using {@link #readable(Object)} to ensure consistent,
@@ -2281,7 +2295,7 @@ public class StringUtils {
 	 *
 	 * <p>
 	 * Supports named MessageFormat-style variables: <js>"{key}"</js> where <c>key</c> is a map key.
-	 * For un-numbered sequential placeholders <js>"{}"</js>, use {@link #format(String, Object...)} instead.
+	 * For numbered MessageFormat placeholders <js>"{0}"</js>, use {@link #mformat(String, Object...)} instead.
 	 *
 	 * <p>
 	 * Variable values are converted to strings using {@link #readable(Object)} to ensure consistent,
@@ -5210,7 +5224,7 @@ public class StringUtils {
 			return null;
 		if (s.length() == 1)
 			return s.charAt(0);
-		throw iaex("Invalid character: ''{0}''", s);
+		throw iaex("Invalid character: '%s'", s);
 	}
 
 	/**
@@ -6900,9 +6914,9 @@ public class StringUtils {
 		}
 
 		if (start == -1)
-			throw iaex("Start character '{' not found in string:  {0}", s);
+			throw iaex("Start character { not found in string:  %s", s);
 		if (end == -1)
-			throw iaex("End character '}' not found in string  {0}", s);
+			throw iaex("End character } not found in string  %s", s);
 		return splitNested(s.substring(start, end));
 	}
 
@@ -7008,7 +7022,7 @@ public class StringUtils {
 		if (state == S4)
 			l.add(s.substring(mark));
 		else if (state == S2 || state == S3)
-			throw iaex("Unmatched string quotes: {0}", s);
+			throw iaex("Unmatched string quotes: %s", s);
 		return l.toArray(new String[l.size()]);
 	}
 
@@ -8035,7 +8049,7 @@ public class StringUtils {
 		if (isEmpty(str))
 			return str;
 		if (wrapLength <= 0)
-			throw iaex("wrapLength must be > 0: {0}", wrapLength);
+			throw iaex("wrapLength must be > 0: %s", wrapLength);
 		if (newline == null)
 			throw iaex("newline cannot be null");
 
@@ -8699,4 +8713,4 @@ public class StringUtils {
 	 * Constructor.
 	 */
 	protected StringUtils() {}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/Console_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/Console_Test.java
index ac7034037f..e150ecc66f 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/Console_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/Console_Test.java
@@ -77,21 +77,21 @@ class Console_Test extends TestBase {
 
 	@Test
 	void a02_out_withSingleArgument() {
-		Console.out("test{0}", 123);
+		Console.out("test%s", 123);
 		var output = outCapture.toString();
 		assertTrue(output.contains("test123"), output);
 	}
 
 	@Test
 	void a03_out_withMultipleArguments() {
-		Console.out("test{0} {1} {2}", "a", "b", "c");
+		Console.out("test%s %s %s", "a", "b", "c");
 		var output = outCapture.toString();
 		assertTrue(output.contains("testa b c"), output);
 	}
 
 	@Test
 	void a04_out_withNullArgument() {
-		Console.out("test{0}", (Object)null);
+		Console.out("test%s", (Object)null);
 		var output = outCapture.toString();
 		assertTrue(output.contains("testnull"), output);
 	}
@@ -111,35 +111,29 @@ class Console_Test extends TestBase {
 	}
 
 	@Test
-	void a07_out_withMessageFormatPattern() {
-		Console.out("Value: {0,number}", 12345);
+	void a07_out_withNumericArgument() {
+		Console.out("Value: %d", 12345);
 		var output = outCapture.toString();
-		assertTrue(output.contains("Value:"), output);
-		// MessageFormat may add locale-specific formatting (e.g., commas), so check for digits
-		assertTrue(output.contains("Value:") && output.chars().anyMatch(Character::isDigit),
-			"Output should contain 'Value:' and at least one digit. Actual: " + output);
+		assertTrue(output.contains("Value: 12345"), output);
 	}
 
 	@Test
 	void a08_out_withSpecialCharacters() {
-		Console.out("test{0}", "a\nb\tc");
+		Console.out("test%s", "a\nb\tc");
 		var output = outCapture.toString();
 		assertTrue(output.contains("testa"), output);
 	}
 
 	@Test
-	void a09_out_withNumberFormatting() {
-		Console.out("Number: {0,number,integer}", 1234);
+	void a09_out_withIntegerFormatting() {
+		Console.out("Number: %d", 1234);
 		var output = outCapture.toString();
-		assertTrue(output.contains("Number:"), output);
-		// MessageFormat may add locale-specific formatting (e.g., commas), so check for digits
-		assertTrue(output.contains("Number:") && output.chars().anyMatch(Character::isDigit),
-			"Output should contain 'Number:' and at least one digit. Actual: " + output);
+		assertTrue(output.contains("Number: 1234"), output);
 	}
 
 	@Test
-	void a10_out_withDateFormatting() {
-		Console.out("Date: {0,date}", new java.util.Date(0));
+	void a10_out_withDateArgument() {
+		Console.out("Date: %s", new java.util.Date(0));
 		var output = outCapture.toString();
 		assertTrue(output.contains("Date:"), output);
 	}
@@ -165,21 +159,21 @@ class Console_Test extends TestBase {
 
 	@Test
 	void b02_err_withSingleArgument() {
-		Console.err("test{0}", 123);
+		Console.err("test%s", 123);
 		var output = errCapture.toString();
 		assertTrue(output.contains("test123"), output);
 	}
 
 	@Test
 	void b03_err_withMultipleArguments() {
-		Console.err("test{0} {1} {2}", "a", "b", "c");
+		Console.err("test%s %s %s", "a", "b", "c");
 		var output = errCapture.toString();
 		assertTrue(output.contains("testa b c"), output);
 	}
 
 	@Test
 	void b04_err_withNullArgument() {
-		Console.err("test{0}", (Object)null);
+		Console.err("test%s", (Object)null);
 		var output = errCapture.toString();
 		assertTrue(output.contains("testnull"), output);
 	}
@@ -199,35 +193,29 @@ class Console_Test extends TestBase {
 	}
 
 	@Test
-	void b07_err_withMessageFormatPattern() {
-		Console.err("Error: {0,number}", 12345);
+	void b07_err_withNumericArgument() {
+		Console.err("Error: %d", 12345);
 		var output = errCapture.toString();
-		assertTrue(output.contains("Error:"), output);
-		// MessageFormat may add locale-specific formatting (e.g., commas), so check for digits
-		assertTrue(output.contains("Error:") && output.chars().anyMatch(Character::isDigit),
-			"Output should contain 'Error:' and at least one digit. Actual: " + output);
+		assertTrue(output.contains("Error: 12345"), output);
 	}
 
 	@Test
 	void b08_err_withSpecialCharacters() {
-		Console.err("test{0}", "a\nb\tc");
+		Console.err("test%s", "a\nb\tc");
 		var output = errCapture.toString();
 		assertTrue(output.contains("testa"), output);
 	}
 
 	@Test
-	void b09_err_withNumberFormatting() {
-		Console.err("Number: {0,number,integer}", 1234);
+	void b09_err_withIntegerFormatting() {
+		Console.err("Number: %d", 1234);
 		var output = errCapture.toString();
-		assertTrue(output.contains("Number:"), output);
-		// MessageFormat may add locale-specific formatting (e.g., commas), so check for digits
-		assertTrue(output.contains("Number:") && output.chars().anyMatch(Character::isDigit),
-			"Output should contain 'Number:' and at least one digit. Actual: " + output);
+		assertTrue(output.contains("Number: 1234"), output);
 	}
 
 	@Test
-	void b10_err_withDateFormatting() {
-		Console.err("Date: {0,date}", new java.util.Date(0));
+	void b10_err_withDateArgument() {
+		Console.err("Date: %s", new java.util.Date(0));
 		var output = errCapture.toString();
 		assertTrue(output.contains("Date:"), output);
 	}
@@ -271,11 +259,12 @@ class Console_Test extends TestBase {
 
 	@Test
 	void c03_complexFormatting() {
-		Console.out("User {0} has {1} items worth {2,number,currency}", "John", 5, 99.99);
+		Console.out("User %s has %d items worth $%.2f", "John", 5, 99.99);
 		var output = outCapture.toString();
 		assertTrue(output.contains("User"), output);
 		assertTrue(output.contains("John"), output);
 		assertTrue(output.contains("5"), output);
+		assertTrue(output.contains("99.99"), output);
 	}
 }
 
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/lang/StringFormat_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/lang/StringFormat_Test.java
index 07396da9be..bcf5c6b742 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/lang/StringFormat_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/lang/StringFormat_Test.java
@@ -16,26 +16,31 @@
  */
 package org.apache.juneau.commons.lang;
 
-import static java.util.stream.Collectors.*;
 import static org.apache.juneau.commons.utils.Shorts.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.math.*;
-import java.text.*;
 import java.util.*;
-import java.util.stream.*;
 
 import org.apache.juneau.commons.*;
 import org.apache.juneau.commons.function.*;
 import org.junit.jupiter.api.*;
 
+/**
+ * Tests for the printf-only {@link StringFormat} engine.
+ *
+ * <p>
+ * MessageFormat-grammar behavior is no longer owned by this engine; it lives behind
+ * {@code Shorts.mf(...)}/{@code Shorts.mfs(...)} / {@code StringUtils.mformat(...)} (backed by
+ * {@link java.text.MessageFormat}) and is exercised in {@code Shorts_Test}.
+ */
 @SuppressWarnings({
 	"java:S5961" // High assertion count acceptable in comprehensive test
 })
 class StringFormat_Test extends TestBase {
 
 	private static StringFormat fs(String pattern) {
-		return StringFormat.of(pattern);
+		return StringFormat.ofPrintf(pattern);
 	}
 
 	private static String stringify(ThrowingSupplier<String> supplier) {
@@ -84,100 +89,6 @@ class StringFormat_Test extends TestBase {
 		}
 	}
 
-	private static void assertMessageFormat(String pattern, Locale locale, Object... args) {
-		var expected = stringify(()->new MessageFormat(pattern, locale).format(args));
-		var actual = "";
-		var fmt = (StringFormat)null;
-		try {
-			var fmt2 = fs(pattern);
-			fmt = fmt2;
-			actual = stringify(()->fmt2.format(locale, args));
-		} catch (Throwable t) {
-			actual = cns(t) + ": " + t.getLocalizedMessage();
-		}
-		if (!expected.equals(actual)) {
-			System.out.println("Pattern: " + pattern);
-			var toPattern = o(fmt).map(x -> x.toPattern()).orElse(null);
-			System.out.println("toPattern(): " + toPattern);
-			fail("Pattern: " + pattern + ", toPattern(): " + toPattern + ", expected: <" + expected + "> but was: <" + actual + ">");
-		}
-	}
-
-	private static void assertMessageFormat(String pattern, Object... args) {
-		var expected = stringify(()->MessageFormat.format(pattern, args));
-		var actual = "";
-		var fmt = (StringFormat)null;
-		try {
-			var fmt2 = fs(pattern);
-			fmt = fmt2;
-			actual = stringify(()->fmt2.format(args));
-		} catch (Throwable t) {
-			actual = cns(t) + ": " + t.getLocalizedMessage();
-		}
-		if (!expected.equals(actual)) {
-			System.out.println("Pattern: " + pattern);
-			var toPattern = o(fmt).map(x -> x.toPattern()).orElse(null);
-			System.out.println("toPattern(): " + toPattern);
-			fail("Pattern: " + pattern + ", toPattern(): " + toPattern + ", expected: <" + expected + "> but was: <" + actual + ">");
-		}
-	}
-
-	private static void assertMixedFormat(String expected, String pattern, Object... args) {
-		var actual = "";
-		var fmt = (StringFormat)null;
-		try {
-			var fmt2 = fs(pattern);
-			fmt = fmt2;
-			actual = stringify(()->fmt2.format(args));
-		} catch (Throwable t) {
-			actual = cns(t) + ": " + t.getLocalizedMessage();
-		}
-		if (!expected.equals(actual)) {
-			System.out.println("Pattern: " + pattern);
-			var toPattern = o(fmt).map(x -> x.toPattern()).orElse(null);
-			System.out.println("toPattern(): " + toPattern);
-			fail("Pattern: " + pattern + ", toPattern(): " + toPattern + ", expected: <" + expected + "> but was: <" + actual + ">");
-		}
-	}
-
-	//====================================================================================================
-	// MessageFormat tests
-	//====================================================================================================
-	@Test void a01_messageFormat() {
-		assertMessageFormat("Hello {0}", "John");
-		assertMessageFormat("Price: {0,number,currency}", 19.99);
-		assertMessageFormat("{0} has {1} items and {2} friends", "John", 5, 3);
-		assertMessageFormat("Hello {0} world", "John");
-		assertMessageFormat("Count: {0,number,integer}", 1234);
-		assertMessageFormat("Date: {0,date,short}", new Date(0));
-		assertMessageFormat("Time: {0,time,short}", new Date(0));
-		// Simple {0} with Date - uses DATE_FORMAT_CACHE for formatting
-		assertMessageFormat("Date: {0}", new Date(0));
-		assertMessageFormat("Value: {0}", (String)null);
-		assertMessageFormat("Name: {0}", "");
-		assertMessageFormat("Text: {0}\nNewline\tTab", "Hello");
-		assertMessageFormat("Unicode: {0} 中文", "Test");
-		assertMessageFormat("{0}{1}", "A", "B");
-		assertMessageFormat("{0} and {0} again", "Hello");
-		assertMessageFormat("Price: {0,number,currency}, Count: {1,number,integer}, Date: {2,date,short}", 19.99, 42, new Date(0L));
-		assertMessageFormat("Price: {0,number,currency}", Locale.US, 19.99);
-		assertMessageFormat("Price: {0,number,currency}", Locale.FRANCE, 19.99);
-		assertMessageFormat("a '{0}' b");
-		assertMessageFormat("a ''{0}'' b", 1);
-		assertMessageFormat("'{0}'");
-		assertMessageFormat("''{0}''", 1);
-
-		// Errors
-		assertMessageFormat("Set: {{0}}", 50);
-		assertMessageFormat("Set: {{0}} and {{1}}", "A", "B");
-		assertMessageFormat("Hello {0}");
-		assertMessageFormat("{0} has {1} items and {2} friends", "John", 5);
-		assertMessageFormat("Hello {");
-		assertMessageFormat("Hello {0");
-		assertMessageFormat("Hello '");
-		assertMessageFormat("Hello 'x");
-	}
-
 	//====================================================================================================
 	// StringFormat (printf) tests
 	//====================================================================================================
@@ -272,45 +183,18 @@ class StringFormat_Test extends TestBase {
 	}
 
 	//====================================================================================================
-	// Mixed format tests
+	// Printf value-adds beyond raw String.format
 	//====================================================================================================
-	@Test void a03_mixedFormat() {
-		assertMixedFormat("Hello John, you have 5 items", "Hello {0}, you have %d items", "John", 5);
-		assertMixedFormat("User Alice has admin and 10 items", "User {0} has %s and {2} items", "Alice", "admin", 10);
-		assertMixedFormat("Alice loves Bob, and Alice also loves Charlie", "%1$s loves %2$s, and {0} also loves %3$s", "Alice", "Bob", "Charlie");
-		assertMixedFormat("Alice has 5 items, Bob has 3 items, total: 8", "{0} has %d items, {2} has %d items, total: %d", "Alice", 5, "Bob", 3, 8);
-		assertMixedFormat("Alice Bob Charlie", "{0} %2$s {2}", "Alice", "Bob", "Charlie");
-		assertMixedFormat("Hello John, you have 5 items", "Hello {0}, you have %d items", "John", 5);
-		assertMixedFormat("A B B D C", "{0} %s {1} %s {2}", "A", "B", "C", "D");
-		assertMixedFormat("ABB", "{0}%s{1}", "A", "B", "C");
-		assertMixedFormat("Hello and Hello are the same", "{0} and %1$s are the same", "Hello");
+	@Test void a04_printfValueAdds() {
+		// { and ' are literal text on the printf path (java.util.Formatter semantics).
+		assertEquals("Hello {0} world", fs("Hello {0} world").format("ignored-extra-arg"));
+		assertEquals("a '{0}' b", fs("a '{0}' b").format("ignored"));
 
-		// Errors
-		assertMixedFormat("MissingFormatArgumentException: Format specifier '%s'", "Hello {0} and %s", "John");
-		assertMixedFormat("John has 5 items and {2} friends", "{0} has %d items and {2} friends", "John", 5);
-		assertMixedFormat("MissingFormatArgumentException: Format specifier '%s'", "%1$s loves %2$s, and {0} also loves %3$s", "Alice", "Bob");
-	}
+		// BigDecimal with %d - String.format throws exception, but our optimized code handles it via longValue().
+		assertEquals("Number: 42", fs("Number: %d").format(new BigDecimal("42")));
 
-	//====================================================================================================
-	// Supported but deviates from MessageFormat/String.format
-	//====================================================================================================
-	@Test void a04_supportedButDeviatesFromMessageFormat() {
-		// {} is not supported by MessageFormat, only by StringFormat as an extension
-		assertMixedFormat("Hello John world", "Hello {} world", "John");
-		assertMixedFormat("A B C", "{} {} {}", "A", "B", "C");
-		// BigDecimal with %d - String.format throws exception, but our optimized code handles it
-		assertMixedFormat("Number: 42", "Number: %d", new BigDecimal("42"));
-		// MessageFormat throws NullPointerException when locale is null, but StringFormat handles it
-		// So we test StringFormat's behavior directly instead of comparing with MessageFormat
-		// Use Locale.US to get dollar sign for currency formatting
-		// Note: Java 25 changed currency format from "$19.99" to "USD 19.99", so we check for both
-		var fmt = fs("Price: {0,number,currency}");
-		var result = stringify(()->fmt.format(Locale.US, 19.99));
-		assertTrue(result.contains("19.99"), "Result should contain '19.99', but was: " + result);
-		assertTrue(result.contains("Price: "), "Result should contain 'Price: ', but was: " + result);
-		// Accept either old format ($19.99) or new format (USD 19.99) for Java 25 compatibility
-		assertTrue(result.contains("$") || result.contains("USD"),
-			"Result should contain '$' or 'USD' for currency, but was: " + result);
+		// Lenient null handling for simple string conversions (renders "null" rather than throwing).
+		assertEquals("Value: null", fs("Value: %s").format((Object)null));
 	}
 
 	//====================================================================================================
@@ -323,36 +207,36 @@ class StringFormat_Test extends TestBase {
 
 	@Test void a06_caching() {
 		// Should return the same instance due to caching
-		assertSame(fs("Hello {0}"), fs("Hello {0}"));
+		assertSame(fs("Hello %s"), fs("Hello %s"));
 
 		// Different patterns should return different instances
-		assertNotSame(fs("Hello {0}"), fs("Hello %s"));
+		assertNotSame(fs("Hello %s"), fs("Hello %d"));
 
 		// Constructor doesn't use cache, so instances should be different
-		var fmt1 = new StringFormat("Hello {0}");
-		var fmt2 = new StringFormat("Hello {0}");
+		var fmt1 = new StringFormat("Hello %s");
+		var fmt2 = new StringFormat("Hello %s");
 		assertNotSame(fmt1, fmt2);
 		assertEquals(fmt1, fmt2); // But they should be equal
 	}
 
 	@Test void a07_equalsAndHashCode() {
-		var fmt1 = StringFormat.of("Hello {0}");
-		var fmt2 = StringFormat.of("Hello {0}");
-		var fmt3 = StringFormat.of("Hello %s");
+		var fmt1 = StringFormat.ofPrintf("Hello %s");
+		var fmt2 = StringFormat.ofPrintf("Hello %s");
+		var fmt3 = StringFormat.ofPrintf("Hello %d");
 
-		// Test equals - covers line 623
+		// Test equals
 		assertEquals(fmt1, fmt2);
 		assertNotEquals(fmt1, fmt3);
 
-		// Test equals with null - covers line 623 (instanceof check fails)
+		// Test equals with null (instanceof check fails)
 		assertNotEquals(null, fmt1);
 
-		// Test equals with different type - covers line 623 (instanceof check fails)
-		assertNotEquals("Hello {0}", fmt1);
+		// Test equals with different type (instanceof check fails)
+		assertNotEquals("Hello %s", fmt1);
 		assertNotEquals(fmt1, new Object());
 
-		// Test equals with different pattern - covers line 623 (pattern comparison)
-		var fmt4 = StringFormat.of("Different pattern");
+		// Test equals with different pattern
+		var fmt4 = StringFormat.ofPrintf("Different pattern");
 		assertNotEquals(fmt1, fmt4);
 
 		// Test hashCode
@@ -360,35 +244,24 @@ class StringFormat_Test extends TestBase {
 	}
 
 	@Test void a08_toString() {
-		assertEquals("Hello {0}", fs("Hello {0}").toString());
+		assertEquals("Hello %s", fs("Hello %s").toString());
 	}
 
 	@Test void a09_toPattern() {
-		// Literal tokens
+		// Literal tokens ({ and ' are literal on the printf path)
 		assertEquals("[L:Hello ]", fs("Hello ").toPattern());
-		assertEquals("[L:a ][L:{0}][L: b]", fs("a '{0}' b").toPattern());  // Single quotes don't escape MessageFormat
-
-		// MessageFormat tokens - simple (content == null) - Line 228: content == null branch
-		assertEquals("[L:Hello ][M:s0]", fs("Hello {0}").toPattern());
-		assertEquals("[L:Hello ][M:s0][L: ][M:s1]", fs("Hello {0} {1}").toPattern());
-
-		// MessageFormat tokens - complex (content != null) - Line 228: content != null branch
-		assertEquals("[L:Price: ][M:o0:{0,number,currency}]", fs("Price: {0,number,currency}").toPattern());
-		assertEquals("[L:Count: ][M:o0:{0,number,integer}]", fs("Count: {0,number,integer}").toPattern());
-		assertEquals("[L:Date: ][M:o0:{0,date,short}]", fs("Date: {0,date,short}").toPattern());
+		assertEquals("[L:a '{0}' b]", fs("a '{0}' b").toPattern());
+		assertEquals("[L:Hello {0}]", fs("Hello {0}").toPattern());
 
-		// StringFormat tokens - Line 406: StringFormatToken.toString()
+		// StringFormat (printf) tokens
 		assertEquals("[L:Hello ][S:s0:%s]", fs("Hello %s").toPattern());  // Simple format: 's'
 		assertEquals("[L:Number: ][S:d0:%d]", fs("Number: %d").toPattern());  // Simple format: 'd'
 		assertEquals("[L:Hex: ][S:x0:%x]", fs("Hex: %x").toPattern());  // Simple format: 'x'
 		assertEquals("[L:Float: ][S:z0:%.2f]", fs("Float: %.2f").toPattern());  // Complex format: 'z' (other)
 		assertEquals("[L:ID: ][S:z0:%05d]", fs("ID: %05d").toPattern());  // Complex format: 'z' (other)
+		assertEquals("[L:Hello ][S:s0:%s][L: ][S:s1:%s]", fs("Hello %s %s").toPattern());
 
-		// Mixed formats
-		assertEquals("[L:Hello ][M:s0][L:, you have ][S:d1:%d][L: items]", fs("Hello {0}, you have %d items").toPattern());
-		assertEquals("[L:Price: ][M:o0:{0,number,currency}][L: and ][S:s1:%s]", fs("Price: {0,number,currency} and %s").toPattern());
-
-		// Time conversions (2-character) - Line 529: 't' or 'T' handling
+		// Time conversions (2-character) - 't' or 'T' handling
 		assertEquals("[L:Month: ][S:z0:%tm]", fs("Month: %tm").toPattern());  // %tm is 2-character time conversion
 		assertEquals("[L:Year: ][S:z0:%tY]", fs("Year: %tY").toPattern());  // %tY is 2-character time conversion
 		assertEquals("[L:Date: ][S:z0:%TD]", fs("Date: %TD").toPattern());  // %TD is 2-character time conversion
@@ -400,91 +273,13 @@ class StringFormat_Test extends TestBase {
 	}
 
 	@Test void a10_veryLongPattern() {
-		var pattern = "Start: " + IntStream.range(0, 10).mapToObj(i -> "{" + i + "}").collect(joining(" ")) + " ";
-		var args = IntStream.range(0, 10).boxed().toArray();
-		assertMessageFormat(pattern, args);
-	}
-
-	@Test void a11_parseIndexErrors() {
-		assertThrows(IllegalArgumentException.class, () -> fs("Hello {abc}"));
-	}
-
-	//====================================================================================================
-	// Test coverage for line 162 branches in MessageFormatToken.append()
-	//====================================================================================================
-	@Test void a14_messageFormatTokenBranches() {
-		// Test args == null branch - covers line 162 (args == null)
-		var fmt1 = StringFormat.of("Hello {0}");
-		var result1 = fmt1.format((Object[])null);
-		assertEquals("Hello {0}", result1);
-
-		// Test with complex format and null args
-		var fmt2 = StringFormat.of("Price: {0,number,currency}");
-		var result2 = fmt2.format((Object[])null);
-		assertEquals("Price: {0,number,currency}", result2);
-
-		// Test locale == null branch - covers line 167 (locale == null ? Locale.getDefault() : locale)
-		// When locale is null, should use Locale.getDefault()
-		var fmt3 = StringFormat.of("Hello {0}");
-		var result3 = fmt3.format((Locale)null, "World");
-		// Should format using default locale
-		assertEquals("Hello World", result3);
-
-		// Test locale != null branch - covers line 167 (else branch)
-		// When locale is provided, should use that locale
-		var fmt4 = StringFormat.of("Price: {0,number,currency}");
-		var result4 = fmt4.format(Locale.US, 19.99);
-		// Should format using US locale (dollar sign)
-		assertTrue(result4.contains("19.99") || result4.contains("$19.99"));
-
-		var result5 = fmt4.format(Locale.FRANCE, 19.99);
-		// Should format using France locale (different currency symbol)
-		assertTrue(result5.contains("19.99") || result5.contains("19,99"));
-
-		// Note on other branches:
-		// - index >= args.length: This branch exists but testing it is complex because MessageFormat
-		//   behavior with missing arguments may vary. The existing test a01_messageFormat() already
-		//   tests patterns with missing args (line 188: assertMessageFormat("Hello {0}") with no args).
-		// - index < 0: parseIndexMF can parse negative numbers (it uses Integer.parseInt), so technically
-		//   a pattern like "{-1}" could create index = -1. However, MessageFormat syntax doesn't support
-		//   negative indices, so this is a defensive check. The branch exists but is unlikely to be
-		//   reached through normal MessageFormat patterns. Testing it would require either: (1) a pattern
-		//   that somehow parses to a negative index, or (2) directly constructing a MessageFormatToken
-		//   with a negative index via reflection. This may be marked as HTT (Hard To Test) if it cannot
-		//   be reached through the public API.
-	}
-
-	//====================================================================================================
-	// Test coverage for line 217 branches in StringFormatToken.append()
-	//====================================================================================================
-	@Test void a15_stringFormatTokenBranches() {
-		// Test args == null branch - covers line 217 (args == null)
-		var fmt1 = StringFormat.of("Hello %s");
-		assertThrows(MissingFormatArgumentException.class, () -> fmt1.format((Object[])null));
-
-		// Test with complex format and null args
-		var fmt2 = StringFormat.of("Price: %.2f");
-		assertThrows(MissingFormatArgumentException.class, () -> fmt2.format((Object[])null));
-
-		// Test with explicit index format and null args
-		var fmt3 = StringFormat.of("First: %1$s, Second: %2$s");
-		assertThrows(MissingFormatArgumentException.class, () -> fmt3.format((Object[])null));
-
-		// Note on other branches:
-		// - index >= args.length: This branch exists but testing it is complex because the index
-		//   calculation depends on how sequential vs explicit indices are handled. The existing
-		//   test a02_stringFormat() already tests patterns with missing args (line 282-283:
-		//   assertStringFormat("Hello %s") and assertStringFormat("Hello %s and %s", "John")).
-		//   These tests verify that MissingFormatArgumentException is thrown, which exercises
-		//   the index >= args.length branch.
-		// - index < 0: parseIndexSF can parse negative numbers (it uses Integer.parseInt), and the
-		//   index is calculated as parseIndexSF(...) - 1. So if parseIndexSF returns 0, index = -1.
-		//   However, printf-style format specifiers use 1-based indexing (e.g., %1$s), so parseIndexSF
-		//   would return 1, making index = 0. A negative index would require parseIndexSF to return 0,
-		//   which would mean a format specifier like %0$s. While this is technically possible to parse,
-		//   it's invalid printf syntax (indices must be >= 1). The branch exists as a defensive check
-		//   but is unlikely to be reached through normal printf patterns. This may be marked as HTT
-		//   (Hard To Test) if it cannot be reached through the public API.
+		var sb = new StringBuilder("Start:");
+		var args = new Object[10];
+		for (var i = 0; i < 10; i++) {
+			sb.append(" %s");
+			args[i] = i;
+		}
+		assertStringFormat(sb.toString(), args);
 	}
 
 	@Test void a12_localeHandling() {
@@ -493,37 +288,48 @@ class StringFormat_Test extends TestBase {
 		assertStringFormat("Number: %d", (Locale)null, 42);
 		assertStringFormat("Float: %.2f", (Locale)null, 3.14);  // Use .2f for consistent formatting
 
-		// Test with default locale (covers locale.equals(Locale.getDefault()) on line 260)
+		// Test with default locale (covers locale.equals(Locale.getDefault()))
 		assertStringFormat("Hello %s", Locale.getDefault(), "John");
 		assertStringFormat("Number: %d", Locale.getDefault(), 42);
 		assertStringFormat("Float: %.2f", Locale.getDefault(), 3.14);  // Use .2f for consistent formatting
 
-		// Test with non-default locale (covers else branch on line 259 and false case on line 260)
+		// Test with non-default locale (covers else branch and false case)
 		assertStringFormat("Hello %s", Locale.FRANCE, "John");
 		assertStringFormat("Number: %d", Locale.GERMANY, 42);
 		assertStringFormat("Float: %.2f", Locale.JAPAN, 3.14);  // Use .2f for consistent formatting
 	}
 
 	//====================================================================================================
-	// format(String, Locale, Object...) - covers lines 413-415
+	// formatPrintf(String, Locale, Object...)
 	//====================================================================================================
-	@Test void a13_format_withLocale() {
-		// Test with empty args - covers lines 413-414 (args.length == 0, return pattern)
-		String result1 = StringFormat.format("Hello", Locale.US);
-		assertEquals("Hello", result1);
+	@Test void a13_formatPrintf_withLocale() {
+		// Test with empty args (args.length == 0, return pattern)
+		assertEquals("Hello", StringFormat.formatPrintf("Hello", Locale.US));
+		assertEquals("Test pattern", StringFormat.formatPrintf("Test pattern", Locale.FRANCE));
 
-		String result2 = StringFormat.format("Test pattern", Locale.FRANCE);
-		assertEquals("Test pattern", result2);
+		// Test with args
+		assertEquals("Hello World", StringFormat.formatPrintf("Hello %s", Locale.US, "World"));
 
-		// Test with args - covers line 415 (calls of(pattern).format(locale, args))
-		String result3 = StringFormat.format("Hello %s", Locale.US, "World");
-		assertEquals("Hello World", result3);
+		// Test with null locale and empty args
+		assertEquals("Test", StringFormat.formatPrintf("Test", (Locale)null));
 
-		String result4 = StringFormat.format("Price: {0,number,currency}", Locale.US, 19.99);
-		assertTrue(result4.contains("19.99") || result4.contains("$19.99"));
+		// Default-locale convenience entry point
+		assertEquals("Hello World", StringFormat.formatPrintf("Hello %s", "World"));
+		assertEquals("NoArgs", StringFormat.formatPrintf("NoArgs"));
+	}
 
-		// Test with null locale and empty args - covers line 413-414
-		String result5 = StringFormat.format("Test", (Locale)null);
-		assertEquals("Test", result5);
+	//====================================================================================================
+	// Missing-argument behavior in StringFormatToken.append()
+	//====================================================================================================
+	@Test void a15_stringFormatTokenBranches() {
+		// Missing args -> MissingFormatArgumentException (matches String.format)
+		var fmt1 = StringFormat.ofPrintf("Hello %s");
+		assertThrows(MissingFormatArgumentException.class, () -> fmt1.format((Object[])null));
+
+		var fmt2 = StringFormat.ofPrintf("Price: %.2f");
+		assertThrows(MissingFormatArgumentException.class, () -> fmt2.format((Object[])null));
+
+		var fmt3 = StringFormat.ofPrintf("First: %1$s, Second: %2$s");
+		assertThrows(MissingFormatArgumentException.class, () -> fmt3.format((Object[])null));
 	}
 }
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecordCapture_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecordCapture_Test.java
index 57f9a77399..8666cff19a 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecordCapture_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecordCapture_Test.java
@@ -302,7 +302,7 @@ class LogRecordCapture_Test extends TestBase {
 	@Test void h02_capturesFormattedMessages() {
 		var logger = getLogger("h02");
 		try (var capture = logger.captureEvents()) {
-			logger.info("User {0} logged in", "John");
+			logger.info("User %s logged in", "John");
 			logger.warning("Failed after %d attempts", 3);
 
 			var records = capture.getRecords();
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecord_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecord_Test.java
index 23cceedb2d..abe71117e9 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecord_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/LogRecord_Test.java
@@ -52,7 +52,7 @@ class LogRecord_Test extends TestBase {
 	}
 
 	@Test void a02_constructor_withParameters() {
-		var rec = new LogRecord("test.logger", Level.INFO, "User {0}", new Object[]{"John"}, null);
+		var rec = new LogRecord("test.logger", Level.INFO, "User %s", new Object[]{"John"}, null);
 
 		assertEquals("test.logger", rec.getLoggerName());
 		assertEquals(Level.INFO, rec.getLevel());
@@ -84,7 +84,7 @@ class LogRecord_Test extends TestBase {
 	//====================================================================================================
 
 	@Test void b01_getMessage_formatsLazily() {
-		var rec = new LogRecord("test.logger", Level.INFO, "Value: {0}", new Object[]{42}, null);
+		var rec = new LogRecord("test.logger", Level.INFO, "Value: %s", new Object[]{42}, null);
 
 		// Message should be formatted when accessed
 		var message = rec.getMessage();
@@ -95,7 +95,7 @@ class LogRecord_Test extends TestBase {
 	}
 
 	@Test void b02_getMessage_withMultipleArgs() {
-		var rec = new LogRecord("test.logger", Level.INFO, "{0} + {1} = {2}",
+		var rec = new LogRecord("test.logger", Level.INFO, "%s + %s = %s",
 			new Object[]{1, 2, 3}, null);
 
 		assertEquals("1 + 2 = 3", rec.getMessage());
@@ -226,7 +226,7 @@ class LogRecord_Test extends TestBase {
 	}
 
 	@Test void d07_formatted_msg() {
-		var rec = new LogRecord("test.logger", Level.INFO, "Test {0}", new Object[]{"value"}, null);
+		var rec = new LogRecord("test.logger", Level.INFO, "Test %s", new Object[]{"value"}, null);
 
 		var formatted = rec.formatted("{msg}");
 		assertEquals("Test value", formatted);
@@ -318,7 +318,7 @@ class LogRecord_Test extends TestBase {
 	}
 
 	@Test void e03_formatted_mixedPlaceholders() {
-		var rec = new LogRecord("test.logger", Level.INFO, "Test {0}", new Object[]{"value"}, null);
+		var rec = new LogRecord("test.logger", Level.INFO, "Test %s", new Object[]{"value"}, null);
 
 		var formatted = rec.formatted("%1$tb %1$td, %1$tY {level}: {msg}");
 		assertTrue(formatted.contains("INFO"));
@@ -340,7 +340,7 @@ class LogRecord_Test extends TestBase {
 
 	@Test void f02_formatted_complexFormat() {
 		var exception = new RuntimeException("Error");
-		var rec = new LogRecord("test.logger", Level.SEVERE, "Failed: {0}",
+		var rec = new LogRecord("test.logger", Level.SEVERE, "Failed: %s",
 			new Object[]{"operation"}, exception);
 
 		var formatted = rec.formatted("[{timestamp}] {level}: {msg}%n{exception}");
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/Logger_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/Logger_Test.java
index ae1897b21a..633fca2e37 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/Logger_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/logging/Logger_Test.java
@@ -198,7 +198,7 @@ class Logger_Test extends TestBase {
 	@Test void c01_severe_formatted() {
 		try (var capture = getLogger("c01").captureEvents()) {
 			var logger = getLogger("c01");
-			logger.severe("User {0} logged in", "John");
+			logger.severe("User %s logged in", "John");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -211,7 +211,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c02").captureEvents()) {
 			var logger = getLogger("c02");
 			var exception = new RuntimeException("Error");
-			logger.severe(exception, "Failed to process {0}", "request");
+			logger.severe(exception, "Failed to process %s", "request");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -237,7 +237,7 @@ class Logger_Test extends TestBase {
 	@Test void c04_info_formatted() {
 		try (var capture = getLogger("c04").captureEvents()) {
 			var logger = getLogger("c04");
-			logger.info("Processing {} items", 42);
+			logger.info("Processing %s items", 42);
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -275,7 +275,7 @@ class Logger_Test extends TestBase {
 		// Test line 241: log(Level level, String msg, Object param1)
 		try (var capture = getLogger("c07").captureEvents()) {
 			var logger = getLogger("c07");
-			logger.log(Level.INFO, "User {0} logged in", "john");
+			logger.log(Level.INFO, "User %s logged in", "john");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -289,7 +289,7 @@ class Logger_Test extends TestBase {
 		// Test line 246: log(Level level, String msg, Object[] params)
 		try (var capture = getLogger("c08").captureEvents()) {
 			var logger = getLogger("c08");
-			logger.log(Level.INFO, "User {0} logged in from {1}", new Object[]{"john", "NYC"});
+			logger.log(Level.INFO, "User %s logged in from %s", new Object[]{"john", "NYC"});
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -358,7 +358,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c12").captureEvents()) {
 			var logger = getLogger("c12");
 			var exception = new RuntimeException("Test error");
-			logger.warning(exception, "Warning: {0} occurred", "error");
+			logger.warning(exception, "Warning: %s occurred", "error");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -373,7 +373,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c13").captureEvents()) {
 			var logger = getLogger("c13");
 			var exception = new IllegalStateException("State error");
-			logger.info(exception, "Info: {0} occurred", "issue");
+			logger.info(exception, "Info: %s occurred", "issue");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -387,7 +387,7 @@ class Logger_Test extends TestBase {
 		// Test line 361: config(String pattern, Object...args)
 		try (var capture = getLogger("c14").captureEvents()) {
 			var logger = getLogger("c14");
-			logger.config("Configuration: {0} = {1}", "timeout", 30);
+			logger.config("Configuration: %s = %s", "timeout", 30);
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -402,7 +402,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c15").captureEvents()) {
 			var logger = getLogger("c15");
 			var exception = new IllegalArgumentException("Config error");
-			logger.config(exception, "Configuration: {0} failed", "setup");
+			logger.config(exception, "Configuration: %s failed", "setup");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -416,7 +416,7 @@ class Logger_Test extends TestBase {
 		// Test line 382: fine(String pattern, Object...args)
 		try (var capture = getLogger("c16").captureEvents()) {
 			var logger = getLogger("c16");
-			logger.fine("Fine detail: {0} = {1}", "key", "value");
+			logger.fine("Fine detail: %s = %s", "key", "value");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -431,7 +431,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c17").captureEvents()) {
 			var logger = getLogger("c17");
 			var exception = new RuntimeException("Fine error");
-			logger.fine(exception, "Fine detail: {0} occurred", "event");
+			logger.fine(exception, "Fine detail: %s occurred", "event");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -445,7 +445,7 @@ class Logger_Test extends TestBase {
 		// Test line 403: finer(String pattern, Object...args)
 		try (var capture = getLogger("c18").captureEvents()) {
 			var logger = getLogger("c18");
-			logger.finer("Finer detail: {0} = {1}", "param", 42);
+			logger.finer("Finer detail: %s = %s", "param", 42);
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -460,7 +460,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c19").captureEvents()) {
 			var logger = getLogger("c19");
 			var exception = new RuntimeException("Finer error");
-			logger.finer(exception, "Finer detail: {0} occurred", "trace");
+			logger.finer(exception, "Finer detail: %s occurred", "trace");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -474,7 +474,7 @@ class Logger_Test extends TestBase {
 		// Test line 424: finest(String pattern, Object...args)
 		try (var capture = getLogger("c20").captureEvents()) {
 			var logger = getLogger("c20");
-			logger.finest("Finest detail: {0} = {1}", "debug", "value");
+			logger.finest("Finest detail: %s = %s", "debug", "value");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
@@ -489,7 +489,7 @@ class Logger_Test extends TestBase {
 		try (var capture = getLogger("c21").captureEvents()) {
 			var logger = getLogger("c21");
 			var exception = new RuntimeException("Finest error");
-			logger.finest(exception, "Finest detail: {0} occurred", "debug");
+			logger.finest(exception, "Finest detail: %s occurred", "debug");
 
 			var records = capture.getRecords();
 			assertSize(1, records);
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/BeanRuntimeException_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/BeanRuntimeException_Test.java
index adda441567..e00c3d9c30 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/BeanRuntimeException_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/BeanRuntimeException_Test.java
@@ -41,7 +41,7 @@ class BeanRuntimeException_Test extends TestBase {
 
 	@Test
 	void a02_constructor_withClassAndMessageWithArgs_formatsMessage() {
-		var ex = new BeanRuntimeException(Integer.class, "Value is {0}", 42);
+		var ex = new BeanRuntimeException(Integer.class, "Value is %s", 42);
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Integer"));
 		assertTrue(ex.getMessage().contains("42"));
@@ -71,7 +71,7 @@ class BeanRuntimeException_Test extends TestBase {
 
 	@Test
 	void b02_constructor_withMessageAndArgs_formatsMessage() {
-		var ex = new BeanRuntimeException("Value is {0}", 123);
+		var ex = new BeanRuntimeException("Value is %s", 123);
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("123"));
 		assertNull(ex.getCause());
@@ -125,7 +125,7 @@ class BeanRuntimeException_Test extends TestBase {
 	@Test
 	void d02_constructor_withCauseClassAndMessageWithArgs_formatsMessage() {
 		var cause = new RuntimeException("Underlying error");
-		var ex = new BeanRuntimeException(cause, Integer.class, "Value {0} failed", 99);
+		var ex = new BeanRuntimeException(cause, Integer.class, "Value %s failed", 99);
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Integer"));
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/ExecutableException_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/ExecutableException_Test.java
index 61303bc638..70ccd91b79 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/ExecutableException_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/reflect/ExecutableException_Test.java
@@ -46,7 +46,7 @@ class ExecutableException_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a002_constructor_messageWithArgs() {
-		ExecutableException e = new ExecutableException("Test {0} message {1}", "arg1", "arg2");
+		ExecutableException e = new ExecutableException("Test %s message %s", "arg1", "arg2");
 		assertTrue(e.getMessage().contains("arg1"));
 		assertTrue(e.getMessage().contains("arg2"));
 		assertNull(e.getCause());
@@ -68,7 +68,7 @@ class ExecutableException_Test extends TestBase {
 	@Test
 	void a004_constructor_causeAndMessage() {
 		Throwable cause = new RuntimeException("cause");
-		ExecutableException e = new ExecutableException(cause, "Test {0}", "arg");
+		ExecutableException e = new ExecutableException(cause, "Test %s", "arg");
 		assertSame(cause, e.getCause());
 		assertTrue(e.getMessage().contains("arg"));
 	}
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
index 19f6f12852..36c5ddab9a 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
@@ -35,8 +35,8 @@ class AssertionUtils_Test extends TestBase {
 	void a001_assertArg() {
 		// Should not throw when expression is true
 		assertArg(true, "Should not throw");
-		assertArg(true, "Message with {0}", "arg");
-		assertArg(true, "Test {0} {1} {2}", "a", "b", "c");
+		assertArg(true, "Message with %s", "arg");
+		assertArg(true, "Test %s %s %s", "a", "b", "c");
 
 		// Should throw when expression is false
 		assertThrowsWithMessage(IllegalArgumentException.class, "Test message", () -> {
@@ -44,11 +44,11 @@ class AssertionUtils_Test extends TestBase {
 		});
 
 		assertThrowsWithMessage(IllegalArgumentException.class, fixedSizeList("Test message", "arg1"), () -> {
-			assertArg(false, "Test message {0}", "arg1");
+			assertArg(false, "Test message %s", "arg1");
 		});
 
 		assertThrowsWithMessage(IllegalArgumentException.class, "Test", () -> {
-			assertArg(false, "Test {0} {1} {2}", "a", "b", "c");
+			assertArg(false, "Test %s %s %s", "a", "b", "c");
 		});
 	}
 
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/Shorts_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/Shorts_Test.java
index ab818f419f..a27fb69eae 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/Shorts_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/Shorts_Test.java
@@ -96,7 +96,48 @@ class Shorts_Test extends TestBase {
 	void b002_ne_isNotEmpty_charSeq() { assertTrue(ine("x")); }
 
 	@Test
-	void b003_f_format() { assertEquals("hello world", f("{0} {1}", "hello", "world")); }
+	void b003_f_format() { assertEquals("hello world", f("%s %s", "hello", "world")); }
+
+	@Test
+	void b003a_mf_messageFormat() { assertEquals("hello world", mf("{0} {1}", "hello", "world")); }
+
+	@Test
+	void b003b_mf_typedNumber() {
+		// Typed MessageFormat conversion (locale-aware grouping) must render identically to java.text.MessageFormat.
+		var expected = new java.text.MessageFormat("{0,number}").format(new Object[]{1234567});
+		assertEquals(expected, mf("{0,number}", 1234567));
+	}
+
+	@Test
+	void b003c_mf_singleQuoteEscaping() { assertEquals("'x'", mf("''{0}''", "x")); }
+
+	@Test
+	void b003d_mfs_supplier() { assertEquals("hello world", mfs("{0} {1}", "hello", "world").get()); }
+
+	@Test
+	void b003e_mf_nullArg() { assertEquals("Value: null", mf("Value: {0}", (Object)null)); }
+
+	@Test
+	void b003f_mf_missingArgKeepsPlaceholder() {
+		// java.text.MessageFormat inserts the placeholder text when an argument is missing.
+		assertEquals("a {1}", mf("{0} {1}", "a"));
+	}
+
+	@Test
+	void b003g_mf_noArgsReturnsPatternVerbatim() {
+		// With no args the pattern is returned as-is (single quotes left untouched).
+		assertEquals("It''s a test", mf("It''s a test"));
+	}
+
+	@Test
+	void b003h_mf_typedDate() {
+		var d = new java.util.Date(0L);
+		var expected = new java.text.MessageFormat("{0,date,short}").format(new Object[]{d});
+		assertEquals(expected, mf("{0,date,short}", d));
+	}
+
+	@Test
+	void b003i_mf_multiArgWithReuse() { assertEquals("Hello and Hello", mf("{0} and {0}", "Hello")); }
 
 	@Test
 	void b004_b_isBlank() { assertTrue(ib("   ")); }
@@ -190,7 +231,7 @@ class Shorts_Test extends TestBase {
 
 	@Test
 	void e001_rex_runtimeException() {
-		RuntimeException e = rex("test {0}", "msg");
+		RuntimeException e = rex("test %s", "msg");
 		assertEquals("test msg", e.getMessage());
 	}
 
@@ -202,7 +243,7 @@ class Shorts_Test extends TestBase {
 
 	@Test
 	void e003_ise_illegalState() {
-		IllegalStateException e = isex("bad state {0}", 1);
+		IllegalStateException e = isex("bad state %s", 1);
 		assertEquals("bad state 1", e.getMessage());
 	}
 
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
index ae827ecc9e..9db2f669f2 100755
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/StringUtils_Test.java
@@ -1488,10 +1488,10 @@ class StringUtils_Test extends TestBase {
 		var lineSep = System.lineSeparator();
 		assertEquals("Line 1" + lineSep + "Line 2", format("Line 1%nLine 2", "dummy"));
 
-		// MessageFormat style
-		assertEquals("Hello John, you are 30 years old", format("Hello {0}, you are {1} years old", "John", 30));
-		assertEquals("Hello {0}", format("Hello {0}")); // No args
-		assertEquals("Hello {}", format("Hello {}")); // Unnumbered placeholder
+		// MessageFormat style is handled by mformat(), not format() (which is printf-only as of 10.0.0)
+		assertEquals("Hello John, you are 30 years old", mformat("Hello {0}, you are {1} years old", "John", 30));
+		assertEquals("Hello {0}", mformat("Hello {0}")); // No args
+		assertEquals("Hello {}", format("Hello {}")); // Printf-only: { is literal
 	}
 
 	//====================================================================================================
@@ -4403,7 +4403,7 @@ class StringUtils_Test extends TestBase {
 
 		// Invalid input invokes the supplier and the supplier's exception is thrown.
 		var ex = assertThrows(IllegalArgumentException.class,
-			() -> parseInt("invalid", () -> Shorts.iaex("Bad int: {0}", "invalid")));
+			() -> parseInt("invalid", () -> Shorts.iaex("Bad int: %s", "invalid")));
 		assertEquals("Bad int: invalid", ex.getMessage());
 
 		// Custom RuntimeException subtype is preserved by the generic signature.
@@ -4449,7 +4449,7 @@ class StringUtils_Test extends TestBase {
 
 		// Invalid input invokes the supplier and the supplier's exception is thrown.
 		var ex = assertThrows(IllegalArgumentException.class,
-			() -> parseIntWithSuffix("1X", () -> Shorts.iaex("Bad size: {0}", "1X")));
+			() -> parseIntWithSuffix("1X", () -> Shorts.iaex("Bad size: %s", "1X")));
 		assertEquals("Bad size: 1X", ex.getMessage());
 	}
 
@@ -4479,7 +4479,7 @@ class StringUtils_Test extends TestBase {
 
 		// Invalid input invokes the supplier and the supplier's exception is thrown.
 		var ex = assertThrows(IllegalArgumentException.class,
-			() -> parseLong("invalid", () -> Shorts.iaex("Bad long: {0}", "invalid")));
+			() -> parseLong("invalid", () -> Shorts.iaex("Bad long: %s", "invalid")));
 		assertEquals("Bad long: invalid", ex.getMessage());
 	}
 
diff --git a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ThrowableUtils_Test.java b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ThrowableUtils_Test.java
index 638b588bb4..b2de0bb1f4 100644
--- a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ThrowableUtils_Test.java
+++ b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/utils/ThrowableUtils_Test.java
@@ -48,7 +48,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a001_bex_withClass() {
-		BeanRuntimeException ex = brex(String.class, "Error in class {0}", "TestClass");
+		BeanRuntimeException ex = brex(String.class, "Error in class %s", "TestClass");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Error in class TestClass"));
 		assertTrue(ex.getMessage().contains("java.lang.String")); // Class name is in message
@@ -59,7 +59,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a002_bex_withMessage() {
-		BeanRuntimeException ex = brex("Error message {0}", "test");
+		BeanRuntimeException ex = brex("Error message %s", "test");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Error message test"));
 	}
@@ -81,7 +81,7 @@ class ThrowableUtils_Test extends TestBase {
 	@Test
 	void a004_bex_withCauseAndClass() {
 		var cause = new IOException("root cause");
-		BeanRuntimeException ex = brex(cause, String.class, "Error in {0}", "TestClass");
+		BeanRuntimeException ex = brex(cause, String.class, "Error in %s", "TestClass");
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Error in TestClass"));
@@ -97,7 +97,7 @@ class ThrowableUtils_Test extends TestBase {
 		// Note: bex(Throwable, String, ...) calls new BeanRuntimeException(f(msg, args), cause)
 		// but BeanRuntimeException doesn't have a (String, Throwable) constructor,
 		// so it matches BeanRuntimeException(String) and the cause is lost
-		BeanRuntimeException ex = brex(cause, "Error message {0}", "test");
+		BeanRuntimeException ex = brex(cause, "Error message %s", "test");
 		assertNotNull(ex);
 		// The cause is not preserved because BeanRuntimeException(String) constructor is used
 		assertTrue(ex.getMessage().contains("Error message test"));
@@ -263,7 +263,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a011_illegalArg_withMessage() {
-		IllegalArgumentException ex = iaex("Invalid parameter {0}", "userId");
+		IllegalArgumentException ex = iaex("Invalid parameter %s", "userId");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Invalid parameter userId"));
 		assertNull(ex.getCause());
@@ -286,7 +286,7 @@ class ThrowableUtils_Test extends TestBase {
 	@Test
 	void a013_illegalArg_withCauseAndMessage() {
 		var cause = new IOException("root cause");
-		IllegalArgumentException ex = iaex(cause, "Invalid parameter {0}", "userId");
+		IllegalArgumentException ex = iaex(cause, "Invalid parameter %s", "userId");
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Invalid parameter userId"));
@@ -297,7 +297,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a014_ioex_withMessage() {
-		IOException ex = ioex("File not found: {0}", "/tmp/test.txt");
+		IOException ex = ioex("File not found: %s", "/tmp/test.txt");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("File not found: /tmp/test.txt"));
 		assertNull(ex.getCause());
@@ -320,7 +320,7 @@ class ThrowableUtils_Test extends TestBase {
 	@Test
 	void a016_ioex_withCauseAndMessage() {
 		var cause = new FileNotFoundException("config.xml");
-		IOException ex = ioex(cause, "Failed to load {0}", "configuration");
+		IOException ex = ioex(cause, "Failed to load %s", "configuration");
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Failed to load configuration"));
@@ -342,7 +342,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a018_rex_withMessage() {
-		RuntimeException ex = rex("Error message {0}", "test");
+		RuntimeException ex = rex("Error message %s", "test");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Error message test"));
 		assertNull(ex.getCause());
@@ -365,7 +365,7 @@ class ThrowableUtils_Test extends TestBase {
 	@Test
 	void a020_rex_withCauseAndMessage() {
 		var cause = new SQLException("Database error");
-		RuntimeException ex = rex(cause, "Failed to process {0} at {1}", "user", "login");
+		RuntimeException ex = rex(cause, "Failed to process %s at %s", "user", "login");
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Failed to process user at login"));
@@ -412,7 +412,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a023_unsupportedOp_withMessage() {
-		UnsupportedOperationException ex = uoex("Operation {0} is not supported for type {1}", "delete", "User");
+		UnsupportedOperationException ex = uoex("Operation %s is not supported for type %s", "delete", "User");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Operation delete is not supported for type User"));
 		assertNull(ex.getCause());
@@ -435,7 +435,7 @@ class ThrowableUtils_Test extends TestBase {
 	@Test
 	void a025_unsupportedOp_withCauseAndMessage() {
 		var cause = new IllegalStateException("Locked");
-		UnsupportedOperationException ex = uoex(cause, "Cannot {0} on {1}", "delete", "immutable collection");
+		UnsupportedOperationException ex = uoex(cause, "Cannot %s on %s", "delete", "immutable collection");
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Cannot delete on immutable collection"));
@@ -457,7 +457,7 @@ class ThrowableUtils_Test extends TestBase {
 	//====================================================================================================
 	@Test
 	void a027_exex_withMessage() {
-		ExecutableException ex = exex("Error message {0}", "test");
+		ExecutableException ex = exex("Error message %s", "test");
 		assertNotNull(ex);
 		assertTrue(ex.getMessage().contains("Error message test"));
 		assertNull(ex.getCause());
@@ -480,7 +480,7 @@ class ThrowableUtils_Test extends TestBase {
 	@Test
 	void a029_exex_withCauseAndMessage() {
 		var cause = new IOException("root cause");
-		ExecutableException ex = exex(cause, "Error message {0}", "test");
+		ExecutableException ex = exex(cause, "Error message %s", "test");
 		assertNotNull(ex);
 		assertSame(cause, ex.getCause());
 		assertTrue(ex.getMessage().contains("Error message test"));
@@ -574,7 +574,7 @@ class ThrowableUtils_Test extends TestBase {
 		System.setProperty("juneau.enableVerboseExceptions", "true");
 		try {
 			// Any method that calls log() will trigger the verbose branch if it re-reads the setting
-			var ex = iaex("test {0}", "verbose");
+			var ex = iaex("test %s", "verbose");
 			assertNotNull(ex);
 		} finally {
 			System.clearProperty("juneau.enableVerboseExceptions");
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java
index 3b79de0227..4cb169e55f 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Section.java
@@ -120,7 +120,7 @@ public class Section {
 			var bpm = bm.getPropertyMeta(k);
 			if (bpm == null) {
 				if (! ignoreUnknownProperties)
-					throw new ParseException("Unknown property ''{0}'' encountered in configuration section ''{1}''.", k, name);
+					throw new ParseException("Unknown property '%s' encountered in configuration section '%s'.", k, name);
 			} else {
 				bm.put(k, config.get(name + '/' + k).as(bpm.getBeanInfo().inner()).orElse(null));
 			}
@@ -196,7 +196,7 @@ public class Section {
 		assertArgNotNull(ARG_c, c);
 
 		if (! c.isInterface())
-			throw iaex("Class ''{0}'' passed to toInterface() is not an interface.", cn(c));
+			throw iaex("Class '%s' passed to toInterface() is not an interface.", cn(c));
 
 		return o((T)Proxy.newProxyInstance(c.getClassLoader(), a(c), (InvocationHandler)(proxy, method, args) -> {
 			var bi = Introspector.getBeanInfo(c, null);
@@ -208,7 +208,7 @@ public class Section {
 				if (method.equals(wm))
 					return config.set(name + '/' + pd.getName(), args[0]);
 			}
-			throw uoex("Unsupported interface method.  method=''{0}''", method);
+			throw uoex("Unsupported interface method.  method='%s'", method);
 		}));
 	}
 
@@ -250,7 +250,7 @@ public class Section {
 	public Section writeToBean(Object bean, boolean ignoreUnknownProperties) throws ParseException {
 		assertArgNotNull(ARG_bean, bean);
 		if (! isPresent())
-			throw iaex("Section ''{0}'' not found in configuration.", name);
+			throw iaex("Section '%s' not found in configuration.", name);
 
 		var keys = configMap.getKeys(name);
 
@@ -259,7 +259,7 @@ public class Section {
 			var bpm = bm.getPropertyMeta(k);
 			if (bpm == null) {
 				if (! ignoreUnknownProperties)
-					throw new ParseException("Unknown property ''{0}'' encountered in configuration section ''{1}''.", k, name);
+					throw new ParseException("Unknown property '%s' encountered in configuration section '%s'.", k, name);
 			} else {
 				bm.put(k, config.get(name + '/' + k).as(bpm.getBeanInfo().inner()).orElse(null));
 			}
@@ -267,4 +267,4 @@ public class Section {
 
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigMap.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigMap.java
index 8d702d2e8c..014d4b4234 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigMap.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/internal/ConfigMap.java
@@ -94,7 +94,7 @@ public class ConfigMap implements ConfigStoreListener {
 					if (c != '#' && l.indexOf('=') != -1) {
 						var e = new ConfigMapEntry(l, lines.subList(start, i));
 						if (entries.containsKey(e.key))
-							throw new ConfigException("Duplicate entry found in section [{0}] of configuration:  {1}", name2, e.key);
+							throw new ConfigException("Duplicate entry found in section [%s] of configuration:  %s", name2, e.key);
 						entries.put(e.key, e);
 						start = i + 1;
 					}
@@ -198,12 +198,12 @@ public class ConfigMap implements ConfigStoreListener {
 
 	private static void checkKeyName(String s) {
 		if (! isValidKeyName(s))
-			throw iaex("Invalid key name: ''{0}''", s);
+			throw iaex("Invalid key name: '%s'", s);
 	}
 
 	private static void checkSectionName(String s) {
 		if (! ("".equals(s) || isValidNewSectionName(s)))
-			throw iaex("Invalid section name: ''{0}''", s);
+			throw iaex("Invalid section name: '%s'", s);
 	}
 
 	private static boolean isValidConfigName(String s) {
@@ -853,17 +853,17 @@ public class ConfigMap implements ConfigStoreListener {
 				if (c == '[') {
 					var l = line.trim();
 					if (c2 != ']' || ! isValidNewSectionName(l.substring(1, l.length() - 1)))
-						throw new ConfigException("Invalid section name found in configuration:  {0}", line);
+						throw new ConfigException("Invalid section name found in configuration:  %s", line);
 				} else if (c == '<') {
 					var l = line.trim();
 					var i = l.indexOf('>');
 					if (i != -1) {
 						var l2 = l.substring(1, i);
 						if (! isValidConfigName(l2))
-							throw new ConfigException("Invalid import config name found in configuration:  {0}", line);
+							throw new ConfigException("Invalid import config name found in configuration:  %s", line);
 						var l3 = l.substring(i + 1);
 						if (! (isEmpty(l3) || firstChar(l3) == '#'))
-							throw new ConfigException("Invalid import config name found in configuration:  {0}", line);
+							throw new ConfigException("Invalid import config name found in configuration:  %s", line);
 						var importName = l2.trim();
 						// Circular imports are detected in ConfigStore.getMap() which throws a clean ConfigException.
 						if (! imports2.containsKey(importName))
@@ -949,7 +949,7 @@ public class ConfigMap implements ConfigStoreListener {
 		for (var i = sections.size() - 1; i >= 0; i--) {
 			var cs = sections.get(i);
 			if (entries.containsKey(cs.name))
-				throw new ConfigException("Duplicate section found in configuration:  [{0}]", cs.name);
+				throw new ConfigException("Duplicate section found in configuration:  [%s]", cs.name);
 			entries.put(cs.name, cs);
 		}
 
@@ -966,4 +966,4 @@ public class ConfigMap implements ConfigStoreListener {
 		var ce = cs == null ? null : cs.entries.get(key);
 		return nn(ce);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
index de7ef0ba3f..8911f0a166 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ConfigStore.java
@@ -138,7 +138,7 @@ public abstract class ConfigStore extends Context implements Closeable {
 		// Detect circular imports before recursing into ConfigMap construction.
 		var loading = LOADING.get();
 		if (! loading.add(key))
-			throw new ConfigException("Import loop detected in configuration:  {0}", importChain(loading, name));
+			throw new ConfigException("Import loop detected in configuration:  %s", importChain(loading, name));
 		try {
 			cm = new ConfigMap(this, name, format2);
 		} finally {
@@ -263,4 +263,4 @@ public abstract class ConfigStore extends Context implements Closeable {
 	protected String resolveName(String name) {
 		return name;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
index 1c77b7a3c9..d56fef313d 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
@@ -530,7 +530,7 @@ public class FileStore extends ConfigStore {
 			if (! Files.exists(p)) {
 				Files.createDirectories(p.getParent());
 				if (! Files.exists(p) && ! p.toFile().createNewFile()) { // HTT - createNewFile() failure requires OS-level file system restrictions
-					throw ioex("Could not create file: {0}", p);
+					throw ioex("Could not create file: %s", p);
 				}
 			}
 		} catch (@SuppressWarnings("unused") IOException e) {
@@ -609,4 +609,4 @@ public class FileStore extends ConfigStore {
 		}
 		return nameCache.get(name);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ProfileConfigStore.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ProfileConfigStore.java
index 86200772b3..cbac1f7b02 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ProfileConfigStore.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/ProfileConfigStore.java
@@ -168,7 +168,7 @@ public class ProfileConfigStore extends ConfigStore {
 			try {
 				update(baseName, mergedContents());
 			} catch (IOException e) {  // HTT: re-merge IO failure only on a real FileStore IO error mid-reload; not reproducible with in-memory stores.
-				throw new ConfigException(e, "Failed to re-merge profile overlays for ''{0}''", baseName);
+				throw new ConfigException(e, "Failed to re-merge profile overlays for '%s'", baseName);
 			}
 		};
 		delegate.register(baseName, reloadListener);
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfParserSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfParserSession.java
index 116e65b9bc..40060f74da 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfParserSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfParserSession.java
@@ -201,7 +201,7 @@ public class RdfParserSession extends ReaderParserSession {
 				return parseAnything(object(), st.getObject(), outer, null);
 			}
 		}
-		throw new ParseException(this, "Unknown value type for node ''{0}''", n);
+		throw new ParseException(this, "Unknown value type for node '%s'", n);
 	}
 
 	private boolean isBag(RDFNode n) {
@@ -297,7 +297,7 @@ public class RdfParserSession extends ReaderParserSession {
 					}
 				}
 			} else {
-				throw new ParseException(this, "Unrecognized node type ''{0}'' for object", n);
+				throw new ParseException(this, "Unrecognized node type '%s' for object", n);
 			}
 		} else if (nn(builder)) {
 			var r = n.asResource();
@@ -332,7 +332,7 @@ public class RdfParserSession extends ReaderParserSession {
 			} else if (r.canAs(RDFList.class)) {
 				parseIntoCollection(r.as(RDFList.class), (Collection)o, sType, pMeta);
 			} else {
-				throw new ParseException(this, "Unrecognized node type ''{0}'' for collection", n);
+				throw new ParseException(this, "Unrecognized node type '%s' for collection", n);
 			}
 			if (sType.isArray() || sType.isArgs())
 				o = toArray(sType, (Collection)o);
@@ -369,9 +369,9 @@ public class RdfParserSession extends ReaderParserSession {
 			else if (nn(sType.getProxyInvocationHandler()))
 				o = newBeanMap(outer, sType.inner()).load(m).getBean();
 			else
-				throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+				throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		} else {
-			throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+			throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		}
 
 		if (nn(swap) && nn(o))
@@ -506,7 +506,7 @@ public class RdfParserSession extends ReaderParserSession {
 			return type.isOptional() ? (T)oe() : null;
 
 		if (roots.size() > 1)
-			throw new ParseException(this, "Too many root nodes found in model:  {0}", roots.size());
+			throw new ParseException(this, "Too many root nodes found in model:  %s", roots.size());
 		var resource = roots.get(0);
 
 		return parseAnything(type, resource, getOuter(), null);
@@ -614,4 +614,4 @@ public class RdfParserSession extends ReaderParserSession {
 	 * 	<jk>true</jk> if whitespace in text elements will be automatically trimmed.
 	 */
 	protected final boolean isTrimWhitespace() { return ctx.isTrimWhitespace(); }
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfSerializerSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfSerializerSession.java
index 464f5dd072..61963f8eff 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfSerializerSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfSerializerSession.java
@@ -148,7 +148,7 @@ public class RdfSerializerSession extends WriterSerializerSession {
 		var langName = ctx.getLanguage();
 		lang = toLang(langName);
 		if (lang == null)
-			throw rex("Unknown RDF language encountered: ''{0}''", langName);
+			throw rex("Unknown RDF language encountered: '%s'", langName);
 	}
 
 	private static Lang toLang(String langName) {
@@ -608,4 +608,4 @@ public class RdfSerializerSession extends WriterSerializerSession {
 	 * 	<br>Otherwise, namespaces will be defined using {@link RdfNs @RdfNs} and {@link Rdf @Rdf}.
 	 */
 	protected final boolean isUseXmlNamespaces() { return ctx.isUseXmlNamespaces(); }
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamParserSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamParserSession.java
index 7cadf5df74..0f4d7a2c9d 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamParserSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/marshall/jena/RdfStreamParserSession.java
@@ -215,7 +215,7 @@ public class RdfStreamParserSession extends InputStreamParserSession {
 				return parseAnything(object(), st.getObject(), outer, null);
 			}
 		}
-		throw new ParseException(this, "Unknown value type for node ''{0}''", n);
+		throw new ParseException(this, "Unknown value type for node '%s'", n);
 	}
 
 	private boolean isBag(RDFNode n) {
@@ -311,7 +311,7 @@ public class RdfStreamParserSession extends InputStreamParserSession {
 					}
 				}
 			} else {
-				throw new ParseException(this, "Unrecognized node type ''{0}'' for object", n);
+				throw new ParseException(this, "Unrecognized node type '%s' for object", n);
 			}
 		} else if (nn(builder)) {
 			var r = n.asResource();
@@ -356,7 +356,7 @@ public class RdfStreamParserSession extends InputStreamParserSession {
 			} else if (r.canAs(RDFList.class)) {
 				parseIntoCollection(r.as(RDFList.class), (Collection)o, sType, pMeta);
 			} else {
-				throw new ParseException(this, "Unrecognized node type ''{0}'' for collection", n);
+				throw new ParseException(this, "Unrecognized node type '%s' for collection", n);
 			}
 			if (sType.isArray() || sType.isArgs())
 				o = toArray(sType, (Collection)o);
@@ -393,9 +393,9 @@ public class RdfStreamParserSession extends InputStreamParserSession {
 			else if (nn(sType.getProxyInvocationHandler()))
 				o = newBeanMap(outer, sType.inner()).load(m).getBean();
 			else
-				throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+				throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		} else {
-			throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+			throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		}
 
 		if (nn(swap) && nn(o))
@@ -530,7 +530,7 @@ public class RdfStreamParserSession extends InputStreamParserSession {
 			return type.isOptional() ? (T)oe() : null;
 
 		if (roots.size() > 1)
-			throw new ParseException(this, "Too many root nodes found in model:  {0}", roots.size());
+			throw new ParseException(this, "Too many root nodes found in model:  %s", roots.size());
 		var resource = roots.get(0);
 
 		return parseAnything(type, resource, getOuter(), null);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/AnnotationApplier.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/AnnotationApplier.java
index 77386544c7..69e65655cb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/AnnotationApplier.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/AnnotationApplier.java
@@ -141,7 +141,7 @@ public abstract class AnnotationApplier<A extends Annotation,B> {
 
 	private Character toCharacter(String in, String loc) {
 		if (in.length() != 1)
-			throw new ConfigException("Invalid syntax for character on annotation @{0}({1}): {2}", ca.getSimpleName(), loc, in);
+			throw new ConfigException("Invalid syntax for character on annotation @%s(%s): %s", ca.getSimpleName(), loc, in);
 		return in.charAt(0);
 	}
 
@@ -200,7 +200,7 @@ public abstract class AnnotationApplier<A extends Annotation,B> {
 		try {
 			return string(in).map(Integer::parseInt);
 		} catch (NumberFormatException e) {
-			throw new ConfigException(e, "Invalid syntax for integer on annotation @{0}({1}): {2}", ca.getSimpleName(), loc, in);
+			throw new ConfigException(e, "Invalid syntax for integer on annotation @%s(%s): %s", ca.getSimpleName(), loc, in);
 		}
 	}
 
@@ -257,4 +257,4 @@ public abstract class AnnotationApplier<A extends Annotation,B> {
 	protected VarResolverSession vr() {
 		return vr;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanDictionaryMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanDictionaryMap.java
index b499123454..fa3109451b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanDictionaryMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanDictionaryMap.java
@@ -85,7 +85,7 @@ public class BeanDictionaryMap extends LinkedHashMap<String,Object> {
 				return;
 			}
 		}
-		throw brex("Invalid object type passed to BeanDictionaryMap: ''{0}''.  Only objects of type Class or Object[] containing Class or Object[] objects can be used.", cn(o));
+		throw brex("Invalid object type passed to BeanDictionaryMap: '%s'.  Only objects of type Class or Object[] containing Class or Object[] objects can be used.", cn(o));
 	}
 
 	/**
@@ -129,4 +129,4 @@ public class BeanDictionaryMap extends LinkedHashMap<String,Object> {
 		put(typeName, a(mapClass, keyClass, valueClass));
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanRegistry.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanRegistry.java
index 0ddce459f0..e0428e7046 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanRegistry.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BeanRegistry.java
@@ -166,7 +166,7 @@ public class BeanRegistry implements BeanRegistryLookup {
 						if (x instanceof Class<?> x2)
 							addClass(info(x2));
 						else
-							throw brex("Collection class ''{0}'' passed to BeanRegistry does not contain Class objects.", ci.getName());
+							throw brex("Collection class '%s' passed to BeanRegistry does not contain Class objects.", ci.getName());
 					});
 				} else if (ci.isAssignableTo(Map.class)) {
 					Map<?,?> m = BeanInstantiator.of(Map.class).type(ci).preferZeroArgConstructor().run();
@@ -178,7 +178,7 @@ public class BeanRegistry implements BeanRegistryLookup {
 						else if (isArray(v))
 							val = getTypedClassMeta(v);
 						else
-							throw brex("Class ''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is not a Type object.", ci.getName(), cn(v));
+							throw brex("Class '%s' was passed to BeanRegistry but value of type '%s' found in map is not a Type object.", ci.getName(), cn(v));
 						addToMap(typeName, val);
 					});
 				} else {
@@ -188,7 +188,7 @@ public class BeanRegistry implements BeanRegistryLookup {
 						.map(x -> x.inner().typeName())
 						.filter(Shorts::ine)
 						.findFirst()
-						.orElseThrow(() -> brex("Class ''{0}'' was passed to BeanRegistry but it doesn't have a @Marshalled(typeName) annotation defined.", ci.getName()));
+						.orElseThrow(() -> brex("Class '%s' was passed to BeanRegistry but it doesn't have a @Marshalled(typeName) annotation defined.", ci.getName()));
 					// @formatter:on
 					addToMap(typeName, bc.getClassMeta(ci.inner()));
 				}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BigNumberFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BigNumberFormat.java
index b5d748e1bb..365cbde5e0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BigNumberFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BigNumberFormat.java
@@ -208,9 +208,9 @@ public enum BigNumberFormat {
 				return (T) new BigInteger(s);
 			if (BigDecimal.class.equals(targetType))
 				return (T) new BigDecimal(s);
-			throw iaex("Unsupported BigNumberFormat target type: {0}", targetType.getName());
+			throw iaex("Unsupported BigNumberFormat target type: %s", targetType.getName());
 		} catch (NumberFormatException e) {
-			throw iaex("Invalid big-number value ''{0}'' for format {1}: {2}", value, format, e.getMessage());
+			throw iaex("Invalid big-number value '%s' for format %s: %s", value, format, e.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BinaryFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BinaryFormat.java
index e540248b54..0d7f59dfbc 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BinaryFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BinaryFormat.java
@@ -124,7 +124,7 @@ public enum BinaryFormat {
 			try {
 				return Base64.getUrlDecoder().decode(s);
 			} catch (IllegalArgumentException e) {
-				throw iaex("Invalid binary value ''{0}'' for format {1}: {2}", s, this, e.getMessage());
+				throw iaex("Invalid binary value '%s' for format %s: %s", s, this, e.getMessage());
 			}
 		}
 		// Format-agnostic parsing: sniff the wire shape and decode accordingly, regardless of the
@@ -140,7 +140,7 @@ public enum BinaryFormat {
 		try {
 			return base64Decode(s);
 		} catch (IllegalArgumentException e) {
-			throw iaex("Invalid binary value ''{0}'' for format {1}: {2}", s, this, e.getMessage());
+			throw iaex("Invalid binary value '%s' for format %s: %s", s, this, e.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BitSetFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BitSetFormat.java
index d91b0102f1..8f3cab9d4b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BitSetFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BitSetFormat.java
@@ -173,7 +173,7 @@ public enum BitSetFormat {
 				}
 			}
 		} catch (IllegalArgumentException e) {
-			throw iaex("Invalid BitSet value ''{0}'' for format {1}: {2}", value, fmt, e.getMessage());
+			throw iaex("Invalid BitSet value '%s' for format %s: %s", value, fmt, e.getMessage());
 		}
 		return bs;
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BooleanFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BooleanFormat.java
index b3259a943a..3c3a987744 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BooleanFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/BooleanFormat.java
@@ -186,7 +186,7 @@ public enum BooleanFormat {
 		return switch (s.toLowerCase()) {
 			case "true", "1", "yes", "y", "on" -> true;
 			case "false", "0", "no", "n", "off" -> false;
-			default -> throw iaex("Invalid boolean value ''{0}'' for format {1}", value, format);
+			default -> throw iaex("Invalid boolean value '%s' for format %s", value, format);
 		};
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassFormat.java
index 2544166661..7b70e683d6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassFormat.java
@@ -222,7 +222,7 @@ public enum ClassFormat {
 		try {
 			return resolveWithArraySuffix(s, cl);
 		} catch (ClassNotFoundException firstAttempt) {
-			throw iaex("Could not resolve class ''{0}'' for format {1}: {2}", value, format, firstAttempt.getMessage());
+			throw iaex("Could not resolve class '%s' for format %s: %s", value, format, firstAttempt.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java
index f483d42008..832c7095d9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ClassMeta.java
@@ -456,7 +456,7 @@ public final class ClassMeta<T> extends BeanInfo<T> {
 	public ClassMeta<?> getArg(int index) {
 		if (nn(args) && index >= 0 && index < args.size())
 			return args.get(index);
-		throw brex("Invalid argument index specified:  {0}.  Only {1} arguments are defined.", index, args == null ? 0 : args.size());
+		throw brex("Invalid argument index specified:  %s.  Only %s arguments are defined.", index, args == null ? 0 : args.size());
 	}
 
 	/**
@@ -1404,7 +1404,7 @@ public final class ClassMeta<T> extends BeanInfo<T> {
 			} catch (@SuppressWarnings("unused") IllegalArgumentException e) {
 				if (marshallingContext.isIgnoreUnknownEnumValues())
 					return null;
-				throw new ExecutableException("Could not resolve enum value ''{0}'' on class ''{1}''", arg, cn(inner()));
+				throw new ExecutableException("Could not resolve enum value '%s' on class '%s'", arg, cn(inner()));
 			}
 		}
 
@@ -1484,7 +1484,7 @@ public final class ClassMeta<T> extends BeanInfo<T> {
 			return first(l).map(x -> (ObjectSwap<T,?>)x).orElse(null);
 		}
 
-		throw new ClassMetaRuntimeException(c, "Invalid swap class ''{0}'' specified.  Must extend from ObjectSwap or Surrogate.", c);
+		throw new ClassMetaRuntimeException(c, "Invalid swap class '%s' specified.  Must extend from ObjectSwap or Surrogate.", c);
 	}
 
 	private String findBeanDictionaryName() {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Context.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Context.java
index 357480c49c..e44e6d4816 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Context.java
@@ -536,7 +536,7 @@ public abstract class Context {
 				else if (x instanceof MethodInfo x2)
 					work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER));
 				else
-					iaex("Invalid type passed to applyAnnotations:  {0}", cn(x));
+					iaex("Invalid type passed to applyAnnotations:  %s", cn(x));
 			});
 			return work;
 		}
@@ -792,7 +792,7 @@ public abstract class Context {
 
 		private Context innerBuild() {
 			if (type == null)
-				throw rex("Type not specified for context builder {0}", cn(getClass()));
+				throw rex("Type not specified for context builder %s", cn(getClass()));
 			if (nn(impl) && type.isInstance(impl))
 				return type.cast(impl);
 			if (nn(cache))
@@ -832,7 +832,7 @@ public abstract class Context {
 					).orElse(null))
 				.filter(Objects::nonNull)
 				.findFirst()
-				.orElseThrow(() -> rex("Could not find builder create method on class {0}", cn(type)));
+				.orElseThrow(() -> rex("Could not find builder create method on class %s", cn(type)));
 			// @formatter:on
 		})
 		.build();
@@ -863,7 +863,7 @@ public abstract class Context {
 			var bt = info(builderType);
 			return ct
 				.getPublicConstructor(x -> x.hasNumParameters(1) && x.getParameter(0).getParameterType().isAssignableFrom(builderType))
-				.orElseThrow(() -> rex("Public constructor not found: {0}({1})", ct.getName(), bt.getName()));
+				.orElseThrow(() -> rex("Public constructor not found: %s(%s)", ct.getName(), bt.getName()));
 		})
 		.build();
 
@@ -1024,4 +1024,4 @@ public abstract class Context {
 			.a(PROP_annotations, annotations)
 			.a(PROP_debug, debug);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/CurrencyFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/CurrencyFormat.java
index 16e900a98c..8bf494c203 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/CurrencyFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/CurrencyFormat.java
@@ -185,7 +185,7 @@ public enum CurrencyFormat {
 			// Fall through to symbol / display-name scan.
 		}
 		return switch (fmt) {
-			case NOT_SET, ISO_CODE -> throw iaex("Invalid currency code ''{0}''", value);
+			case NOT_SET, ISO_CODE -> throw iaex("Invalid currency code '%s'", value);
 			case SYMBOL -> findBySymbol(s, loc, value);
 			case DISPLAY_NAME -> findByDisplayName(s, loc, value);
 		};
@@ -209,7 +209,7 @@ public enum CurrencyFormat {
 
 	private static Currency resolveAmbiguousMatches(List<Currency> matches, Locale loc, String original, String kind) {
 		if (matches.isEmpty())
-			throw iaex("Could not resolve currency {0} ''{1}'' in locale {2}", kind, original, loc);
+			throw iaex("Could not resolve currency %s '%s' in locale %s", kind, original, loc);
 		if (matches.size() == 1)
 			return matches.get(0);
 		// Prefer the locale's default currency when the locale has one.
@@ -220,7 +220,7 @@ public enum CurrencyFormat {
 		} catch (@SuppressWarnings("unused") IllegalArgumentException ignored) {
 			// Locale has no associated currency (e.g. Locale.ROOT, Locale.ENGLISH, Locale.JAPAN may or may not).
 		}
-		throw iaex("Ambiguous currency {0} ''{1}'' in locale {2}: matches {3}", kind, original, loc, matches);
+		throw iaex("Ambiguous currency %s '%s' in locale %s: matches %s", kind, original, loc, matches);
 	}
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/EnumFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/EnumFormat.java
index 89586806b2..2d20199288 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/EnumFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/EnumFormat.java
@@ -150,7 +150,7 @@ public enum EnumFormat {
 		for (var e : enumClass.getEnumConstants())
 			if (e.name().equalsIgnoreCase(s) || s.equalsIgnoreCase(e.toString()))
 				return e;
-		throw iaex("Could not resolve enum value ''{0}'' on class ''{1}''", value, enumClass.getName());
+		throw iaex("Could not resolve enum value '%s' on class '%s'", value, enumClass.getName());
 	}
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/FloatFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/FloatFormat.java
index a857252454..f6ffc2df82 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/FloatFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/FloatFormat.java
@@ -169,7 +169,7 @@ public enum FloatFormat {
 			case NOT_SET, NaN_AS_NULL -> null;
 			case NaN_AS_STRING -> nonFiniteTokenFloat(value);
 			case NaN_AS_NUMBER -> Float.valueOf(value);
-			case NaN_AS_ERROR -> throw iaex("Non-finite float value {0} rejected by FloatFormat.NaN_AS_ERROR", value);
+			case NaN_AS_ERROR -> throw iaex("Non-finite float value %s rejected by FloatFormat.NaN_AS_ERROR", value);
 		};
 	}
 
@@ -179,7 +179,7 @@ public enum FloatFormat {
 			case NOT_SET, NaN_AS_NULL -> null;
 			case NaN_AS_STRING -> nonFiniteToken(value);
 			case NaN_AS_NUMBER -> Double.valueOf(value);
-			case NaN_AS_ERROR -> throw iaex("Non-finite double value {0} rejected by FloatFormat.NaN_AS_ERROR", value);
+			case NaN_AS_ERROR -> throw iaex("Non-finite double value %s rejected by FloatFormat.NaN_AS_ERROR", value);
 		};
 	}
 
@@ -227,9 +227,9 @@ public enum FloatFormat {
 				return (T) Double.valueOf(parseDouble(s));
 			if (Float.class.equals(targetType) || float.class.equals(targetType))
 				return (T) Float.valueOf(parseFloat(s));
-			throw iaex("Unsupported FloatFormat target type: {0}", targetType.getName());
+			throw iaex("Unsupported FloatFormat target type: %s", targetType.getName());
 		} catch (NumberFormatException e) {
-			throw iaex("Invalid float value ''{0}'' for format {1}: {2}", value, format, e.getMessage());
+			throw iaex("Invalid float value '%s' for format %s: %s", value, format, e.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/InvalidDataConversionException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/InvalidDataConversionException.java
index b374b6123d..c13b7061ea 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/InvalidDataConversionException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/InvalidDataConversionException.java
@@ -60,7 +60,7 @@ public class InvalidDataConversionException extends BasicRuntimeException {
 	 * @param value The value being converted.
 	 */
 	public InvalidDataConversionException(Object value, Class<?> toType, Exception cause) {
-		this(cause, "Invalid data conversion from type ''{0}'' to type ''{1}''.  Value={2}.", name(value), name(toType), value(value));
+		this(cause, "Invalid data conversion from type '%s' to type '%s'.  Value=%s.", name(value), name(toType), value(value));
 	}
 
 	/**
@@ -69,7 +69,7 @@ public class InvalidDataConversionException extends BasicRuntimeException {
 	 * @param value The value being converted.
 	 */
 	public InvalidDataConversionException(Object value, ClassMeta<?> toType, Exception cause) {
-		this(cause, "Invalid data conversion from type ''{0}'' to type ''{1}''.  Value={2}.", name(value), s(toType), value(value));
+		this(cause, "Invalid data conversion from type '%s' to type '%s'.  Value=%s.", name(value), s(toType), value(value));
 	}
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshalledPropertyPostProcessor.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshalledPropertyPostProcessor.java
index 971fc45582..9a86c7cc23 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshalledPropertyPostProcessor.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshalledPropertyPostProcessor.java
@@ -527,7 +527,7 @@ final class MarshalledPropertyPostProcessor implements BeanPropertyPostProcessor
 				try {
 					validator.validate(v);
 				} catch (SchemaValidationException e) {
-					throw new BeanRuntimeException(e, null, "Schema validation failed on property ''{0}'': {1}", propertyName, e.getMessage());
+					throw new BeanRuntimeException(e, null, "Schema validation failed on property '%s': %s", propertyName, e.getMessage());
 				}
 			}
 			return v;
@@ -538,7 +538,7 @@ final class MarshalledPropertyPostProcessor implements BeanPropertyPostProcessor
 				try {
 					validator.validate(o);
 				} catch (SchemaValidationException e) {
-					throw new BeanRuntimeException(e, null, "Schema validation failed on property ''{0}'': {1}", propertyName, e.getMessage());
+					throw new BeanRuntimeException(e, null, "Schema validation failed on property '%s': %s", propertyName, e.getMessage());
 				}
 			}
 			return nn(innerWrite) ? innerWrite.apply(session, o) : o;
@@ -606,7 +606,7 @@ final class MarshalledPropertyPostProcessor implements BeanPropertyPostProcessor
 		}
 		if (ci.isAssignableTo(Surrogate.class))
 			throw uoex("Surrogate swaps not yet supported on bean properties.");
-		throw rex("Invalid class used in @Swap annotation.  Must be a subclass of ObjectSwap or Surrogate. {0}", cn(c));
+		throw rex("Invalid class used in @Swap annotation.  Must be a subclass of ObjectSwap or Surrogate. %s", cn(c));
 	}
 
 	private static ClassInfo owningClass(BeanPropertyMeta.Builder b) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingContext.java
index f067845eaf..67eca0c92a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingContext.java
@@ -4162,7 +4162,7 @@ public class MarshallingContext extends Context implements ConversionFinder, Bea
 				else if (ci.isAssignableTo(Surrogate.class))
 					objectSwapsList.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
 				else
-					throw rex("Invalid class {0} specified in MarshallingContext.swaps property.  Must be a subclass of ObjectSwap or Surrogate.", cn(ci.inner()));
+					throw rex("Invalid class %s specified in MarshallingContext.swaps property.  Must be a subclass of ObjectSwap or Surrogate.", cn(ci.inner()));
 			}
 		});
 		objectSwaps = u(objectSwapsList);
@@ -4547,7 +4547,7 @@ public class MarshallingContext extends Context implements ConversionFinder, Bea
 					var bs = beanSessionOrDefault(session);
 					var str = in.toString();
 					if (!isProbablyJsonArray(str, false))
-						throw rex("Cannot convert string to {0}: {1}", outType.getName(), str);
+						throw rex("Cannot convert string to %s: %s", outType.getName(), str);
 					var elemType = args.length > 0 ? args[0] : null;
 					var l2 = Json5List.ofString(str).setBeanSession(bs);
 					var result = newCollection(outType);
@@ -5528,7 +5528,7 @@ public class MarshallingContext extends Context implements ConversionFinder, Bea
 			if (cm2.isMap()) {
 				var pParams = (beanp.params().length == 0 ? a(Object.class, Object.class) : beanp.params());
 				if (pParams.length != 2)
-					throw rex("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length);
+					throw rex("Invalid number of parameters specified for Map (must be 2): %s", pParams.length);
 				var keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType());
 				var valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
 				if (keyType.isObject() && valueType.isObject())
@@ -5547,7 +5547,7 @@ public class MarshallingContext extends Context implements ConversionFinder, Bea
 					} else {
 						typeName = "Array";
 					}
-					throw rex("Invalid number of parameters specified for {1} (must be 1): {0}", pParams.length, typeName);
+					throw rex("Invalid number of parameters specified for %2$s (must be 1): %1$s", pParams.length, typeName);
 				}
 				var elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
 				if (elementType.isObject())
@@ -5713,4 +5713,4 @@ public class MarshallingContext extends Context implements ConversionFinder, Bea
 		}
 		return cmObject;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingSession.java
index 766acd2d44..ce0258cfbe 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingSession.java
@@ -1194,13 +1194,13 @@ public class MarshallingSession extends ContextSession implements ConverterSessi
 	public final <T> BeanMap<T> toBeanMap(T o, Class<? super T> c) throws BeanRuntimeException {
 		assertArgNotNull(ARG_o, o);
 		assertArgNotNull(ARG_c, c);
-		assertArg(c.isInstance(o), "The specified object is not an instance of the specified class.  class=''{0}'', objectClass=''{1}'', object=''{2}''", cn(c), cn(o), 0);
+		assertArg(c.isInstance(o), "The specified object is not an instance of the specified class.  class='%s', objectClass='%s', object='%s'", cn(c), cn(o), 0);
 
 		var cm = getClassMeta(c);
 
 		BeanMeta m = cm.getBeanMeta();
 		if (m == null)
-			throw brex(c, "Class is not a bean.  Reason=''{0}''", cm.getNotABeanReason());
+			throw brex(c, "Class is not a bean.  Reason='%s'", cm.getNotABeanReason());
 		var bm = new BeanMap<>(o, m);
 		bm.setBeanSession(this);
 		return bm;
@@ -1407,7 +1407,7 @@ public class MarshallingSession extends ContextSession implements ConverterSessi
 			return convertToType(value, cm);
 		if (targetType instanceof Class<?> c)
 			return convertToType(value, c);
-		throw iaex("Unsupported targetType for convertToType: {0}", cn(targetType));
+		throw iaex("Unsupported targetType for convertToType: %s", cn(targetType));
 	}
 
 	/**
@@ -1429,7 +1429,7 @@ public class MarshallingSession extends ContextSession implements ConverterSessi
 			return convertToMemberType(outer, value, cm);
 		if (targetType instanceof Class<?> c)
 			return convertToMemberType(outer, value, c);
-		throw iaex("Unsupported targetType for convertToMemberType: {0}", cn(targetType));
+		throw iaex("Unsupported targetType for convertToMemberType: %s", cn(targetType));
 	}
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingTraverseSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingTraverseSession.java
index cb11bba86c..96bddd5b12 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingTraverseSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/MarshallingTraverseSession.java
@@ -319,7 +319,7 @@ public class MarshallingTraverseSession extends MarshallingSession {
 			Object o = stack.removeLast().o;
 			Object o2 = set.remove(o);
 			if (o2 == null)
-				onError(null, "Couldn't remove object of type ''{0}'' on attribute ''{1}'' from object stack.", cn(o), stack);
+				onError(null, "Couldn't remove object of type '%s' on attribute '%s' from object stack.", cn(o), stack);
 		}
 		isBottom = false;
 	}
@@ -411,6 +411,6 @@ public class MarshallingTraverseSession extends MarshallingSession {
 			return true;
 
 		stack.add(new StackElement(stack.size(), attrName, o, cm));
-		throw new MarshallingRecursionException("Recursion occurred, stack={0}", getStack(true));
+		throw new MarshallingRecursionException("Recursion occurred, stack=%s", getStack(true));
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UuidFormat.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UuidFormat.java
index f62f7bb14a..4ce627433c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UuidFormat.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UuidFormat.java
@@ -154,7 +154,7 @@ public enum UuidFormat {
 		try {
 			return UUID.fromString(s);
 		} catch (IllegalArgumentException e) {
-			throw iaex("Invalid UUID value ''{0}'' for format {1}: {2}", value, format, e.getMessage());
+			throw iaex("Invalid UUID value '%s' for format %s: %s", value, format, e.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonInputStream.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonInputStream.java
index 774dc06b03..bfe04810ba 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonInputStream.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonInputStream.java
@@ -84,9 +84,9 @@ public class BsonInputStream extends ParserInputStream {
 	 */
 	private int checkLength(int len, String what) throws IOException {
 		if (len < 0)
-			throw ioex("Invalid BSON {0} length (negative): {1}", what, len);
+			throw ioex("Invalid BSON %s length (negative): %s", what, len);
 		if (len > maxLength)
-			throw ioex("BSON {0} length {1} exceeds maximum allowed {2}", what, len, maxLength);
+			throw ioex("BSON %s length %s exceeds maximum allowed %s", what, len, maxLength);
 		return len;
 	}
 
@@ -205,7 +205,7 @@ public class BsonInputStream extends ParserInputStream {
 	public void readDocumentTerminator() throws IOException {
 		var b = read();
 		if (b != 0x00)
-			throw ioex("Expected document terminator, got {0}", b);
+			throw ioex("Expected document terminator, got %s", b);
 	}
 
 	/**
@@ -260,7 +260,7 @@ public class BsonInputStream extends ParserInputStream {
 	public String readString() throws IOException {
 		var len = readLE4();
 		if (len <= 0)
-			throw ioex("Invalid BSON string length: {0}", len);
+			throw ioex("Invalid BSON string length: %s", len);
 		checkLength(len, "string");
 		var bytes = new byte[len - 1]; // length includes null
 		for (var i = 0; i < bytes.length; i++) {
@@ -271,7 +271,7 @@ public class BsonInputStream extends ParserInputStream {
 		}
 		var term = read();
 		if (term != 0x00)
-			throw ioex("Expected string terminator, got {0}", term);
+			throw ioex("Expected string terminator, got %s", term);
 		return new String(bytes, UTF8);
 	}
 
@@ -389,7 +389,7 @@ public class BsonInputStream extends ParserInputStream {
 			case 0x12 -> readLE8();
 			case 0x13 -> skip(16);
 			case 0x7F, 0xFF -> { /* BSON MinKey/MaxKey - zero bytes, marker types with no payload to consume */ }
-			default -> throw ioex("Unknown BSON type: {0}", type);
+			default -> throw ioex("Unknown BSON type: %s", type);
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonOutputStream.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonOutputStream.java
index 02dc16cd8e..0a38452e8d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonOutputStream.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/bson/BsonOutputStream.java
@@ -291,7 +291,7 @@ public class BsonOutputStream extends OutputStream {
 			// BSON Decimal128 (0x13) is bounded to 34 significant digits with exponent in [-6176,6111]; values
 			// outside that range are an unavoidable lossy case, so fail cleanly instead of leaking an unchecked
 			// NumberFormatException.  See the BsonSerializer limitations javadoc.
-			var e2 = new SerializeException("Value out of BSON Decimal128 range (max 34 significant digits, exponent -6176..6111): {0}", value);
+			var e2 = new SerializeException("Value out of BSON Decimal128 range (max 34 significant digits, exponent -6176..6111): %s", value);
 			e2.initCause(e);
 			throw e2;
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborInputStream.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborInputStream.java
index bceb83ca84..be883fc7a4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborInputStream.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborInputStream.java
@@ -151,7 +151,7 @@ public class CborInputStream extends ParserInputStream {
 			return readUInt8();
 		if (additionalInfo == 31)
 			throw ioex("Indefinite-length CBOR encoding not supported");
-		throw ioex("Reserved additional info value: {0}", additionalInfo);
+		throw ioex("Reserved additional info value: %s", additionalInfo);
 	}
 
 	/**
@@ -236,7 +236,7 @@ public class CborInputStream extends ParserInputStream {
 					default -> dt = SIMPLE;
 				}
 			}
-			default -> throw ioex("Invalid major type: {0}", majorType);
+			default -> throw ioex("Invalid major type: %s", majorType);
 		}
 
 		lastDataType = dt;
@@ -400,7 +400,7 @@ public class CborInputStream extends ParserInputStream {
 		var b = new byte[(int)length];
 		var bytesRead = read(b);
 		if (bytesRead != b.length)
-			throw ioex("Expected to read {0} bytes but only read {1}", b.length, bytesRead);
+			throw ioex("Expected to read %s bytes but only read %s", b.length, bytesRead);
 		return b;
 	}
 
@@ -426,14 +426,14 @@ public class CborInputStream extends ParserInputStream {
 			var chunkMajorType = getMajorType(ib);
 			var chunkInfo = getAdditionalInfo(ib);
 			if (chunkMajorType != expectedMajorType)
-				throw ioex("Invalid chunk major type {0} in indefinite-length string (expected {1})", chunkMajorType, expectedMajorType);
+				throw ioex("Invalid chunk major type %s in indefinite-length string (expected %s)", chunkMajorType, expectedMajorType);
 			if (chunkInfo == 31)
 				throw ioex("Nested indefinite-length string chunk not allowed");
 			var chunkLen = (int)readArgument(chunkInfo);
 			var chunk = new byte[chunkLen];
 			var bytesRead = read(chunk);
 			if (bytesRead != chunk.length)
-				throw ioex("Expected to read {0} bytes but only read {1}", chunk.length, bytesRead);
+				throw ioex("Expected to read %s bytes but only read %s", chunk.length, bytesRead);
 			baos.write(chunk, 0, chunk.length);
 		}
 		return baos.toByteArray();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborOutputStream.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborOutputStream.java
index 58525c8e0e..b63f799227 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborOutputStream.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborOutputStream.java
@@ -372,7 +372,7 @@ public class CborOutputStream extends OutputStream {
 		writeHead(3, length);
 		int length2 = writeUtf8To(s);
 		if (length != length2)
-			throw new SerializeException("Unexpected length.  Expected={0}, Actual={1}", length, length2);
+			throw new SerializeException("Unexpected length.  Expected=%s, Actual=%s", length, length2);
 		return this;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborParserSession.java
index 3ed21775a8..edf83e64b5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborParserSession.java
@@ -243,7 +243,7 @@ public class CborParserSession extends InputStreamParserSession implements Token
 					}
 					o = builder == null ? m.getBean() : builder.build(this, m.getBean(), eType);
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (sType.isMap()) {
 				if (dt == MAP) {
@@ -257,7 +257,7 @@ public class CborParserSession extends InputStreamParserSession implements Token
 					}
 					o = m;
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (sType.isBoolean() || sType.isCharSequence() || sType.isChar() || sType.isNumber() || sType.isByteArray()) {
 				// Merged scalar tier: one CBOR data type (BOOLEAN/UINT/NINT/FLOAT/STRING/BINARY) covers
@@ -287,7 +287,7 @@ public class CborParserSession extends InputStreamParserSession implements Token
 						l.add(parseAnything(sType.getElementType(), is, l, pMeta));
 					o = l;
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (sType.isArray() || sType.isArgs()) {
 				if (dt == MAP) {
@@ -301,7 +301,7 @@ public class CborParserSession extends InputStreamParserSession implements Token
 						l.add(parseAnything(sType.isArgs() ? sType.getArg(i) : sType.getElementType(), is, l, pMeta));
 					o = toArray(sType, l);
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (dt == MAP) {
 				var m = newGenericMap();
@@ -312,12 +312,12 @@ public class CborParserSession extends InputStreamParserSession implements Token
 				else if (nn(sType.getProxyInvocationHandler()))
 					o = newBeanMap(outer, sType.inner()).load(m).getBean();
 				else
-					throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+					throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 			} else if (dt == UNDEFINED || dt == SIMPLE) {
 				// Treat as null for unknown simple values
 				o = null;
 			} else {
-				throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+				throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 			}
 		}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborTokenReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborTokenReader.java
index 15b33bcdf0..0a58636dbd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborTokenReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cbor/CborTokenReader.java
@@ -289,7 +289,7 @@ public class CborTokenReader implements TokenReader {
 					// Guard against pathologically deep tag chains blowing the JVM stack.
 					if (tagNestingDepth >= maxTagNestingDepth)
 						throw new ParseException(
-							"CBOR tag nesting depth exceeded the maximum of {0}.  Increase the limit via CborTokenReader.setMaxTagNestingDepth(int) if this is intentional.",
+							"CBOR tag nesting depth exceeded the maximum of %s.  Increase the limit via CborTokenReader.setMaxTagNestingDepth(int) if this is intentional.",
 							maxTagNestingDepth);
 					tagNestingDepth++;
 					try {
@@ -305,7 +305,7 @@ public class CborTokenReader implements TokenReader {
 				currentToken = TokenType.VALUE_NULL;
 				consumedOneElement();
 			}
-			default -> throw new ParseException("Unexpected CBOR data type: {0}", dt);
+			default -> throw new ParseException("Unexpected CBOR data type: %s", dt);
 		}
 		return currentToken;
 	}
@@ -321,7 +321,7 @@ public class CborTokenReader implements TokenReader {
 			case BOOLEAN:   return Boolean.toString(is.readBoolean());
 			case FLOAT:     return Double.toString(is.readDouble());
 			default:
-				throw new ParseException("Cannot use CBOR data type {0} as a map key", dt);
+				throw new ParseException("Cannot use CBOR data type %s as a map key", dt);
 		}
 	}
 
@@ -456,7 +456,7 @@ public class CborTokenReader implements TokenReader {
 		} catch (Exception e) {
 			if (e instanceof IOException ioe) throw ioe;
 			if (e instanceof ParseException pe) throw pe;
-			throw new ParseException(s, "read failed: {0}", e.getMessage());
+			throw new ParseException(s, "read failed: %s", e.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonList.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonList.java
index b8a24d59f8..b0c7543327 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonList.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonList.java
@@ -670,7 +670,7 @@ public class JsonList extends MarshalledList {
 	 */
 	public Object cast(ClassMeta<?> cm) {
 		try {
-			return Json5Parser.DEFAULT.parse(Json5Serializer.DEFAULT.serialize(this), cm);
+			return Json5.to(Json5.of(this), cm);
 		} catch (ParseException | SerializeException e) {
 			throw toRex(e);
 		}
@@ -718,8 +718,8 @@ public class JsonList extends MarshalledList {
 	}
 
 	/**
-	 * Convenience method for serializing this JsonList to the specified Writer using the JsonSerializer.DEFAULT
-	 * serializer.
+	 * Convenience method for serializing this JsonList to the specified Writer using the {@link Json#DEFAULT}
+	 * marshaller.
 	 *
 	 * @param w The writer to send the serialized contents of this object.
 	 * @return This object.
@@ -727,7 +727,7 @@ public class JsonList extends MarshalledList {
 	 * @throws SerializeException If a problem occurred trying to convert the output.
 	 */
 	public JsonList writeTo(Writer w) throws IOException, SerializeException {
-		JsonSerializer.DEFAULT.serialize(this, w);
+		Json.DEFAULT.write(this, w);
 		return this;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonMap.java
index b2c6d25784..57edb591b3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonMap.java
@@ -692,7 +692,7 @@ public class JsonMap extends MarshalledMap {
 	 * @throws ParseException Malformed input encountered.
 	 */
 	public void putJson(String key, String json) throws ParseException {
-		this.put(key, JsonParser.DEFAULT.parse(json, Object.class));
+		this.put(key, Json.to(json, Object.class));
 	}
 
 	@Override /* Overridden from MarshalledMap */
@@ -721,7 +721,7 @@ public class JsonMap extends MarshalledMap {
 
 	/**
 	 * Convenience method for serializing this map to the specified <c>Writer</c> using the
-	 * {@link JsonSerializer#DEFAULT} serializer.
+	 * {@link Json#DEFAULT} marshaller.
 	 *
 	 * @param w The writer to serialize this object to.
 	 * @return This object.
@@ -729,7 +729,7 @@ public class JsonMap extends MarshalledMap {
 	 * @throws SerializeException If a problem occurred trying to convert the output.
 	 */
 	public JsonMap writeTo(Writer w) throws IOException, SerializeException {
-		JsonSerializer.DEFAULT.serialize(this, w);
+		Json.DEFAULT.write(this, w);
 		return this;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonPointer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonPointer.java
index 291a3f7858..ebb9b52e6f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonPointer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/JsonPointer.java
@@ -93,7 +93,7 @@ public class JsonPointer {
 		if (pointer.isEmpty())
 			return List.of();
 		if (pointer.charAt(0) != '/')
-			throw iaex("Invalid JSON Pointer ''{0}'': a non-empty pointer must begin with ''/''.", pointer);
+			throw iaex("Invalid JSON Pointer '%s': a non-empty pointer must begin with '/'.", pointer);
 		var parts = pointer.split("/", -1);
 		var tokens = new ArrayList<String>(parts.length - 1);
 		for (var i = 1; i < parts.length; i++)
@@ -236,14 +236,14 @@ public class JsonPointer {
 			}
 			var idx = toArrayIndex(token);
 			if (idx < 0 || idx > list.size())
-				throw iaex("Invalid JSON Pointer array index ''{0}'' for a list of size {1}.", token, list.size());
+				throw iaex("Invalid JSON Pointer array index '%s' for a list of size %s.", token, list.size());
 			if (idx == list.size())
 				list.add(value);
 			else
 				list.set(idx, value);
 			return;
 		}
-		throw iaex("Cannot set value at token ''{0}'' on a non-container value.", token);
+		throw iaex("Cannot set value at token '%s' on a non-container value.", token);
 	}
 
 	private static Object rawRemove(Object container, String token) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/MarshalledMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/MarshalledMap.java
index d22b90ba96..dbb994bf9f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/MarshalledMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/collections/MarshalledMap.java
@@ -1611,10 +1611,10 @@ public class MarshalledMap extends LinkedHashMap<String,Object> {
 			}
 
 		} catch (Exception e) {
-			throw brex(e, cm.inner(), "Error occurred attempting to cast to an object of type ''{0}''", cn(cm));
+			throw brex(e, cm.inner(), "Error occurred attempting to cast to an object of type '%s'", cn(cm));
 		}
 
-		throw brex(cm.inner(), "Cannot convert to class type ''{0}''.  Only beans and maps can be converted using this method.", cn(cm));
+		throw brex(cm.inner(), "Cannot convert to class type '%s'.  Only beans and maps can be converted using this method.", cn(cm));
 	}
 
 	private PathTraversal getPathTraversal() {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/ContextBeanCreator.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/ContextBeanCreator.java
index 6ec784965d..080745bdab 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/ContextBeanCreator.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/ContextBeanCreator.java
@@ -177,7 +177,7 @@ public class ContextBeanCreator<T> {
 	public ContextBeanCreator<T> type(Class<? extends T> value) {
 		builder = Context.createBuilder((Class<? extends Context>)value);
 		if (builder == null)
-			throw iaex("Creator for class {0} not found.", cn(value));
+			throw iaex("Creator for class %s not found.", cn(value));
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/Messages.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/Messages.java
index 6405d8b796..f4c18a489b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/Messages.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/cp/Messages.java
@@ -481,7 +481,7 @@ public class Messages extends ResourceBundle {
 		var s = getString(key);
 		if (s.startsWith("{!"))
 			return s;
-		return f(s, args);
+		return mf(s, args);
 	}
 
 	@Override /* Overridden from ResourceBundle */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvCellParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvCellParser.java
index 80db52480b..b8a1812d37 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvCellParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvCellParser.java
@@ -63,7 +63,7 @@ public final class CsvCellParser {
 		try {
 			return p.parseValue();
 		} catch (Exception e) {
-			throw new ParseException(e, "Invalid CSV cell notation at position {0}: ''{1}''", p.pos, cell);
+			throw new ParseException(e, "Invalid CSV cell notation at position %s: '%s'", p.pos, cell);
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvParserSession.java
index e4dcf1eb44..fa7bd56aa0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/csv/CsvParserSession.java
@@ -251,7 +251,7 @@ public class CsvParserSession extends ReaderParserSession implements RecordReada
 			}
 			if (m.containsKey(typeColName))
 				return cast(m, null, eType);
-			throw new ParseException(this, "Polymorphic type ''{0}'' requires _type column for resolution", eType);
+			throw new ParseException(this, "Polymorphic type '%s' requires _type column for resolution", eType);
 		}
 		if (eType.isBean()) {
 			return parseRowIntoBean(headers, row, eType, outer);
@@ -358,7 +358,7 @@ public class CsvParserSession extends ReaderParserSession implements RecordReada
 				return (T) csvParsed;
 			return convertToType(val, eType);
 		} catch (InvalidDataConversionException e) {
-			throw new ParseException(e, "Could not convert CSV cell value ''{0}'' to type ''{1}''.", val, eType);
+			throw new ParseException(e, "Could not convert CSV cell value '%s' to type '%s'.", val, eType);
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/encoders/EncoderSet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/encoders/EncoderSet.java
index e53fb7e814..b4d38ad0af 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/encoders/EncoderSet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/encoders/EncoderSet.java
@@ -167,7 +167,7 @@ public class EncoderSet {
 				if (Encoder.class.isAssignableFrom(v)) {
 					l.add(v);
 				} else if (! cns(v).equals("NoInherit")) {
-					throw iaex("Invalid type passed to EncoderSet.Builder.add(): {0}", cn(v));
+					throw iaex("Invalid type passed to EncoderSet.Builder.add(): %s", cn(v));
 				}
 			}
 			entries.addAll(0, l);
@@ -263,7 +263,7 @@ public class EncoderSet {
 				} else if (Encoder.class.isAssignableFrom(v)) {
 					l.add(v);
 				} else {
-					throw iaex("Invalid type passed to EncoderSet.Builder.set(): {0}", cn(v));
+					throw iaex("Invalid type passed to EncoderSet.Builder.set(): %s", cn(v));
 				}
 			}
 			entries = l;
@@ -408,4 +408,4 @@ public class EncoderSet {
 	 * @return An unmodifiable list of codings supported by all encoders in this group.  Never <jk>null</jk>.
 	 */
 	public List<String> getSupportedEncodings() { return encodings; }
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hjson/HjsonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hjson/HjsonParserSession.java
index 6eb314d94d..b957dcae5b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hjson/HjsonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hjson/HjsonParserSession.java
@@ -131,7 +131,7 @@ public class HjsonParserSession extends ReaderParserSession implements RecordRea
 		// Same per-property type threading as parseObject so braceless-root beans get typed-map keys (Bug #7b).
 		var beanMeta = (type != null && type.isBean()) ? type.getBeanMeta() : null;
 		if (t.read().type() != HjsonTokenizer.TokenType.COLON)
-			throw new ParseException(this, "Expected ':' after key at line {0}", t.getLine());
+			throw new ParseException(this, "Expected : after key at line %s", t.getLine());
 		t.skipWhitespaceAndComments();
 		var value = parseValue(t, propertyType(beanMeta, firstKey, type));
 		result.put(firstKey, value);
@@ -142,7 +142,7 @@ public class HjsonParserSession extends ReaderParserSession implements RecordRea
 			var key = readKey(t);
 			t.skipWhitespaceAndComments();
 			if (t.read().type() != HjsonTokenizer.TokenType.COLON)
-				throw new ParseException(this, "Expected ':' after key at line {0}", t.getLine());
+				throw new ParseException(this, "Expected : after key at line %s", t.getLine());
 			t.skipWhitespaceAndComments();
 			value = parseValue(t, propertyType(beanMeta, key, type));
 			result.put(key, value);
@@ -164,7 +164,7 @@ public class HjsonParserSession extends ReaderParserSession implements RecordRea
 			case LBRACE -> parseObject(t, type);
 			case LBRACKET -> parseArray(t, type);
 			case EOF -> null;
-			default -> throw new ParseException(this, "Unexpected token {0} at line {1}", tok.type(), t.getLine());
+			default -> throw new ParseException(this, "Unexpected token %s at line %s", tok.type(), t.getLine());
 		};
 		if (raw == null)
 			return null;
@@ -189,7 +189,7 @@ public class HjsonParserSession extends ReaderParserSession implements RecordRea
 			var key = readKey(t);
 			t.skipWhitespaceAndComments();
 			if (t.read().type() != HjsonTokenizer.TokenType.COLON)
-				throw new ParseException(this, "Expected ':' after key at line {0}", t.getLine());
+				throw new ParseException(this, "Expected : after key at line %s", t.getLine());
 			t.skipWhitespaceAndComments();
 			var valueType = propertyType(beanMeta, key, type);
 			var value = parseValue(t, valueType);
@@ -262,7 +262,7 @@ public class HjsonParserSession extends ReaderParserSession implements RecordRea
 			case TRUE -> "true";
 			case FALSE -> "false";
 			case NUMBER -> tok.numberValue().toString();
-			default -> throw new ParseException(this, "Expected key at line {0}", t.getLine());
+			default -> throw new ParseException(this, "Expected key at line %s", t.getLine());
 		};
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconParserSession.java
index 1961efa370..e410d50cd8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconParserSession.java
@@ -162,7 +162,7 @@ public class HoconParserSession extends ReaderParserSession implements RecordRea
 				value = resolveSelfRefConcatIfNeeded(value, path, root);
 				root.setPath(path, value);
 			} else {
-				throw new ParseException(this, "Expected =, : or brace at line {0}", t.getLine());
+				throw new ParseException(this, "Expected =, : or brace at line %s", t.getLine());
 			}
 			t.skipWhitespaceAndComments();
 			if (t.peek().type() == HoconTokenizer.TokenType.NEWLINE)
@@ -181,7 +181,7 @@ public class HoconParserSession extends ReaderParserSession implements RecordRea
 			case TRUE -> "true";
 			case FALSE -> "false";
 			case NUMBER -> tok.numberValue().toString();
-			default -> throw new ParseException(this, "Expected key at line {0}", t.getLine());
+			default -> throw new ParseException(this, "Expected key at line %s", t.getLine());
 		};
 		if (first == null)
 			return EMPTY_PATH;
@@ -318,7 +318,7 @@ public class HoconParserSession extends ReaderParserSession implements RecordRea
 				yield new HoconValue.HoconSubstitution(st.stringValue(), tok.type() == HoconTokenizer.TokenType.OPT_SUBSTITUTION);
 			}
 			case EOF -> null;
-			default -> throw new ParseException(this, "Unexpected token {0} at line {1}", tok.type(), t.getLine());
+			default -> throw new ParseException(this, "Unexpected token %s at line %s", tok.type(), t.getLine());
 		};
 	}
 
@@ -363,7 +363,7 @@ public class HoconParserSession extends ReaderParserSession implements RecordRea
 				value = resolveSelfRefConcatIfNeeded(value, fullPath, effectiveRoot);
 				obj.setPath(path, value);
 			} else {
-				throw new ParseException(this, "Expected =, : or brace at line {0}", t.getLine());
+				throw new ParseException(this, "Expected =, : or brace at line %s", t.getLine());
 			}
 			// skipWhitespaceAndComments is a no-op while a token is cached (see HoconTokenizer), so a
 			// closing `}` already peeked by parseValueOrConcat's concat loop is preserved here and the
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconResolver.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconResolver.java
index 1d6b98eed8..3c7b26a0e6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconResolver.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/hocon/HoconResolver.java
@@ -104,14 +104,14 @@ public class HoconResolver {
 	private HoconValue resolveSubstitution(HoconValue.HoconSubstitution sub, boolean optional) {
 		var path = sub.getPath();
 		if (inProgress.contains(path))
-			throw rex("Circular substitution: {0}", path);
+			throw rex("Circular substitution: %s", path);
 		inProgress.add(path);
 		try {
 			var found = lookup(path);
 			if (found == null) {
 				if (optional)
 					return null;
-				throw rex("Substitution ''${0}'' not found", path);
+				throw rex("Substitution '$%s' not found", path);
 			}
 			var resolved = resolveValue(found);
 			if (resolved != null)
@@ -202,14 +202,14 @@ public class HoconResolver {
 			Function<String, HoconValue> lookup) {
 		var path = sub.getPath();
 		if (inProgress.contains(path))
-			throw rex("Circular substitution: {0}", path);
+			throw rex("Circular substitution: %s", path);
 		inProgress.add(path);
 		try {
 			var found = lookup.apply(path);
 			if (found == null) {
 				if (optional)
 					return null;
-				throw rex("Substitution ''${0}'' not found", path);
+				throw rex("Substitution '$%s' not found", path);
 			}
 			var resolved = resolveValueWithLookup(found, lookup);
 			if (resolved != null)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlParserSession.java
index 98abb98499..fc8b6c3979 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlParserSession.java
@@ -158,7 +158,7 @@ public class HtmlParserSession extends XmlParserSession {
 			if (t == tag)
 				return tag;
 
-		throw new ParseException(this, "Unexpected tag: ''{0}''.  Expected one of the following: {1}", tag, expected);
+		throw new ParseException(this, "Unexpected tag: '%s'.  Expected one of the following: %s", tag, expected);
 	}
 
 	/*
@@ -221,7 +221,7 @@ public class HtmlParserSession extends XmlParserSession {
 			event = skipWs(r);
 
 		if (event == END_DOCUMENT)
-			throw new ParseException(this, "Unexpected end of stream in parseAnything for type ''{0}''", eType);
+			throw new ParseException(this, "Unexpected end of stream in parseAnything for type '%s'", eType);
 
 		// Handle @Html(asXml=true) beans.
 		var hcm = getHtmlClassMeta(sType);
@@ -389,7 +389,7 @@ public class HtmlParserSession extends XmlParserSession {
 		}
 
 		if (! isValid)
-			throw new ParseException(this, "Unexpected tag ''{0}'' for type ''{1}''", tag, eType);
+			throw new ParseException(this, "Unexpected tag '%s' for type '%s'", tag, eType);
 
 		if (nn(swap) && nn(o))
 			o = unswap(swap, o, eType);
@@ -626,7 +626,7 @@ public class HtmlParserSession extends XmlParserSession {
 		int et = r.getEventType();
 
 		if (et != START_ELEMENT)
-			throw new ParseException(this, "skipToNextTag() call on invalid event ''{0}''.  Must only be called on START_ELEMENT events.", XmlUtils.toReadableEvent(r));
+			throw new ParseException(this, "skipToNextTag() call on invalid event '%s'.  Must only be called on START_ELEMENT events.", XmlUtils.toReadableEvent(r));
 
 		String n = r.getLocalName();
 
@@ -652,7 +652,7 @@ public class HtmlParserSession extends XmlParserSession {
 		if (tag.isOneOf(expected))
 			r.next();
 		else
-			throw new ParseException(this, "Unexpected tag: ''{0}''.  Expected one of the following: {1}", tag, expected);
+			throw new ParseException(this, "Unexpected tag: '%s'.  Expected one of the following: %s", tag, expected);
 	}
 
 	/*
@@ -853,7 +853,7 @@ public class HtmlParserSession extends XmlParserSession {
 			}
 			return "";
 		} else {
-			throw new ParseException(this, "Invalid tag found in parseWhitespaceElement(): ''{0}''", tag);
+			throw new ParseException(this, "Invalid tag found in parseWhitespaceElement(): '%s'", tag);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlSerializerSession.java
index 9e1dc95103..07b10f05df 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlSerializerSession.java
@@ -714,7 +714,7 @@ public class HtmlSerializerSession extends XmlSerializerSession {
 		} catch (StackOverflowError t) {
 			throw t;
 		} catch (Exception t) {
-			onError(t, "Could not call getValue() on property ''{0}'', {1}", e.getKey(), localizedMessage(t));
+			onError(t, "Could not call getValue() on property '%s', %s", e.getKey(), localizedMessage(t));
 		}
 
 		String link = getLink(ppMeta);
@@ -1095,4 +1095,4 @@ public class HtmlSerializerSession extends XmlSerializerSession {
 
 		return super.serializeAnything(out, o, eType, keyName, elementName, elementNamespace, addNamespaceUris, format, isMixed, preserveWhitespace, pMeta);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlTag.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlTag.java
index ea163e3e94..dabf7c4706 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlTag.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlTag.java
@@ -77,7 +77,7 @@ enum HtmlTag {
 			return forString(r.getLocalName(), false);
 		else if (et == END_ELEMENT)
 			return forString(r.getLocalName(), true);
-		throw new ParseException(session, "Invalid call to HtmlTag.forEvent on event of type ''{0}''", XmlUtils.toReadableEvent(r));
+		throw new ParseException(session, "Invalid call to HtmlTag.forEvent on event of type '%s'", XmlUtils.toReadableEvent(r));
 	}
 
 	@SuppressWarnings({
@@ -154,4 +154,4 @@ enum HtmlTag {
 	public String toString() {
 		return label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/HttpPartSchema.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/HttpPartSchema.java
index 70fab81c14..f25b5fd124 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/HttpPartSchema.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/HttpPartSchema.java
@@ -701,7 +701,7 @@ public class HttpPartSchema {
 				if (ine(value))
 					this.collectionFormat = HttpPartCollectionFormat.fromString(value);
 			} catch (Exception e) {
-				throw new BasicRuntimeException(e, "Invalid value ''{0}'' passed in as collectionFormat value.  Valid values: {1}", value, HttpPartCollectionFormat.values());
+				throw new BasicRuntimeException(e, "Invalid value '%s' passed in as collectionFormat value.  Valid values: %s", value, HttpPartCollectionFormat.values());
 			}
 			return this;
 		}
@@ -1249,7 +1249,7 @@ public class HttpPartSchema {
 				if (ine(value))
 					format = HttpPartFormat.fromString(value);
 			} catch (Exception e) {
-				throw new BasicRuntimeException(e, "Invalid value ''{0}'' passed in as format value.  Valid values: {1}", value, HttpPartFormat.values());
+				throw new BasicRuntimeException(e, "Invalid value '%s' passed in as format value.  Valid values: %s", value, HttpPartFormat.values());
 			}
 			return this;
 		}
@@ -2002,7 +2002,7 @@ public class HttpPartSchema {
 				if (ine(value))
 					this.pattern = Pattern.compile(value);
 			} catch (Exception e) {
-				throw new BasicRuntimeException(e, "Invalid value {0} passed in as pattern value.  Must be a valid regular expression.", value);
+				throw new BasicRuntimeException(e, "Invalid value %s passed in as pattern value.  Must be a valid regular expression.", value);
 			}
 			return this;
 		}
@@ -2459,7 +2459,7 @@ public class HttpPartSchema {
 				if (ine(value))
 					type = HttpPartDataType.fromString(value);
 			} catch (Exception e) {
-				throw new BasicRuntimeException(e, "Invalid value ''{0}'' passed in as type value.  Valid values: {1}", value, HttpPartDataType.values());
+				throw new BasicRuntimeException(e, "Invalid value '%s' passed in as type value.  Valid values: %s", value, HttpPartDataType.values());
 			}
 			return this;
 		}
@@ -4205,17 +4205,17 @@ public class HttpPartSchema {
 			if (! isValidAllowEmpty(in))
 				throw new SchemaValidationException("Empty value not allowed.");
 			if (! isValidConst(in))
-				throw new SchemaValidationException("Value does not match constant.  Must be: {0}", const_);
+				throw new SchemaValidationException("Value does not match constant.  Must be: %s", const_);
 			if (! isValidPattern(in))
-				throw new SchemaValidationException("Value does not match expected pattern.  Must match pattern: {0}", pattern.pattern());
+				throw new SchemaValidationException("Value does not match expected pattern.  Must match pattern: %s", pattern.pattern());
 			if (! isValidEnum(in))
-				throw new SchemaValidationException("Value does not match one of the expected values.  Must be one of the following:  {0}", toCdl(enum_));
+				throw new SchemaValidationException("Value does not match one of the expected values.  Must be one of the following:  %s", toCdl(enum_));
 			if (! isValidMaxLength(in))
 				throw new SchemaValidationException("Maximum length of value exceeded.");
 			if (! isValidMinLength(in))
 				throw new SchemaValidationException("Minimum length of value not met.");
 			if (! isValidFormat(in))
-				throw new SchemaValidationException("Value does not match expected format: {0}", format);
+				throw new SchemaValidationException("Value does not match expected format: %s", format);
 		}
 		return in;
 	}
@@ -4314,9 +4314,9 @@ public class HttpPartSchema {
 					if (! isValidMaxLength(s))
 						throw new SchemaValidationException("Maximum length of value exceeded.");
 					if (! isValidPattern(s))
-						throw new SchemaValidationException("Value does not match expected pattern.  Must match pattern: {0}", pattern.pattern());
+						throw new SchemaValidationException("Value does not match expected pattern.  Must match pattern: %s", pattern.pattern());
 					if (! isValidFormat(s))
-						throw new SchemaValidationException("Value does not match expected format: {0}", format);
+						throw new SchemaValidationException("Value does not match expected format: %s", format);
 				}
 				break;
 			}
@@ -5066,4 +5066,4 @@ public class HttpPartSchema {
 	private static boolean resolve(Boolean b) {
 		return b != null && b;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniParserSession.java
index 956a9d50fe..c4061cd90d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniParserSession.java
@@ -102,7 +102,7 @@ public class IniParserSession extends ReaderParserSession implements RecordReada
 			if (sections.isEmpty())
 				return type.canCreateNewBean(getOuter()) ? type.newInstance(getOuter()) : null;
 			if (!type.isBean() && !type.isMap())
-				throw new ParseException(this, "INI format requires bean or Map<String,?> target. Got: {0}", type.inner().getName());
+				throw new ParseException(this, "INI format requires bean or Map<String,?> target. Got: %s", type.inner().getName());
 			if (type.isMap()) {
 				var result = buildMapFromSections(sections, "");
 				return (T) convertMapToTarget(result, type);
@@ -183,7 +183,7 @@ public class IniParserSession extends ReaderParserSession implements RecordReada
 				if (pMeta == null && isIgnoreUnknownBeanProperties())
 					continue;
 				if (pMeta == null)
-					throw new ParseException(this, "Unknown property ''{0}''", key);
+					throw new ParseException(this, "Unknown property '%s'", key);
 				var value = parseValue(rawValue, (ClassMeta<?>) pMeta.getBeanInfo());
 				bm.put(key, value);
 			}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniSerializerSession.java
index eb68cc77c6..6296cbe450 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/ini/IniSerializerSession.java
@@ -99,7 +99,7 @@ public class IniSerializerSession extends WriterSerializerSession implements Rec
 			return;
 		var aType = getClassMetaForObject(o);
 		if (!aType.isBean() && !aType.isMap())
-			throw new SerializeException(this, "INI format requires a bean or Map<String,?> at root. Got: {0}", aType.inner().getName());
+			throw new SerializeException(this, "INI format requires a bean or Map<String,?> at root. Got: %s", aType.inner().getName());
 		var w = getIniWriter(out);
 		var eType = getExpectedRootType(o);
 		if (isAddBeanTypes() || isAddRootType()) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/internal/DelegateBeanMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/internal/DelegateBeanMap.java
index 963a44a5ae..f780993fe3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/internal/DelegateBeanMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/internal/DelegateBeanMap.java
@@ -91,7 +91,7 @@ public class DelegateBeanMap<T> extends BeanMap<T> {
 			else
 				bme = this.getProperty(k);
 			if (bme == null)
-				throw brex(super.getBeanInfo().inner(), "Property ''{0}'' not found on class.", k);
+				throw brex(super.getBeanInfo().inner(), "Property '%s' not found on class.", k);
 			s.add(bme);
 		});
 		return s;
@@ -169,4 +169,4 @@ public class DelegateBeanMap<T> extends BeanMap<T> {
 		keys.remove(key);
 		return null;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jcs/JcsWriter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jcs/JcsWriter.java
index 9e54ae08dc..5d78c6dcf4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jcs/JcsWriter.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jcs/JcsWriter.java
@@ -110,10 +110,10 @@ public class JcsWriter extends JsonWriter {
 			var c = s.charAt(i);
 			if (Character.isHighSurrogate(c)) {
 				if (i + 1 >= s.length() || !Character.isLowSurrogate(s.charAt(i + 1)))
-					throw rex("Lone high surrogate at index {0} in string", i);
+					throw rex("Lone high surrogate at index %s in string", i);
 				i++;
 			} else if (Character.isLowSurrogate(c)) {
-				throw rex("Lone low surrogate at index {0} in string", i);
+				throw rex("Lone low surrogate at index %s in string", i);
 			}
 		}
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonParserSession.java
index 05f68d38b5..716ce04cb9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonParserSession.java
@@ -263,11 +263,11 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 			else if (nn(sType.getProxyInvocationHandler()))
 				o = newBeanMap(outer, sType.inner()).load(m).getBean();
 			else
-				throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+				throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		} else if (sType.canCreateNewInstanceFromString(outer) && canCoerceNonStringToString()) {
 			o = sType.newInstanceFromString(outer, parseString(r));
 		} else {
-			throw new ParseException(this, "Unrecognized syntax for class type ''{0}'', starting character ''{1}''", sType, (char)c);
+			throw new ParseException(this, "Unrecognized syntax for class type '%s', starting character '%s'", sType, (char)c);
 		}
 
 		if (nn(wrapperAttr))
@@ -293,7 +293,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 			parseKeyword("false", r);
 			return Boolean.FALSE;
 		} else {
-			throw new ParseException(this, "Unrecognized syntax.  Expected boolean value, actual=''{0}''", r.read(100));
+			throw new ParseException(this, "Unrecognized syntax.  Expected boolean value, actual='%s'", r.read(100));
 		}
 	}
 
@@ -572,9 +572,9 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 			String s = r.read(keyword.length());
 			if (s.equals(keyword))
 				return;
-			throw new ParseException(this, "Unrecognized syntax.  Expected=''{0}'', Actual=''{1}''", keyword, s);
+			throw new ParseException(this, "Unrecognized syntax.  Expected='%s', Actual='%s'", keyword, s);
 		} catch (@SuppressWarnings("unused") IndexOutOfBoundsException e) {
-			throw new ParseException(this, "Unrecognized syntax.  Expected=''{0}'', found end-of-file.", keyword);
+			throw new ParseException(this, "Unrecognized syntax.  Expected='%s', found end-of-file.", keyword);
 		}
 	}
 
@@ -593,7 +593,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 	protected Number parseNumber(ParserReader r, String s, Class<? extends Number> type) throws ParseException {
 
 		if (s.isEmpty())
-			throw new ParseException(this, "Invalid JSON number: ''{0}''", s);
+			throw new ParseException(this, "Invalid JSON number: '%s'", s);
 
 		var isNegative = false;
 		var c = s.charAt(0);
@@ -603,17 +603,17 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 		}
 
 		if (c == '.')
-			throw new ParseException(this, "Invalid JSON number: ''{0}''", s);
+			throw new ParseException(this, "Invalid JSON number: '%s'", s);
 
 		if (c == '0' && s.length() > (isNegative ? 2 : 1)) {
 			var c2 = s.charAt((isNegative ? 2 : 1));
 			if (c2 != '.' && c2 != 'e' && c2 != 'E')
-				throw new ParseException(this, "Invalid JSON number: ''{0}''", s);
+				throw new ParseException(this, "Invalid JSON number: '%s'", s);
 		}
 
 		var i = s.indexOf('.');
 		if (i != -1 && (s.length() == (i + 1) || ! decChars.contains(s.charAt(i + 1))))
-			throw new ParseException(this, "Invalid JSON number: ''{0}''", s);
+			throw new ParseException(this, "Invalid JSON number: '%s'", s);
 
 		return StringUtils.parseNumber(s, type);
 	}
@@ -632,7 +632,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 		r.mark();
 		int qc = r.read();
 		if (qc != '"') {
-			var msg = (qc == '\'' ? "Invalid quote character \"{0}\" being used." : "Did not find quote character marking beginning of string.  Character=\"{0}\"");
+			var msg = (qc == '\'' ? "Invalid quote character \"%s\" being used." : "Did not find quote character marking beginning of string.  Character=\"%s\"");
 			throw new ParseException(this, msg, (char)qc);
 		}
 		String s = null;
@@ -641,7 +641,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 		while (c != -1) {
 			c = r.read();
 			if (c <= 0x1F)
-				throw new ParseException(this, "Unescaped control character encountered: ''0x{0}''", String.format("%04X", c));
+				throw new ParseException(this, "Unescaped control character encountered: '0x%s'", String.format("%04X", c));
 			if (isInEscape) {
 				// @formatter:off
 				switch (c) {
@@ -679,7 +679,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 			}
 		}
 		if (s == null)
-			throw new ParseException(this, "Could not find expected end character ''{0}''.", (char)qc);
+			throw new ParseException(this, "Could not find expected end character '%s'.", (char)qc);
 
 		skipCommentsAndSpace(r);
 		if (r.peek() == '+')
@@ -770,7 +770,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 				} else {
 					currAttr = parseFieldName(r.unread());
 					if (! currAttr.equals(wrapperAttr))
-						throw new ParseException(this, "Expected to find wrapper attribute ''{0}'' but found attribute ''{1}''", wrapperAttr, currAttr);
+						throw new ParseException(this, "Expected to find wrapper attribute '%s' but found attribute '%s'", wrapperAttr, currAttr);
 					state = S3;
 				}
 			} else if (state == S3) {  // NOSONAR - State check necessary for state machine
@@ -803,7 +803,7 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 		skipCommentsAndSpace(r);
 		int c = r.read();
 		if (c != -1 && c != ';')  // var x = {...}; expressions can end with a semicolon.
-			throw new ParseException(this, "Remainder after parse: ''{0}''.", (char)c);
+			throw new ParseException(this, "Remainder after parse: '%s'.", (char)c);
 	}
 
 	@Override /* Overridden from ParserSession */
@@ -975,4 +975,4 @@ public class JsonParserSession extends ReaderParserSession implements TokenReada
 	protected MarshalledList newGenericList() {
 		return new JsonList(this);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonTokenReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonTokenReader.java
index 6bf9f6247e..835533b80c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonTokenReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json/JsonTokenReader.java
@@ -91,13 +91,13 @@ public class JsonTokenReader implements TokenReader {
 	 * Error-message format string for invalid JSON numbers.  Used with
 	 * {@link #parseException(String, Object...)}.
 	 */
-	protected static final String MSG_invalidNumber = "Invalid JSON number: ''{0}''";
+	protected static final String MSG_invalidNumber = "Invalid JSON number: '%s'";
 
 	/**
 	 * Error-message format string for unexpected characters at the cursor's current position.
 	 * Used with {@link #parseException(String, Object...)}.
 	 */
-	protected static final String MSG_unexpectedChar = "Unexpected character: ''{0}''";
+	protected static final String MSG_unexpectedChar = "Unexpected character: '%s'";
 
 	/**
 	 * State-machine state: at root, after <c>[</c>, after <c>:</c>, or after <c>,</c> inside an
@@ -363,7 +363,7 @@ public class JsonTokenReader implements TokenReader {
 						return;
 					}
 					if (c != ',')
-						throw parseException("Expected ',' or ']' but got ''{0}''", (char) c);
+						throw parseException("Expected , or ] but got '%s'", (char) c);
 					// If a trailing-comma case follows (next non-ws is ']'), keep the comma-or-end
 					// state so a subsequent next() closes the container correctly.  Format-specific
 					// hook: plain JSON rejects trailing commas, JSON5 accepts.
@@ -385,7 +385,7 @@ public class JsonTokenReader implements TokenReader {
 						return;
 					}
 					if (c != ',')
-						throw parseException("Expected ',' or '}' but got ''{0}''", (char) c);
+						throw parseException("Expected , or } but got '%s'", (char) c);
 					var c2 = readSkipWsAndComments();
 					if (c2 == '}') {
 						r.unread();
@@ -403,7 +403,7 @@ public class JsonTokenReader implements TokenReader {
 					if (c == -1)
 						return;
 					if (c != ':')
-						throw parseException("Expected ':' after field name but got ''{0}''", (char) c);
+						throw parseException("Expected : after field name but got '%s'", (char) c);
 					state = S00_expectValue;
 					break;
 				}
@@ -445,7 +445,7 @@ public class JsonTokenReader implements TokenReader {
 		} catch (Exception e) {
 			if (e instanceof IOException ioe) throw ioe;
 			if (e instanceof ParseException pe) throw pe;
-			throw new ParseException(s, "read failed: {0}", e.getMessage());
+			throw new ParseException(s, "read failed: %s", e.getMessage());
 		}
 	}
 
@@ -578,7 +578,7 @@ public class JsonTokenReader implements TokenReader {
 			return;
 		}
 		if (c != '"')
-			throw parseException("Expected '\"' for field name but got ''{0}''", (char) c);
+			throw parseException("Expected \" for field name but got '%s'", (char) c);
 		r.unread();
 		currentFieldName = maybeTrim(readString());
 		currentToken = TokenType.FIELD_NAME;
@@ -593,7 +593,7 @@ public class JsonTokenReader implements TokenReader {
 
 	private void readColonThenValue(int c) throws IOException, ParseException {
 		if (c != ':')
-			throw parseException("Expected ':' after field name but got ''{0}''", (char) c);
+			throw parseException("Expected : after field name but got '%s'", (char) c);
 		var c2 = readSkipWsAndComments();
 		if (c2 == -1)
 			throw parseException("Unexpected end of input after ':'");
@@ -620,7 +620,7 @@ public class JsonTokenReader implements TokenReader {
 			return;
 		}
 		if (c != ',')
-			throw parseException("Expected ',' or '}' but got ''{0}''", (char) c);
+			throw parseException("Expected , or } but got '%s'", (char) c);
 		var c2 = readSkipWsAndComments();
 		if (c2 == -1)
 			throw parseException("Unexpected end of input after ','");
@@ -648,7 +648,7 @@ public class JsonTokenReader implements TokenReader {
 			return;
 		}
 		if (c != ',')
-			throw parseException("Expected ',' or ']' but got ''{0}''", (char) c);
+			throw parseException("Expected , or ] but got '%s'", (char) c);
 		var c2 = readSkipWsAndComments();
 		if (c2 == -1)
 			throw parseException("Unexpected end of input after ','");
@@ -698,7 +698,7 @@ public class JsonTokenReader implements TokenReader {
 		while (c != -1) {
 			c = r.read();
 			if (c <= 0x1F && c != -1)
-				throw parseException("Unescaped control character encountered: ''0x{0}''", String.format("%04X", c));
+				throw parseException("Unescaped control character encountered: '0x%s'", String.format("%04X", c));
 			if (inEscape) {
 				switch (c) {
 					case 'n': r.replace('\n'); break;
@@ -771,7 +771,7 @@ public class JsonTokenReader implements TokenReader {
 	private void expectLiteral(String literal) throws IOException, ParseException {
 		var s = r.read(literal.length());
 		if (!literal.equals(s))
-			throw parseException("Unrecognized syntax.  Expected=''{0}'', Actual=''{1}''", literal, s);
+			throw parseException("Unrecognized syntax.  Expected='%s', Actual='%s'", literal, s);
 	}
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5List.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5List.java
index ac966de4ad..5d2edf2a8f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5List.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5List.java
@@ -392,7 +392,7 @@ public class Json5List extends MarshalledList {
 	 */
 	public Object cast(ClassMeta<?> cm) {
 		try {
-			return Json5Parser.DEFAULT.parse(Json5Serializer.DEFAULT.serialize(this), cm);
+			return Json5.to(Json5.of(this), cm);
 		} catch (ParseException | SerializeException e) {
 			throw toRex(e);
 		}
@@ -452,8 +452,8 @@ public class Json5List extends MarshalledList {
 	}
 
 	/**
-	 * Convenience method for serializing this list to the specified Writer using the {@link Json5Serializer#DEFAULT}
-	 * serializer.
+	 * Convenience method for serializing this list to the specified Writer using the {@link Json5#DEFAULT}
+	 * marshaller.
 	 *
 	 * @param w The writer to send the serialized contents of this object.
 	 * @return This object.
@@ -461,7 +461,7 @@ public class Json5List extends MarshalledList {
 	 * @throws SerializeException If a problem occurred trying to convert the output.
 	 */
 	public Json5List writeTo(Writer w) throws IOException, SerializeException {
-		Json5Serializer.DEFAULT.serialize(this, w);
+		Json5.DEFAULT.write(this, w);
 		return this;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5Map.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5Map.java
index 6cc253d4bd..fe7ef69542 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5Map.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5Map.java
@@ -504,7 +504,7 @@ public class Json5Map extends MarshalledMap {
 	 * @throws ParseException Malformed input encountered.
 	 */
 	public void putJson5(String key, String json5) throws ParseException {
-		this.put(key, Json5Parser.DEFAULT.parse(json5, Object.class));
+		this.put(key, Json5.to(json5, Object.class));
 	}
 
 	@Override /* Overridden from MarshalledMap */
@@ -556,7 +556,7 @@ public class Json5Map extends MarshalledMap {
 
 	/**
 	 * Convenience method for serializing this map to the specified <c>Writer</c> using the
-	 * {@link Json5Serializer#DEFAULT} serializer.
+	 * {@link Json5#DEFAULT} marshaller.
 	 *
 	 * @param w The writer to serialize this object to.
 	 * @return This object.
@@ -564,7 +564,7 @@ public class Json5Map extends MarshalledMap {
 	 * @throws SerializeException If a problem occurred trying to convert the output.
 	 */
 	public Json5Map writeTo(Writer w) throws IOException, SerializeException {
-		Json5Serializer.DEFAULT.serialize(this, w);
+		Json5.DEFAULT.write(this, w);
 		return this;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5ParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5ParserSession.java
index be03fe88c5..a5e7ab75bd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5ParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5ParserSession.java
@@ -197,7 +197,7 @@ public class Json5ParserSession extends JsonParserSession {
 			}
 		}
 		if (s == null)
-			throw new ParseException(this, "Could not find expected end character ''{0}''.", (char)qc);
+			throw new ParseException(this, "Could not find expected end character '%s'.", (char)qc);
 
 		skipCommentsAndSpace(r);
 		if (r.peek() == '+') {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5TokenReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5TokenReader.java
index 83d0ab4b2b..e5b66e4810 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5TokenReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/json5/Json5TokenReader.java
@@ -156,7 +156,7 @@ public class Json5TokenReader extends JsonTokenReader {
 			return;
 		}
 		if (c != ',')
-			throw parseException("Expected ',' or ']' but got ''{0}''", (char) c);
+			throw parseException("Expected , or ] but got '%s'", (char) c);
 		var c2 = readSkipWsAndComments();
 		if (c2 == -1)
 			throw parseException("Unexpected end of input after ','");
@@ -180,7 +180,7 @@ public class Json5TokenReader extends JsonTokenReader {
 			return;
 		}
 		if (c != ',')
-			throw parseException("Expected ',' or '}' but got ''{0}''", (char) c);
+			throw parseException("Expected , or } but got '%s'", (char) c);
 		var c2 = readSkipWsAndComments();
 		if (c2 == -1)
 			throw parseException("Unexpected end of input after ','");
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/JsonSchemaGeneratorSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/JsonSchemaGeneratorSession.java
index f0d65951c5..b8d26e821b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/JsonSchemaGeneratorSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/JsonSchemaGeneratorSession.java
@@ -32,7 +32,7 @@ import org.apache.juneau.commons.utils.*;
 import org.apache.juneau.marshall.*;
 import org.apache.juneau.marshall.collections.*;
 import org.apache.juneau.marshall.json.*;
-import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.marshall.marshaller.*;
 import org.apache.juneau.marshall.parser.*;
 import org.apache.juneau.marshall.serializer.*;
 
@@ -259,7 +259,7 @@ public class JsonSchemaGeneratorSession extends MarshallingTraverseSession {
 			var example = sType.getExample(this, jpSession());
 			if (nn(example)) {
 				try {
-					return Json5Parser.DEFAULT.parse(toJson(example), Object.class);
+					return Json5.to(toJson(example), Object.class);
 				} catch (ParseException e) {
 					throw new SerializeException(e);
 				}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/SchemaUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/SchemaUtils.java
index 9fc866f841..db966e4108 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/SchemaUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/jsonschema/SchemaUtils.java
@@ -83,7 +83,7 @@ public class SchemaUtils {
 			return o2;
 		if (o instanceof MarshalledMap o2)
 			return new JsonMap(o2);
-		throw new ParseException("Unexpected data type ''{0}''.  Expected Map or String.", cn(o));
+		throw new ParseException("Unexpected data type '%s'.  Expected Map or String.", cn(o));
 	}
 
 	/**
@@ -125,4 +125,4 @@ public class SchemaUtils {
 		Json5List.ofJson5OrCdl(s).forEach(x -> set.add(x.toString()));
 		return set;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/markdown/MarkdownParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/markdown/MarkdownParserSession.java
index 8d516c1fd2..ed23fef88d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/markdown/MarkdownParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/markdown/MarkdownParserSession.java
@@ -255,7 +255,7 @@ public class MarkdownParserSession extends ReaderParserSession implements Record
 			try {
 				return getJson5Parser().parseWithOuter(json5, eType, outer);
 			} catch (Exception e) {
-				throw new ParseException(this, e, "Could not parse key-value table as ''{0}'' via JSON5 ''{1}''.", eType, json5);
+				throw new ParseException(this, e, "Could not parse key-value table as '%s' via JSON5 '%s'.", eType, json5);
 			}
 		}
 
@@ -293,7 +293,7 @@ public class MarkdownParserSession extends ReaderParserSession implements Record
 					try {
 						setName(pmcm, val, key);
 					} catch (Exception e) {
-						throw new ParseException(this, e, "Could not set @NameProperty on ''{0}''.", key);
+						throw new ParseException(this, e, "Could not set @NameProperty on '%s'.", key);
 					}
 					pm.set(m, key, val);
 					setCurrentProperty(null);
@@ -324,7 +324,7 @@ public class MarkdownParserSession extends ReaderParserSession implements Record
 				try {
 					setName(valueType, val, key);
 				} catch (Exception e) {
-					throw new ParseException(this, e, "Could not set @NameProperty for map key ''{0}''.", key);
+					throw new ParseException(this, e, "Could not set @NameProperty for map key '%s'.", key);
 				}
 				map.put(key, val);
 			}
@@ -438,7 +438,7 @@ public class MarkdownParserSession extends ReaderParserSession implements Record
 				try {
 				return getJson5Parser().parseWithOuter(json5, actualType, outer);
 			} catch (Exception e) {
-				throw new ParseException(this, e, "Could not parse table row as ''{0}'' via JSON5 ''{1}''.", actualType, json5);
+				throw new ParseException(this, e, "Could not parse table row as '%s' via JSON5 '%s'.", actualType, json5);
 			}
 		}
 
@@ -585,7 +585,7 @@ public class MarkdownParserSession extends ReaderParserSession implements Record
 			try {
 				return getJson5Parser().parseWithOuter(inner, eType, outer);
 			} catch (Exception e) {
-				throw new ParseException(this, e, "Could not parse inline JSON5 ''{0}'' to type ''{1}''.", inner, eType);
+				throw new ParseException(this, e, "Could not parse inline JSON5 '%s' to type '%s'.", inner, eType);
 			}
 		}
 
@@ -620,7 +620,7 @@ public class MarkdownParserSession extends ReaderParserSession implements Record
 		try {
 			return convertToType(val, eType);
 		} catch (@SuppressWarnings("unused") Exception e) {
-			throw new ParseException(this, "Could not convert Markdown cell value ''{0}'' to type ''{1}''.", val, eType);
+			throw new ParseException(this, "Could not convert Markdown cell value '%s' to type '%s'.", val, eType);
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackInputStream.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackInputStream.java
index d45108b027..c7eb4089f1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackInputStream.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackInputStream.java
@@ -127,7 +127,7 @@ public class MsgPackInputStream extends ParserInputStream {
 		// Java arrays/collections are int-indexed; a 32-bit MessagePack length in [2^31, 2^32-1] would
 		// otherwise truncate to a negative int and allocate the wrong size (G8).
 		if (length > Integer.MAX_VALUE)
-			throw ioex("MessagePack length {0} exceeds the maximum supported size of {1}.", length, Integer.MAX_VALUE);
+			throw ioex("MessagePack length %s exceeds the maximum supported size of %s.", length, Integer.MAX_VALUE);
 		var b = new byte[(int)length];
 		var bytesRead = read(b);
 		if (bytesRead != b.length)
@@ -154,7 +154,7 @@ public class MsgPackInputStream extends ParserInputStream {
 	DataType readDataType() throws IOException {
 		int i = read();
 		if (i == -1)
-			throw ioex("Unexpected end of file found at position {0}", pos2);
+			throw ioex("Unexpected end of file found at position %s", pos2);
 		DataType currentDataType = TYPES[i];
 		switch (currentDataType) {
 			case NULL, FLOAT: {
@@ -542,4 +542,4 @@ public class MsgPackInputStream extends ParserInputStream {
 	String readString() throws IOException {
 		return new String(readBinary(), UTF8);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackOutputStream.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackOutputStream.java
index 4d6206b683..85483ef054 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackOutputStream.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackOutputStream.java
@@ -398,7 +398,7 @@ public class MsgPackOutputStream extends OutputStream {
 			return appendLong(value.longValue());
 		if (value.signum() > 0 && value.bitLength() == 64)
 			return append1(UINT64).append8(value.longValue());
-		throw new SerializeException("BigInteger value ''{0}'' is outside the range supported by MessagePack integer types (64-bit).", value);
+		throw new SerializeException("BigInteger value '%s' is outside the range supported by MessagePack integer types (64-bit).", value);
 	}
 
 	/**
@@ -445,7 +445,7 @@ public class MsgPackOutputStream extends OutputStream {
 		int length2 = writeUtf8To(cs);
 
 		if (length != length2)
-			throw new SerializeException("Unexpected length.  Expected={0}, Actual={1}", length, length2);
+			throw new SerializeException("Unexpected length.  Expected=%s, Actual=%s", length, length2);
 
 		return this;
 	}
@@ -515,4 +515,4 @@ public class MsgPackOutputStream extends OutputStream {
 			return append1(MAP16).append2(size);
 		return append1(MAP32).append4(size);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackParserSession.java
index 174b94b5c2..c4151adfdb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackParserSession.java
@@ -166,7 +166,7 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 	<T> T parseAnything(ClassMeta<?> eType, MsgPackInputStream is, Object outer, BeanPropertyMeta pMeta) throws IOException, ParseException, ExecutableException {
 		if (++parseDepth > MAX_PARSE_DEPTH) {
 			parseDepth--;
-			throw new ParseException(this, "Maximum parse depth exceeded ({0}).", MAX_PARSE_DEPTH);
+			throw new ParseException(this, "Maximum parse depth exceeded (%s).", MAX_PARSE_DEPTH);
 		}
 		try {
 			return parseAnything0(eType, is, outer, pMeta);
@@ -207,7 +207,7 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 		// G8: array32/map32/str32/bin32/ext32 lengths are 32-bit unsigned (up to 2^32-1); a value in
 		// [2^31, 2^32-1] would truncate to a negative int.  Java containers/arrays cannot exceed int range.
 		if (rawLength > Integer.MAX_VALUE)
-			throw new ParseException(this, "MessagePack length {0} exceeds the maximum supported size of {1}.", rawLength, Integer.MAX_VALUE);
+			throw new ParseException(this, "MessagePack length %s exceeds the maximum supported size of %s.", rawLength, Integer.MAX_VALUE);
 		int length = (int)rawLength;
 
 		if (dt != DataType.NULL) {
@@ -275,7 +275,7 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 					}
 					o = builder == null ? m.getBean() : builder.build(this, m.getBean(), eType);
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (sType.isMap()) {
 				if (dt == MAP) {
@@ -289,7 +289,7 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 					}
 					o = m;
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (sType.isBoolean() || sType.isCharSequence() || sType.isChar() || sType.isNumber() || sType.isByteArray()) {
 				// Merged scalar tier: one wire-type (BOOLEAN/INT/LONG/FLOAT/DOUBLE/STRING/BIN) covers
@@ -319,7 +319,7 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 						l.add(parseAnything(sType.getElementType(), is, l, pMeta));
 					o = l;
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (sType.isArray() || sType.isArgs()) {
 				if (dt == MAP) {
@@ -333,7 +333,7 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 						l.add(parseAnything(sType.isArgs() ? sType.getArg(i) : sType.getElementType(), is, l, pMeta));
 					o = toArray(sType, l);
 				} else {
-					throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+					throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 				}
 			} else if (dt == MAP) {
 				var m = newGenericMap();
@@ -344,9 +344,9 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 				else if (nn(sType.getProxyInvocationHandler()))
 					o = newBeanMap(outer, sType.inner()).load(m).getBean();
 				else
-					throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+					throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 			} else {
-				throw new ParseException(this, "Invalid data type {0} encountered for parse type {1}", dt, sType);
+				throw new ParseException(this, "Invalid data type %s encountered for parse type %s", dt, sType);
 			}
 		}
 
@@ -365,4 +365,4 @@ public class MsgPackParserSession extends InputStreamParserSession implements To
 			return parseAnything(type, is, getOuter(), null);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackTokenReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackTokenReader.java
index ea78ae019b..2186be5fa3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackTokenReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/msgpack/MsgPackTokenReader.java
@@ -229,7 +229,7 @@ public class MsgPackTokenReader implements TokenReader {
 				currentToken = TokenType.VALUE_BINARY;
 				consumedOneElement();
 			}
-			default -> throw new ParseException("Unexpected MsgPack data type: {0}", dt);
+			default -> throw new ParseException("Unexpected MsgPack data type: %s", dt);
 		}
 		return currentToken;
 	}
@@ -247,7 +247,7 @@ public class MsgPackTokenReader implements TokenReader {
 			case FLOAT:     return Float.toString(is.readFloat());
 			case DOUBLE:    return Double.toString(is.readDouble());
 			default:
-				throw new ParseException("Cannot use MsgPack data type {0} as a map key", dt);
+				throw new ParseException("Cannot use MsgPack data type %s as a map key", dt);
 		}
 	}
 
@@ -362,7 +362,7 @@ public class MsgPackTokenReader implements TokenReader {
 		} catch (Exception e) {
 			if (e instanceof IOException ioe) throw ioe;
 			if (e instanceof ParseException pe) throw pe;
-			throw new ParseException(s, "read failed: {0}", e.getMessage());
+			throw new ParseException(s, "read failed: %s", e.getMessage());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/oapi/OpenApiParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/oapi/OpenApiParserSession.java
index ec409dabfa..03010dbd09 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/oapi/OpenApiParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/oapi/OpenApiParserSession.java
@@ -300,7 +300,7 @@ public class OpenApiParserSession extends UonParserSession {
 					type = (ClassMeta<T>)CM_JsonMap;
 
 				if (! type.isMapOrBean())
-					throw new ParseException("Invalid type {0} for part type OBJECT.", type);
+					throw new ParseException("Invalid type %s for part type OBJECT.", type);
 
 				var ss = new String[] {};
 
@@ -327,12 +327,12 @@ public class OpenApiParserSession extends UonParserSession {
 					for (var s : ss) {
 						var kv = StringUtils.splita(s, '=', 2);
 						if (kv.length != 2)
-							throw new ParseException("Invalid input {0} for part type OBJECT.", in);
+							throw new ParseException("Invalid input %s for part type OBJECT.", in);
 						var key = kv[0];
 						var value = kv[1];
 						var bpm = m.getPropertyMeta(key);
 						if (bpm == null && ! isIgnoreUnknownBeanProperties())
-							throw new ParseException("Invalid input {0} for part type OBJECT.  Cannot find property {1}", in, key);
+							throw new ParseException("Invalid input %s for part type OBJECT.  Cannot find property %s", in, key);
 						m.put(key, parse(partType, schema.getProperty(key), value, ((ClassMeta<T>)(bpm == null ? object() : bpm.getBeanInfo()))));
 					}
 					return m.getBean();
@@ -352,7 +352,7 @@ public class OpenApiParserSession extends UonParserSession {
 					for (var s : ss) {
 						var kv = StringUtils.splita(s, '=', 2);
 						if (kv.length != 2)
-							throw new ParseException("Invalid input {0} for part type OBJECT.", in);
+							throw new ParseException("Invalid input %s for part type OBJECT.", in);
 						var key = kv[0];
 						var value = kv[1];
 						m.put(key, parse(partType, schema.getProperty(key), value, eType));
@@ -386,4 +386,4 @@ public class OpenApiParserSession extends UonParserSession {
 	protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws IOException, ParseException, ExecutableException {
 		return parseInner(null, HttpPartSchema.DEFAULT, pipe.asString(), type);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/NumberMatcherFactory.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/NumberMatcherFactory.java
index 400c306050..0c195323c8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/NumberMatcherFactory.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/NumberMatcherFactory.java
@@ -230,12 +230,12 @@ public class NumberMatcherFactory extends MatcherFactory {
 			}
 
 			if (i != s.length())
-				throw new PatternException("Invalid range pattern ({0}): {1}", state, s);
+				throw new PatternException("Invalid range pattern (%s): %s", state, s);
 
 			if (state == S1) {
 				// No tokens found.
 			} else if (state == S2 || state == S3 || state == S4 || state == S8 || state == S9) {
-				throw new PatternException("Invalid range pattern (E{0}): {1}", state, s);
+				throw new PatternException("Invalid range pattern (E%s): %s", state, s);
 			} else if (state == S6) {
 				n1 = Integer.parseInt(s.substring(mark).trim());
 				l.add(new NumberRange(eq, n1, isNot));
@@ -337,4 +337,4 @@ public class NumberMatcherFactory extends MatcherFactory {
 	public AbstractMatcher create(String pattern) {
 		return new NumberMatcher(pattern);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
index a9f85adc76..f34bb958ca 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/PathTraversal.java
@@ -202,7 +202,7 @@ public class PathTraversal {
 		try {
 			return Integer.parseInt(key);
 		} catch (@SuppressWarnings("unused") NumberFormatException e) {
-			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot address an item in an array with a non-integer key ''{0}''", key);
+			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot address an item in an array with a non-integer key '%s'", key);
 		}
 	}
 
@@ -796,9 +796,9 @@ public class PathTraversal {
 			}
 			var n = (parentUrl == null ? root : getNode(parentUrl, root));
 			if (n == null)
-				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL ''{0}'' not found.", parentUrl);
+				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL '%s' not found.", parentUrl);
 			if (n.o == null && n.cm.isObject())
-				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL ''{0}'' not found.", parentUrl);
+				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL '%s' not found.", parentUrl);
 			var cm = n.cm;
 			var o = n.o;
 			if (cm.isMap())
@@ -806,7 +806,7 @@ public class PathTraversal {
 			if (cm.isCollection() && o instanceof List o2)
 				return o2.set(parseInt(childKey), convert(val, cm.getElementType()));
 			if (cm.isCollection())
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot PUT to indexed position in non-List collection ''{0}'' of type ''{1}''", url, cm);
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot PUT to indexed position in non-List collection '%s' of type '%s'", url, cm);
 			if (cm.isArray()) {
 				o = setArrayEntry(n.o, parseInt(childKey), val, cm.getElementType());
 				var pct = n.parent.cm;
@@ -820,11 +820,11 @@ public class PathTraversal {
 					m.put(n.keyName, o);
 					return url;
 				}
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform PUT on ''{0}'' with parent node type ''{1}''", url, pct);
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform PUT on '%s' with parent node type '%s'", url, pct);
 			}
 			if (cm.isBean())
 				return session.toBeanMap(o).put(childKey, val);
-			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform PUT on ''{0}'' whose parent is of type ''{1}''", url, cm);
+			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform PUT on '%s' whose parent is of type '%s'", url, cm);
 		}
 
 		if (method == POST) {
@@ -842,13 +842,13 @@ public class PathTraversal {
 					root = new JsonNode(null, null, o2, null);
 					return url + "/" + (o2.length - 1);
 				}
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on ''{0}'' of type ''{1}''", url, cm);
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on '%s' of type '%s'", url, cm);
 			}
 			var n = getNode(url, root);
 			if (n == null)
-				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL ''{0}'' not found.", url);
+				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL '%s' not found.", url);
 			if (n.o == null && n.cm.isObject())
-				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL ''{0}'' not found.", url);
+				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL '%s' not found.", url);
 			var cm = n.cm;
 			var o = n.o;
 			if (cm.isArray()) {
@@ -864,14 +864,14 @@ public class PathTraversal {
 					m.put(childKey, o2);
 					return url + "/" + (o2.length - 1);
 				}
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on ''{0}'' with parent node type ''{1}''", url, pct);
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on '%s' with parent node type '%s'", url, pct);
 			}
 			if (cm.isCollection()) {
 				var c = (Collection)o;
 				c.add(convert(val, cm.getElementType()));
 				return (c instanceof List c2 ? url + "/" + (c2.size() - 1) : null);
 			}
-			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on ''{0}'' of type ''{1}''", url, cm);
+			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on '%s' of type '%s'", url, cm);
 		}
 
 		if (method == DELETE) {
@@ -884,9 +884,9 @@ public class PathTraversal {
 			}
 			var n = (parentUrl == null ? root : getNode(parentUrl, root));
 			if (n == null)
-				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL ''{0}'' not found.", parentUrl);
+				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL '%s' not found.", parentUrl);
 			if (n.o == null && n.cm.isObject())
-				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL ''{0}'' not found.", parentUrl);
+				throw new PathTraversalException(HTTP_NOT_FOUND, "Node at URL '%s' not found.", parentUrl);
 			var cm = n.cm;
 			var o = n.o;
 			if (cm.isMap())
@@ -894,7 +894,7 @@ public class PathTraversal {
 			if (cm.isCollection() && o instanceof List o2)
 				return o2.remove(parseInt(childKey));
 			if (cm.isCollection())
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot DELETE indexed position in non-List collection ''{0}'' of type ''{1}''", url, cm);
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot DELETE indexed position in non-List collection '%s' of type '%s'", url, cm);
 			if (cm.isArray()) {
 				int index = parseInt(childKey);
 				var old = ((Object[])o)[index];
@@ -910,11 +910,11 @@ public class PathTraversal {
 					m.put(n.keyName, o2);
 					return old;
 				}
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on ''{0}'' with parent node type ''{1}''", url, pct);
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform POST on '%s' with parent node type '%s'", url, pct);
 			}
 			if (cm.isBean())
 				return session.toBeanMap(o).put(childKey, null);
-			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform PUT on ''{0}'' whose parent is of type ''{1}''", url, cm);
+			throw new PathTraversalException(HTTP_BAD_REQUEST, "Cannot perform PUT on '%s' whose parent is of type '%s'", url, cm);
 		}
 
 		return null;	// Never gets here.
@@ -978,7 +978,7 @@ public class PathTraversal {
 			o2 = m.get(parentKey);
 			var pMeta = m.getPropertyMeta(parentKey);
 			if (pMeta == null)
-				throw new PathTraversalException(HTTP_BAD_REQUEST, "Unknown property ''{0}'' encountered while trying to parse into class ''{1}''", parentKey, m.getBeanInfo());
+				throw new PathTraversalException(HTTP_BAD_REQUEST, "Unknown property '%s' encountered while trying to parse into class '%s'", parentKey, m.getBeanInfo());
 			ct2 = (ClassMeta) pMeta.getBeanInfo();
 		}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/SearchArgs.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/SearchArgs.java
index ff24e6248a..007a35d302 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/SearchArgs.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/SearchArgs.java
@@ -67,7 +67,7 @@ public class SearchArgs {
 		searchArgs.forEach(s -> {
 			var i = indexOf(s, '=', '>', '<');
 			if (i == -1)
-				throw new PatternException("Invalid search terms: ''{0}''", searchArgs);
+				throw new PatternException("Invalid search terms: '%s'", searchArgs);
 			var c = s.charAt(i);
 			append(s.substring(0, i).trim(), s.substring(c == '=' ? i + 1 : i).trim());
 		});
@@ -106,4 +106,4 @@ public class SearchArgs {
 	 * @return An unmodifiable map of query search terms.
 	 */
 	public Map<String,String> getSearch() { return search; }
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/TimeMatcherFactory.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/TimeMatcherFactory.java
index fec855b6b5..1fceb0795e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/TimeMatcherFactory.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/objecttools/TimeMatcherFactory.java
@@ -283,12 +283,12 @@ public class TimeMatcherFactory extends MatcherFactory {
 			}
 
 			if (i != s.length())
-				throw new PatternException("Invalid range pattern ({0}): pattern=[{1}], pos=[{2}], char=[{3}]", state, s, i, c);
+				throw new PatternException("Invalid range pattern (%s): pattern=[%s], pos=[%s], char=[%s]", state, s, i, c);
 
 			if (state == S1) {
 				// No tokens found.
 			} else if (state == S2 || state == S3 || state == S4 || state == S5 || state == S6 || state == S10 || state == S11 || state == S12) {
-				throw new PatternException("Invalid range pattern (E{0}): {1}", state, s);
+				throw new PatternException("Invalid range pattern (E%s): %s", state, s);
 			} else if (state == S7) {
 				l.add(new TimestampRange(eq, s1));
 			} else if (state == S8) {
@@ -381,4 +381,4 @@ public class TimeMatcherFactory extends MatcherFactory {
 	public AbstractMatcher create(String pattern) {
 		return new TimeMatcher(pattern);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
index b7a95faee9..dec8795a12 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
@@ -201,7 +201,7 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 		var footer = Arrays.copyOfRange(bytes, footerStart, bytes.length - 8);
 		var meta = parseFileMetaData(footer);
 		if (meta.numRows() < 0 || meta.numRows() > MAX_NUM_ROWS)
-			throw new ParseException("Invalid numRows: {0}", meta.numRows());
+			throw new ParseException("Invalid numRows: %s", meta.numRows());
 		ClassMeta<?> effectiveType = type;
 		if (type.isOptional())
 			effectiveType = type.getElementType();
@@ -407,10 +407,10 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 		if (uncompressedSize < 0 || uncompressedSize > MAX_PAGE_SIZE
 			|| compressedSize < 0 || compressedSize > MAX_PAGE_SIZE
 			|| bodyStart + compressedSize > fileBytes.length)
-			throw new ParseException("Invalid page header for column ''{0}'': uncompressed=''{1}'', compressed=''{2}''",
+			throw new ParseException("Invalid page header for column '%s': uncompressed='%s', compressed='%s'",
 				columnPath, uncompressedSize, compressedSize);
 		if (numValues < 0 || numValues > MAX_NUM_VALUES)
-			throw new ParseException("Invalid page num_values for column ''{0}'': {1}", columnPath, numValues);
+			throw new ParseException("Invalid page num_values for column '%s': %s", columnPath, numValues);
 		return new PageHeaderInfo(pageType, uncompressedSize, compressedSize, numValues, encoding, bodyStart);
 	}
 
@@ -757,7 +757,7 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 			int repBitWidth = 32 - Integer.numberOfLeadingZeros(maxRep);
 
 			if (cc.numValues() < 0 || cc.numValues() > MAX_NUM_VALUES)
-				throw new ParseException("Invalid numValues for column ''{0}'': {1}", String.join(".", cc.pathInSchema()), cc.numValues());
+				throw new ParseException("Invalid numValues for column '%s': %s", String.join(".", cc.pathInSchema()), cc.numValues());
 			var codec = CompressionCodec.fromThrift(cc.codec());
 			// Skip a leading dictionary page if present, then read the single data page.  Repeated
 			// (list/map) columns carry rep+def levels with cross-page state; Juneau emits them as a single
@@ -917,7 +917,7 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 			int repBitWidth = 32 - Integer.numberOfLeadingZeros(maxRep);
 
 			if (cc.numValues() < 0 || cc.numValues() > MAX_NUM_VALUES)
-				throw new ParseException("Invalid numValues for column ''{0}'': {1}", String.join(".", cc.pathInSchema()), cc.numValues());
+				throw new ParseException("Invalid numValues for column '%s': %s", String.join(".", cc.pathInSchema()), cc.numValues());
 			var codec = CompressionCodec.fromThrift(cc.codec());
 			// Skip a leading dictionary page if present, then read the single data page.  Repeated
 			// (list/map) columns carry rep+def levels with cross-page state; Juneau emits them as a single
@@ -996,7 +996,7 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 	private static List<Object> readColumnChunk(byte[] fileBytes, ColumnChunkMeta cc, int numRows, Map<String, Integer> schemaRepetition, Set<String> rawByteArrayPaths, Set<String> uuidPaths, Map<String, ColumnLogical> columnLogical, boolean trimStrings) throws ParseException {
 		try {
 			if (cc.numValues() < 0 || cc.numValues() > MAX_NUM_VALUES)
-				throw new ParseException("Invalid numValues for column ''{0}'': {1}", String.join(".", cc.pathInSchema()), cc.numValues());
+				throw new ParseException("Invalid numValues for column '%s': %s", String.join(".", cc.pathInSchema()), cc.numValues());
 			var codec = CompressionCodec.fromThrift(cc.codec());
 			var path = String.join(".", cc.pathInSchema());
 			int rep = schemaRepetition.getOrDefault(path, OPTIONAL);
@@ -1027,7 +1027,7 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 			int pageGuard = 0;
 			while (consumed < valuesToRead && pageOff < fileBytes.length) {
 				if (++pageGuard > MAX_PAGES_PER_CHUNK)
-					throw new ParseException("Column ''{0}'' exceeds the maximum of {1} pages per chunk", path, MAX_PAGES_PER_CHUNK);
+					throw new ParseException("Column '%s' exceeds the maximum of %s pages per chunk", path, MAX_PAGES_PER_CHUNK);
 				var ph = readPageHeader(fileBytes, pageOff, path);
 				var compressedData = Arrays.copyOfRange(fileBytes, ph.bodyStart(), ph.bodyStart() + ph.compressedSize());
 				var decompressed = codec.decompress(compressedData, ph.uncompressedSize());
@@ -1130,7 +1130,7 @@ public class ParquetParserSession extends InputStreamParserSession implements Re
 				} else {
 					int idx = idxDecoder.readInt();
 					if (idx >= dictionary.size())
-						throw new ParseException("Dictionary index {0} out of range [0,{1})", idx, dictionary.size());
+						throw new ParseException("Dictionary index %s out of range [0,%s)", idx, dictionary.size());
 					values.add(dictionary.get(idx));
 				}
 			}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSchemaBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSchemaBuilder.java
index d212acc955..d872c221c6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSchemaBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSchemaBuilder.java
@@ -204,7 +204,7 @@ public final class ParquetSchemaBuilder {
 	private void addBeanSchema(List<ParquetSchemaElement> elements, ClassMeta<?> cm, String name, String parentPath, boolean isRoot, Object sampleBean, Map<Class<?>, Integer> typesInProgress) {
 		var bm = cm.getBeanMeta();
 		if (bm == null) // HTT: addBeanSchema is only called after isBean() check; getBeanMeta() is non-null
-			throw iaex("Class ''{0}'' is not a bean", cm.getName());
+			throw iaex("Class '%s' is not a bean", cm.getName());
 		var beanClass = cm.inner();
 		// Recursion reached here indirectly (e.g. through Optional/collection of the same type) at the depth
 		// limit: keep the legacy String back-reference placeholder so the enclosing group's child count stays
@@ -213,7 +213,7 @@ public final class ParquetSchemaBuilder {
 		if (typesInProgress.getOrDefault(beanClass, 0) >= maxRecursionDepth) {
 			if (cycleHandling == ParquetCycleHandling.THROW) {
 				var path = parentPath != null ? parentPath + "." + name : name; // HTT: parentPath is always non-null when recursion limit is reached at depth ≥ 2
-				throw new SerializeException("Cyclic type reference at ''{0}'' (type ''{1}''). Use @ParentProperty to exclude back-references or set cycleHandling(NULL).", path, beanClass.getName());
+				throw new SerializeException("Cyclic type reference at '%s' (type '%s'). Use @ParentProperty to exclude back-references or set cycleHandling(NULL).", path, beanClass.getName());
 			}
 			addLeafSchema(elements, marshallingContext.getClassMeta(String.class), name, parentPath, isRoot);
 			return;
@@ -255,7 +255,7 @@ public final class ParquetSchemaBuilder {
 					propCm = marshallingContext.getClassMeta(childSample.getClass());
 				if (propCm != null && propCm.isBean() && typesInProgress.getOrDefault(propCm.inner(), 0) >= maxRecursionDepth) { // HTT: propCm is non-null
 					if (cycleHandling == ParquetCycleHandling.THROW)
-						throw new SerializeException("Cyclic type reference at ''{0}.{1}'' (type ''{2}''). Use @ParentProperty to exclude back-references or set cycleHandling(NULL).", childParentPath, p.getName(), propCm.inner().getName());
+						throw new SerializeException("Cyclic type reference at '%s.%s' (type '%s'). Use @ParentProperty to exclude back-references or set cycleHandling(NULL).", childParentPath, p.getName(), propCm.inner().getName());
 					continue;
 				}
 				entries.add(new ResolvedProp(p.getName(), propCm, childSample));
@@ -312,7 +312,7 @@ public final class ParquetSchemaBuilder {
 	private void addListSchema(List<ParquetSchemaElement> elements, ClassMeta<?> cm, String name, String parentPath, boolean isRoot, Object sampleBean, Map<Class<?>, Integer> typesInProgress) {
 		var et = cm.getElementType();
 		if (et == null) // HTT: ClassMeta always provides an element type (at least Object) for list types
-			throw iaex("List element type cannot be determined for ''{0}''", cm.getName());
+			throw iaex("List element type cannot be determined for '%s'", cm.getName());
 		// Resolve element type from sample when generics are erased (et is Object) for proper list-of-bean
 		// expansion into leaf columns (e.g. members.list.element.name, members.list.element.age)
 		var sampleCollection = extractSampleCollection(sampleBean);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSerializerSession.java
index bfaa630531..7785a7d2b3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetSerializerSession.java
@@ -650,7 +650,7 @@ public class ParquetSerializerSession extends OutputStreamSerializerSession impl
 	private void flattenListValues(Object obj, String path, int partIndex, boolean firstInRow, int currentRep, int listDepth, int maxDef, List<FlattenedEntry> out, Set<Object> seen) throws SerializeException {
 		if (obj != null && seen.contains(obj)) {
 			if (ctx.cycleHandling == ParquetCycleHandling.THROW)
-				throw new SerializeException("Cyclic reference at path ''{0}''. Set cycleHandling(NULL) to serialize as null.", path);
+				throw new SerializeException("Cyclic reference at path '%s'. Set cycleHandling(NULL) to serialize as null.", path);
 			out.add(new FlattenedEntry(null, Math.max(0, maxDef - 1), currentRep));
 			return;
 		}
@@ -773,7 +773,7 @@ public class ParquetSerializerSession extends OutputStreamSerializerSession impl
 
 	private Object handleCycle(String path) throws SerializeException {
 		if (ctx.cycleHandling == ParquetCycleHandling.THROW)
-			throw new SerializeException("Cyclic reference at path ''{0}''. Set cycleHandling(NULL) to serialize as null.", path);
+			throw new SerializeException("Cyclic reference at path '%s'. Set cycleHandling(NULL) to serialize as null.", path);
 		return null;
 	}
 
@@ -824,7 +824,7 @@ public class ParquetSerializerSession extends OutputStreamSerializerSession impl
 				w.writeFixedLenByteArray(toFixedLenByteArray(v));
 				break;
 			default:
-				throw new SerializeException("Unsupported Parquet physical type: {0}", col.type);
+				throw new SerializeException("Unsupported Parquet physical type: %s", col.type);
 		}
 	}
 
@@ -928,7 +928,7 @@ public class ParquetSerializerSession extends OutputStreamSerializerSession impl
 		try {
 			return Instant.parse(String.valueOf(v));
 		} catch (@SuppressWarnings("unused") Exception e) {
-			throw new SerializeException("Cannot convert value of type {0} to a TIMESTAMP", v.getClass().getName());
+			throw new SerializeException("Cannot convert value of type %s to a TIMESTAMP", v.getClass().getName());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserPipe.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserPipe.java
index 69252af4a7..f9808d291f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserPipe.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserPipe.java
@@ -240,7 +240,7 @@ public class ParserPipe implements Closeable {
 				doClose = true;
 			}
 		} else {
-			throw ioex("Cannot convert object of type {0} to an InputStream.", cn(input));
+			throw ioex("Cannot convert object of type %s to an InputStream.", cn(input));
 		}
 
 		return inputStream;
@@ -318,7 +318,7 @@ public class ParserPipe implements Closeable {
 			}
 			doClose = true;
 		} else {
-			throw ioex("Cannot convert object of type {0} to an InputStream.", cn(input));
+			throw ioex("Cannot convert object of type %s to an InputStream.", cn(input));
 		}
 
 		return reader;
@@ -353,4 +353,4 @@ public class ParserPipe implements Closeable {
 			return Position.UNKNOWN;
 		return p;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSession.java
index 85b1049662..5324ab611f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSession.java
@@ -659,9 +659,9 @@ public class ParserSession extends MarshallingSession {
 		} catch (@SuppressWarnings("unused") StackOverflowError e) {
 			throw new ParseException(this, "Depth too deep.  Stack overflow occurred.");
 		} catch (IOException e) {
-			throw new ParseException(this, e, "I/O exception occurred.  exception={0}, message={1}.", cns(e), localizedMessage(e));
+			throw new ParseException(this, e, "I/O exception occurred.  exception=%s, message=%s.", cns(e), localizedMessage(e));
 		} catch (Exception e) {
-			throw new ParseException(this, e, "Exception occurred.  exception={0}, message={1}.", cns(e), localizedMessage(e));
+			throw new ParseException(this, e, "Exception occurred.  exception=%s, message=%s.", cns(e), localizedMessage(e));
 		} finally {
 			checkForWarnings();
 		}
@@ -694,9 +694,9 @@ public class ParserSession extends MarshallingSession {
 		} catch (@SuppressWarnings("unused") StackOverflowError e) {
 			throw new ParseException(this, "Depth too deep.  Stack overflow occurred.");
 		} catch (IOException e) {
-			throw new ParseException(this, e, "I/O exception occurred.  exception={0}, message={1}.", cns(e), localizedMessage(e));
+			throw new ParseException(this, e, "I/O exception occurred.  exception=%s, message=%s.", cns(e), localizedMessage(e));
 		} catch (Exception e) {
-			throw new ParseException(this, e, "Exception occurred.  exception={0}, message={1}.", cns(e), localizedMessage(e));
+			throw new ParseException(this, e, "Exception occurred.  exception=%s, message=%s.", cns(e), localizedMessage(e));
 		} finally {
 			checkForWarnings();
 		}
@@ -770,7 +770,7 @@ public class ParserSession extends MarshallingSession {
 		} catch (@SuppressWarnings("unused") StackOverflowError e) {
 			throw new ParseException(this, "Depth too deep.  Stack overflow occurred.");
 		} catch (Exception e) {
-			throw new ParseException(this, e, "Exception occurred.  exception={0}, message={1}.", cns(e), localizedMessage(e));
+			throw new ParseException(this, e, "Exception occurred.  exception=%s, message=%s.", cns(e), localizedMessage(e));
 		} finally {
 			checkForWarnings();
 		}
@@ -839,10 +839,10 @@ public class ParserSession extends MarshallingSession {
 				throw e;
 			if (bodyThrown instanceof IOException e)
 				throw e;
-			throw new ParseException(this, bodyThrown, "Exception occurred.  exception={0}, message={1}.", cns(bodyThrown), localizedMessage(bodyThrown));
+			throw new ParseException(this, bodyThrown, "Exception occurred.  exception=%s, message=%s.", cns(bodyThrown), localizedMessage(bodyThrown));
 		}
 		if (completeThrown != null)
-			throw new ParseException(this, completeThrown, "Exception occurred in BeanConsumer.complete().  exception={0}, message={1}.", cns(completeThrown), localizedMessage(completeThrown));
+			throw new ParseException(this, completeThrown, "Exception occurred in BeanConsumer.complete().  exception=%s, message=%s.", cns(completeThrown), localizedMessage(completeThrown));
 	}
 
 	private static <T> Exception drainToConsumer(BeanConsumer<T> consumer, List<T> list) {
@@ -957,7 +957,7 @@ public class ParserSession extends MarshallingSession {
 			if (sType.canCreateNewInstanceFromString(outer))
 				o = sType.newInstanceFromString(outer, s);
 			else
-				throw new ParseException(this, "Invalid conversion from string to class ''{0}''", type);
+				throw new ParseException(this, "Invalid conversion from string to class '%s'", type);
 		}
 
 		if (nn(swap))
@@ -1041,7 +1041,7 @@ public class ParserSession extends MarshallingSession {
 		"java:S112" // throws Exception intentional - callback/lifecycle method
 	})
 	protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, Collection<E> c, Type elementType) throws Exception {
-		throw uoex("Parser ''{0}'' does not support this method.", cn(getClass()));
+		throw uoex("Parser '%s' does not support this method.", cn(getClass()));
 	}
 
 	/**
@@ -1063,7 +1063,7 @@ public class ParserSession extends MarshallingSession {
 		"java:S112" // throws Exception intentional - callback/lifecycle method
 	})
 	protected <K,V> Map<K,V> doParseIntoMap(ParserPipe pipe, Map<K,V> m, Type keyType, Type valueType) throws Exception {
-		throw uoex("Parser ''{0}'' does not support this method.", cn(getClass()));
+		throw uoex("Parser '%s' does not support this method.", cn(getClass()));
 	}
 
 	/**
@@ -1329,7 +1329,7 @@ public class ParserSession extends MarshallingSession {
 		if (nn(listener))
 			listener.onBeanSetterException(this, t, p);
 		var prefix = "";
-		addWarning("{0}Could not call setValue() on property ''{1}'' of class ''{2}'', exception = {3}", prefix, p.getName(), p.getBeanMeta().getBeanInfo(), localizedMessage(t));
+		addWarning("%sCould not call setValue() on property '%s' of class '%s', exception = %s", prefix, p.getName(), p.getBeanMeta().getBeanInfo(), localizedMessage(t));
 	}
 
 	/**
@@ -1348,7 +1348,7 @@ public class ParserSession extends MarshallingSession {
 		if (propertyName.equals(getBeanTypePropertyName(bmcm)))
 			return;
 		if (! isIgnoreUnknownBeanProperties() && (nn(value) || ! isIgnoreUnknownNullBeanProperties()))
-			throw new ParseException(this, "Unknown property ''{0}'' encountered while trying to parse into class ''{1}''", propertyName, bmcm);
+			throw new ParseException(this, "Unknown property '%s' encountered while trying to parse into class '%s'", propertyName, bmcm);
 		if (nn(listener))
 			listener.onUnknownBeanProperty(this, propertyName, bmcm.inner(), beanMap.getBean());
 	}
@@ -1451,4 +1451,4 @@ public class ParserSession extends MarshallingSession {
 			throw new ParseException(e);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSet.java
index 98daa7618b..59fbcf24a9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parser/ParserSet.java
@@ -204,7 +204,7 @@ public class ParserSet {
 				if (Parser.class.isAssignableFrom(v)) {
 					l.add(createBuilder(v));
 				} else if (! v.getSimpleName().equals(CLASS_NoInherit)) {
-					throw rex("Invalid type passed to ParserSet.Builder.add(): {0}", cn(v));
+					throw rex("Invalid type passed to ParserSet.Builder.add(): %s", cn(v));
 				}
 			}
 			entries.addAll(0, l);
@@ -407,7 +407,7 @@ public class ParserSet {
 				} else if (Parser.class.isAssignableFrom(v)) {
 					l.add(createBuilder(v));
 				} else {
-					throw rex("Invalid type passed to ParserGrouup.Builder.set(): {0}", cn(v));
+					throw rex("Invalid type passed to ParserGrouup.Builder.set(): %s", cn(v));
 				}
 			}
 			entries = l;
@@ -428,7 +428,7 @@ public class ParserSet {
 			if (o instanceof Parser.Builder<?> x) {
 				Parser.Builder<?> x2 = x.copy();
 				if (neq(x.getClass(), x2.getClass()))
-					throw rex("Copy method not implemented on class {0}", cn(x));
+					throw rex("Copy method not implemented on class %s", cn(x));
 				x = x2;
 				if (nn(bcBuilder))
 					x.marshallingContext(bcBuilder);
@@ -643,4 +643,4 @@ public class ParserSet {
 			return o2;
 		return ((Parser.Builder<?>)o).build();
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufParserSession.java
index 385fb55a4c..690779f5e3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufParserSession.java
@@ -103,7 +103,7 @@ public class ProtobufParserSession extends InputStreamParserSession {
 	protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws IOException, ParseException, ExecutableException {
 		var is = new ProtobufReader(pipe.getInputStream());
 		if (! type.isBean())
-			throw new ParseException(this, "Protobuf binary parsing requires a bean target type, but got ''{0}''", cn(type.inner()));
+			throw new ParseException(this, "Protobuf binary parsing requires a bean target type, but got '%s'", cn(type.inner()));
 		return (T)parseMessage(type, is, getOuter());
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufReader.java
index 2f3beb0390..daf0c45638 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/ProtobufReader.java
@@ -221,7 +221,7 @@ public class ProtobufReader {
 		while (off < len) {
 			var r = is.read(b, off, len - off);
 			if (r == -1)
-				throw ioex("Expected to read {0} bytes but stream ended at {1}", len, off);
+				throw ioex("Expected to read %s bytes but stream ended at %s", len, off);
 			off += r;
 		}
 		return b;
@@ -249,7 +249,7 @@ public class ProtobufReader {
 			case I64 -> skip(8);
 			case I32 -> skip(4);
 			case LEN -> skip((int)readVarint());
-			default -> throw ioex("Cannot skip unsupported protobuf wire type: {0}", wireType);
+			default -> throw ioex("Cannot skip unsupported protobuf wire type: %s", wireType);
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/WireType.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/WireType.java
index b7de2709f1..c2834f77dc 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/WireType.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/protobuf/WireType.java
@@ -81,7 +81,7 @@ public enum WireType {
 			case 3: return SGROUP;
 			case 4: return EGROUP;
 			case 5: return I32;
-			default: throw iaex("Invalid protobuf wire type: {0}", code);
+			default: throw iaex("Invalid protobuf wire type: %s", code);
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/prototext/PrototextParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/prototext/PrototextParserSession.java
index e5f154833f..fcbcc6ba7f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/prototext/PrototextParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/prototext/PrototextParserSession.java
@@ -315,7 +315,7 @@ public class PrototextParserSession extends ReaderParserSession implements Recor
 			if (pMeta == null && isIgnoreUnknownBeanProperties())
 				continue;
 			if (pMeta == null)
-				throw new ParseException(this, "Unknown property ''{0}''", key);
+				throw new ParseException(this, "Unknown property '%s'", key);
 			var targetType = (ClassMeta<?>) pMeta.getBeanInfo();
 			var converted = convertValue(val, targetType);
 			bm.put(key, converted);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializeException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializeException.java
index ae3bd40073..1956665bca 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializeException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializeException.java
@@ -23,7 +23,7 @@ import java.text.*;
 import java.util.*;
 
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * General exception thrown whenever an error occurs during serialization.
@@ -66,7 +66,7 @@ public class SerializeException extends BasicRuntimeException {
 		if (nn(session)) {
 			Map<String,Object> m = session.getLastLocation();
 			if (nn(m) && ! m.isEmpty())
-				msg = "Serialize exception occurred at " + Json5Serializer.DEFAULT.toString(m) + ".  " + msg;
+				msg = "Serialize exception occurred at " + Json5.of(m) + ".  " + msg;
 		}
 		return msg;
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerPipe.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerPipe.java
index a067146cfc..fc2cf4da49 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerPipe.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerPipe.java
@@ -129,7 +129,7 @@ public class SerializerPipe implements Closeable {
 		else if (output instanceof File output2)
 			outputStream = new BufferedOutputStream(new FileOutputStream(output2));
 		else
-			throw ioex("Cannot convert object of type {0} to an OutputStream.", cn(output));
+			throw ioex("Cannot convert object of type %s to an OutputStream.", cn(output));
 
 		return new NoCloseOutputStream(outputStream);
 	}
@@ -204,4 +204,4 @@ public class SerializerPipe implements Closeable {
 	 * @param writer The wrapped writer.
 	 */
 	public void setWriter(Writer writer) { this.writer = writer; }
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSession.java
index 93834262f8..90328db7d7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSession.java
@@ -1526,9 +1526,9 @@ public class SerializerSession extends MarshallingTraverseSession {
 		if (nn(listener))
 			listener.onBeanGetterException(this, t, p);
 		String prefix = (isDebug() ? getStack(false) + ": " : "");
-		addWarning("{0}Could not call getValue() on property ''{1}'' of class ''{2}'', exception = {3}", prefix, p.getName(), p.getBeanMeta().getBeanInfo(), localizedMessage(t));
+		addWarning("%sCould not call getValue() on property '%s' of class '%s', exception = %s", prefix, p.getName(), p.getBeanMeta().getBeanInfo(), localizedMessage(t));
 		if (! isIgnoreInvocationExceptionsOnGetters())
-			throw new SerializeException(this, "{0}Could not call getValue() on property ''{1}'' of class ''{2}'', exception = {3}", prefix, p.getName(), p.getBeanMeta().getBeanInfo(), localizedMessage(t))
+			throw new SerializeException(this, "%sCould not call getValue() on property '%s' of class '%s', exception = %s", prefix, p.getName(), p.getBeanMeta().getBeanInfo(), localizedMessage(t))
 				.initCause(t);
 	}
 
@@ -1629,4 +1629,4 @@ public class SerializerSession extends MarshallingTraverseSession {
 			throw new SerializeException(e);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSet.java
index ca13e5c834..fa07665acb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerSet.java
@@ -200,7 +200,7 @@ public class SerializerSet {
 				if (Serializer.class.isAssignableFrom(e)) {
 					l.add(createBuilder(e));
 				} else {
-					throw rex("Invalid type passed to SerializeGroup.Builder.add(): {0}", cn(e));
+					throw rex("Invalid type passed to SerializeGroup.Builder.add(): %s", cn(e));
 				}
 			}
 			entries.addAll(0, l);
@@ -403,7 +403,7 @@ public class SerializerSet {
 				} else if (Serializer.class.isAssignableFrom(e)) {
 					l.add(createBuilder(e));
 				} else {
-					throw rex("Invalid type passed to SerializeGroup.Builder.set(): {0}", cn(e));
+					throw rex("Invalid type passed to SerializeGroup.Builder.set(): %s", cn(e));
 				}
 			}
 			entries = l;
@@ -424,7 +424,7 @@ public class SerializerSet {
 			if (o instanceof Serializer.Builder<?> x) {
 				Serializer.Builder<?> x2 = x.copy();
 				if (neq(x.getClass(), x2.getClass()))
-					throw rex("Copy method not implemented on class {0}", cn(x));
+					throw rex("Copy method not implemented on class %s", cn(x));
 				x = x2;
 				if (nn(bcBuilder))
 					x.marshallingContext(bcBuilder);
@@ -702,4 +702,4 @@ public class SerializerSet {
 			return o2;
 		return ((Serializer.Builder<?>)o).build();
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseParserSession.java
index 20e69fa7cf..b6b08081d9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseParserSession.java
@@ -117,6 +117,6 @@ public class SseParserSession extends ReaderParserSession implements RecordReada
 		}
 		if (List.class.isAssignableFrom(type.inner()))
 			return (T) events;
-		throw new ParseException(this, "SseParser cannot produce target type ''{0}''.", type);
+		throw new ParseException(this, "SseParser cannot produce target type '%s'.", type);
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseSerializerSession.java
index 0f39245589..e89417dde5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/sse/SseSerializerSession.java
@@ -121,7 +121,7 @@ public class SseSerializerSession extends WriterSerializerSession implements Rec
 			for (var item : arr)
 				writeIfEvent(w, item);
 		} else {
-			throw new SerializeException("SseSerializer cannot serialize objects of type ''{0}''.", cn(o));
+			throw new SerializeException("SseSerializer cannot serialize objects of type '%s'.", cn(o));
 		}
 	}
 
@@ -129,7 +129,7 @@ public class SseSerializerSession extends WriterSerializerSession implements Rec
 		if (item == null)
 			return;
 		if (!(item instanceof SseEvent e))
-			throw new SerializeException("SseSerializer encountered non-SseEvent element of type ''{0}''.", cn(item));
+			throw new SerializeException("SseSerializer encountered non-SseEvent element of type '%s'.", cn(item));
 		writeEvent(w, e);
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/stream/StreamingArrayRecord.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/stream/StreamingArrayRecord.java
index e910505d1c..394cfabed6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/stream/StreamingArrayRecord.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/stream/StreamingArrayRecord.java
@@ -68,7 +68,7 @@ public final class StreamingArrayRecord {
 	public static RecordReader reader(TokenReader cursor) throws IOException, ParseException {
 		var t = cursor.next();
 		if (t != TokenType.START_ARRAY)
-			throw new ParseException("Expected START_ARRAY at the root of arrayRecordReader input but got {0}", t);
+			throw new ParseException("Expected START_ARRAY at the root of arrayRecordReader input but got %s", t);
 		return new RecordReader() {
 			@Override public boolean canRead() throws IOException, ParseException {
 				return cursor.canRead();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/ObjectSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/ObjectSwap.java
index fe97a89a57..9bb70468b7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/ObjectSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/ObjectSwap.java
@@ -336,7 +336,7 @@ public abstract class ObjectSwap<T,S> {
 		"java:S112" // throws Exception intentional - callback/lifecycle method for user implementations
 	})
 	public S swap(MarshallingSession session, T o, String template) throws Exception {
-		throw new SerializeException("Swap method not implemented on ObjectSwap ''{0}''", cn(this));
+		throw new SerializeException("Swap method not implemented on ObjectSwap '%s'", cn(this));
 	}
 
 	@Override /* Overridden from Object */
@@ -387,7 +387,7 @@ public abstract class ObjectSwap<T,S> {
 		"java:S112" // throws Exception intentional - callback/lifecycle method for user implementations
 	})
 	public T unswap(MarshallingSession session, S f, ClassMeta<?> hint, String template) throws Exception {
-		throw new ParseException("Unswap method not implemented on ObjectSwap ''{0}''", cn(this));
+		throw new ParseException("Unswap method not implemented on ObjectSwap '%s'", cn(this));
 	}
 
 	/**
@@ -426,4 +426,4 @@ public abstract class ObjectSwap<T,S> {
 		this.template = template;
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/SurrogateSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/SurrogateSwap.java
index 33e8538f2e..2227acdb7f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/SurrogateSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/swap/SurrogateSwap.java
@@ -102,11 +102,11 @@ public class SurrogateSwap<T,F> extends ObjectSwap<T,F> {
 	})
 	public T unswap(MarshallingSession session, F f, ClassMeta<?> hint) throws ParseException {
 		if (unswapMethod == null)
-			throw new ParseException("unswap() method not implement on surrogate class ''{1}'': {0}", cn(f), getNormalClass().getNameFull());
+			throw new ParseException("unswap() method not implement on surrogate class '%2$s': %1$s", cn(f), getNormalClass().getNameFull());
 		try {
 			return (T)unswapMethod.invoke(f);
 		} catch (Exception e) {
 			throw new ParseException(e);
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/toml/TomlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/toml/TomlParserSession.java
index f95dd94fe4..cdcb9fb1b4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/toml/TomlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/toml/TomlParserSession.java
@@ -437,7 +437,7 @@ public class TomlParserSession extends ReaderParserSession implements RecordRead
 			if (pMeta == null && isIgnoreUnknownBeanProperties())
 				continue;
 			if (pMeta == null)
-				throw new ParseException(this, "Unknown property ''{0}''", key);
+				throw new ParseException(this, "Unknown property '%s'", key);
 			ClassMeta<?> targetType = (ClassMeta<?>) pMeta.getBeanInfo();
 			Object converted = convertValue(val, targetType);
 			bm.put(key, converted);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonParserSession.java
index 4ee507cfa1..372877351b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonParserSession.java
@@ -303,7 +303,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 		} else if (sType.isVoid()) {
 			var s = parseString(r, isUrlParamValue);
 			if (nn(s))
-				throw new ParseException(this, "Expected ''null'' for void value, but was ''{0}''.", s);
+				throw new ParseException(this, "Expected 'null' for void value, but was '%s'.", s);
 		} else if (sType.isObject()) {
 			if (c == '(') {
 				var m = newGenericMap();
@@ -403,7 +403,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 			else if (nn(sType.getProxyInvocationHandler()))
 				o = newBeanMap(outer, sType.inner()).load(m).getBean();
 			else
-				throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+				throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		} else if (c == 'n') {
 			@SuppressWarnings({
 				"unused" // Intentionally unused; variable/parameter is required by the interface contract
@@ -411,7 +411,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 			int ignored = r.read();
 			parseNull(r);
 		} else {
-			throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+			throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 		}
 
 		if (o == null && sType.isPrimitive())
@@ -436,7 +436,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 			return true;
 		if (eqic(s, "false"))
 			return false;
-		throw new ParseException(this, "Unrecognized syntax for boolean.  ''{0}''.", s);
+		throw new ParseException(this, "Unrecognized syntax for boolean.  '%s'.", s);
 	}
 
 	@SuppressWarnings({
@@ -731,7 +731,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 		var s = parseString(r, false);
 		if ("ull".equals(s))
 			return null;
-		throw new ParseException(this, "Unexpected character sequence: ''{0}''", s);
+		throw new ParseException(this, "Unexpected character sequence: '%s'", s);
 	}
 
 	private Number parseNumber(UonReader r, Class<? extends Number> c) throws IOException, ParseException {
@@ -778,7 +778,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 			if (c == -1)
 				return;
 			if (! Character.isWhitespace(c))
-				throw new ParseException(this, "Remainder after parse: ''{0}''.", (char)c);
+				throw new ParseException(this, "Remainder after parse: '%s'.", (char)c);
 		}
 	}
 
@@ -949,4 +949,4 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 			.a(PROP_decoding, decoding)
 			.a(PROP_validateEnd, validateEnd);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonReader.java
index 3c20ea4825..a3a60271ee 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonReader.java
@@ -52,7 +52,7 @@ public class UonReader extends ParserReader {
 			return 10 + c - 'a';
 		if (c >= 'A' && c <= 'F')
 			return 10 + c - 'A';
-		throw ioex("Invalid hex character ''{0}'' found in escape pattern.", c);
+		throw ioex("Invalid hex character '%s' found in escape pattern.", c);
 	}
 
 	private final boolean decodeChars;
@@ -136,7 +136,7 @@ public class UonReader extends ParserReader {
 
 				} else if (b0 < 192) {
 					// 10xxxxxx
-					throw ioex("Invalid hex value for first escape pattern in UTF-8 sequence: {0}", b0);
+					throw ioex("Invalid hex value for first escape pattern in UTF-8 sequence: %s", b0);
 
 				} else if (b0 < 224) {
 					// 110xxxxx	10xxxxxx
@@ -166,7 +166,7 @@ public class UonReader extends ParserReader {
 					}
 
 				} else
-					throw ioex("Invalid hex value for first escape pattern in UTF-8 sequence: {0}", b0);
+					throw ioex("Invalid hex value for first escape pattern in UTF-8 sequence: %s", b0);
 
 				if (cx < 0x10000)
 					cbuf[off + i++] = (char)cx;
@@ -212,4 +212,4 @@ public class UonReader extends ParserReader {
 		}
 		return n;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonWriter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonWriter.java
index f504aa4fdb..555e0073d3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonWriter.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/uon/UonWriter.java
@@ -294,7 +294,7 @@ public class UonWriter extends SerializerWriter {
 	 */
 	private UonWriter appendHex(int b) {
 		if (b > 255)
-			throw rex("Invalid value passed to appendHex.  Must be in the range 0-255.  Value={0}", b);
+			throw rex("Invalid value passed to appendHex.  Must be in the range 0-255.  Value=%s", b);
 		w('%').w(hexArray[b >>> 4]).w(hexArray[b & 0x0F]);
 		return this;
 	}
@@ -320,4 +320,4 @@ public class UonWriter extends SerializerWriter {
 		append(o.toString());
 		return this;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/urlencoding/UrlEncodingParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/urlencoding/UrlEncodingParserSession.java
index 84e7742691..f0f59b2136 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/urlencoding/UrlEncodingParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/urlencoding/UrlEncodingParserSession.java
@@ -214,8 +214,8 @@ public class UrlEncodingParserSession extends UonParserSession {
 				o = newBeanMap(outer, sType.inner()).load(m).getBean();
 			} else {
 				if (nn(sType.getNotABeanReason()))
-					throw new ParseException(this, "Class ''{0}'' could not be instantiated as application/x-www-form-urlencoded.  Reason: ''{1}''", sType, sType.getNotABeanReason());
-				throw new ParseException(this, "Malformed application/x-www-form-urlencoded input for class ''{0}''.", sType);
+					throw new ParseException(this, "Class '%s' could not be instantiated as application/x-www-form-urlencoded.  Reason: '%s'", sType, sType.getNotABeanReason());
+				throw new ParseException(this, "Malformed application/x-www-form-urlencoded input for class '%s'.", sType);
 			}
 		}
 
@@ -541,4 +541,4 @@ public class UrlEncodingParserSession extends UonParserSession {
 	 * <br><jk>true</jk> if serializing the same array results in <c>?key=1&amp;key=2&amp;key=3</c>.
 	 */
 	protected final boolean isExpandedParams() { return expandedParams; }
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/Namespace.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/Namespace.java
index 34ac83407c..bc850a20fd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/Namespace.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/Namespace.java
@@ -63,7 +63,7 @@ public class Namespace {
 			return o2;
 		if (o instanceof CharSequence o3)
 			return of(o3.toString());
-		throw rex("Invalid object type passed to Namespace.create(Object):  ''{0}''", cn(o));
+		throw rex("Invalid object type passed to Namespace.create(Object):  '%s'", cn(o));
 	}
 
 	/**
@@ -109,12 +109,12 @@ public class Namespace {
 				else if (o3 instanceof CharSequence o4)
 					n[i++] = create(o4.toString());
 				else
-					throw rex("Invalid type passed to NamespaceFactory.createArray: ''{0}''", cn(o));
+					throw rex("Invalid type passed to NamespaceFactory.createArray: '%s'", cn(o));
 			}
 			return n;
 		}
 
-		throw rex("Invalid type passed to NamespaceFactory.createArray: ''{0}''", cn(o));
+		throw rex("Invalid type passed to NamespaceFactory.createArray: '%s'", cn(o));
 	}
 
 	/**
@@ -190,4 +190,4 @@ public class Namespace {
 	public String toString() {
 		return key;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanMeta.java
index 7ac2766a36..a0f81c0b25 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanMeta.java
@@ -64,7 +64,7 @@ public class XmlBeanMeta extends ExtendedBeanMeta {
 					contentFormat = VOID;
 					defaultFormat.set(VOID);
 				} else
-					throw brex(c, "Invalid format specified in @Xml annotation on bean: {0}.  Must be one of the following: DEFAULT,ATTRS,ELEMENTS,VOID", x.format());
+					throw brex(c, "Invalid format specified in @Xml annotation on bean: %s.  Must be one of the following: DEFAULT,ATTRS,ELEMENTS,VOID", x.format());
 			});
 
 			beanMeta.getProperties().values().forEach(p -> {
@@ -89,11 +89,11 @@ public class XmlBeanMeta extends ExtendedBeanMeta {
 					attrsProperty = p;
 				} else if (xf.isOneOf(ELEMENTS, MIXED, MIXED_PWS, TEXT, TEXT_PWS, XMLTEXT)) {
 					if (xf.isOneOf(ELEMENTS, MIXED, MIXED_PWS) && ! pcm.isCollectionOrArray())
-						throw brex(c, "Invalid type for {0} property.  Only properties of type Collection and array can be used.", xf);
+						throw brex(c, "Invalid type for %s property.  Only properties of type Collection and array can be used.", xf);
 					if (nn(contentProperty)) {
 						if (xf == contentFormat)
-							throw brex(c, "Multiple instances of {0} properties defined on class.  Only one property can be designated as such.", xf);
-						throw brex(c, "{0} and {1} properties found on the same bean.  Only one property can be designated as such.", contentFormat, xf);
+							throw brex(c, "Multiple instances of %s properties defined on class.  Only one property can be designated as such.", xf);
+						throw brex(c, "%s and %s properties found on the same bean.  Only one property can be designated as such.", contentFormat, xf);
 					}
 					contentProperty = p;
 					contentFormat = xf;
@@ -102,7 +102,7 @@ public class XmlBeanMeta extends ExtendedBeanMeta {
 				String n = mp.getXmlBeanPropertyMeta(p).getChildName();
 				if (nn(n)) {
 					if (collapsedProperties.containsKey(n) && collapsedProperties.get(n) != p)
-						throw brex(c, "Multiple properties found with the child name ''{0}''.", n);
+						throw brex(c, "Multiple properties found with the child name '%s'.", n);
 					collapsedProperties.put(n, p);
 				}
 			});
@@ -143,9 +143,9 @@ public class XmlBeanMeta extends ExtendedBeanMeta {
 		// Do some validation.
 		if (nn(contentProperty) || contentFormat == XmlFormat.VOID) {
 			if (! elements.isEmpty())
-				throw brex(c, "{0} and ELEMENT properties found on the same bean.  These cannot be mixed.", contentFormat);
+				throw brex(c, "%s and ELEMENT properties found on the same bean.  These cannot be mixed.", contentFormat);
 			if (! collapsedProperties.isEmpty())
-				throw brex(c, "{0} and COLLAPSED properties found on the same bean.  These cannot be mixed.", contentFormat);
+				throw brex(c, "%s and COLLAPSED properties found on the same bean.  These cannot be mixed.", contentFormat);
 		}
 
 		if (! collapsedProperties.isEmpty() && ! Collections.disjoint(elements.keySet(), collapsedProperties.keySet()))
@@ -263,4 +263,4 @@ public class XmlBeanMeta extends ExtendedBeanMeta {
 		}
 		return getBeanMeta().getPropertyMeta(fieldName);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanPropertyMeta.java
index 3e25fc722a..2126ad8b2c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlBeanPropertyMeta.java
@@ -131,7 +131,7 @@ public class XmlBeanPropertyMeta extends ExtendedBeanPropertyMeta {
 
 		String cen = xml.childName();
 		if ((! cen.isEmpty()) && (! isCollection))
-			throw brex(cmProperty.inner(), "Annotation error on property ''{0}''.  @Xml.childName can only be specified on collections and arrays.", name);
+			throw brex(cmProperty.inner(), "Annotation error on property '%s'.  @Xml.childName can only be specified on collections and arrays.", name);
 
 		if (xmlFormat == XmlFormat.COLLAPSED) {
 			if (isCollection) {
@@ -142,7 +142,7 @@ public class XmlBeanPropertyMeta extends ExtendedBeanPropertyMeta {
 			if (ie(cen))
 				cen = name;
 			} else {
-				throw brex(cmBean.inner(), "Annotation error on property ''{0}''.  @Xml.format=COLLAPSED can only be specified on collections and arrays.", name);
+				throw brex(cmBean.inner(), "Annotation error on property '%s'.  @Xml.format=COLLAPSED can only be specified on collections and arrays.", name);
 			}
 			if (cen.isEmpty())
 				cen = cmProperty.getBeanDictionaryName();
@@ -151,4 +151,4 @@ public class XmlBeanPropertyMeta extends ExtendedBeanPropertyMeta {
 		if (! cen.isEmpty())
 			childName = cen;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlParserSession.java
index 05fa4e8951..9a857828c0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlParserSession.java
@@ -224,7 +224,7 @@ public class XmlParserSession extends ReaderParserSession implements RecordReada
 	private String getElementAsString(XmlReader r) {
 		int t = r.getEventType();
 		if (t > 2)
-			throw rex("Invalid event type on stream reader for elementToString() method: ''{0}''", XmlUtils.toReadableEvent(r));
+			throw rex("Invalid event type on stream reader for elementToString() method: '%s'", XmlUtils.toReadableEvent(r));
 		rsb.setLength(0);
 		rsb.append("<").append(t == 1 ? "" : "/").append(r.getLocalName());
 		if (t == 1)
@@ -334,7 +334,7 @@ public class XmlParserSession extends ReaderParserSession implements RecordReada
 				} while (depth > 0);
 				break;
 			} else {
-				throw new ParseException(this, "Unexpected event type ''{0}''", eventType);
+				throw new ParseException(this, "Unexpected event type '%s'", eventType);
 			}
 			eventType = r.next();
 		}
@@ -487,13 +487,13 @@ public class XmlParserSession extends ReaderParserSession implements RecordReada
 							sb = getStringBuilder();
 						sb.append(getElementAsString(r));
 					} else
-						throw new ParseException("End element found where one was not expected.  {0}", XmlUtils.toReadableEvent(r));
+						throw new ParseException("End element found where one was not expected.  %s", XmlUtils.toReadableEvent(r));
 				}
 				depth--;
 			} else if (event == COMMENT) {
 				// Ignore comments.
 			} else {
-				throw new ParseException("Unexpected event type: {0}", XmlUtils.toReadableEvent(r));
+				throw new ParseException("Unexpected event type: %s", XmlUtils.toReadableEvent(r));
 			}
 		} while (depth >= 0);
 
@@ -1009,7 +1009,7 @@ public class XmlParserSession extends ReaderParserSession implements RecordReada
 				m = newGenericMap().append(wrapperAttr, m);
 			o = newBeanMap(outer, sType.inner()).load(m).getBean();
 		} else {
-			throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}'', property: ''{2}''", cn(sType), sType.getNotABeanReason(),
+			throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s', property: '%s'", cn(sType), sType.getNotABeanReason(),
 				pMeta == null ? null : pMeta.getName());
 		}
 
@@ -1074,4 +1074,4 @@ public class XmlParserSession extends ReaderParserSession implements RecordReada
 	protected String parseWhitespaceElement(XmlReader r) throws IOException, XMLStreamException, ParseException {
 		return null;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlUtils.java
index ad2d60394e..7b480ce335 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/xml/XmlUtils.java
@@ -509,7 +509,7 @@ public class XmlUtils {
 					if (xmlNs.prefix().equals(prefix))
 						return Namespace.of(prefix, xmlNs.namespaceURI());
 			}
-			throw brex("Found @Xml.prefix annotation with no matching URI.  prefix=''{0}''", prefix);
+			throw brex("Found @Xml.prefix annotation with no matching URI.  prefix='%s'", prefix);
 		}
 
 		// If only namespaceURI specified, need to search for prefix. // HTT: reached only via XmlSerializer when @Xml has namespace but no prefix; not exercised by unit tests
@@ -602,4 +602,4 @@ public class XmlUtils {
 		}
 		return false;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlParserSession.java
index cd2051ac5c..cd4338f635 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlParserSession.java
@@ -259,7 +259,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 				else if (nn(sType.getProxyInvocationHandler()))
 					o = newBeanMap(outer, sType.inner()).load(m).getBean();
 				else
-					throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+					throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 			}
 		} else if (c == '[') {
 			if (sType.isObject()) {
@@ -271,7 +271,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 				var l = (ArrayList)parseFlowSequence(r, list(), sType, pMeta);
 				o = toArray(sType, l);
 			} else {
-				throw new ParseException(this, "Unrecognized syntax for class type ''{0}'', starting character ''{1}''", sType, (char)c);
+				throw new ParseException(this, "Unrecognized syntax for class type '%s', starting character '%s'", sType, (char)c);
 			}
 		} else if (c == '\'') {
 			String s = parseSingleQuotedString(r);
@@ -291,7 +291,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 					var l = (ArrayList)parseBlockSequence(r, list(), sType, pMeta, 0);
 					o = toArray(sType, l);
 				} else {
-					throw new ParseException(this, "Unrecognized syntax for class type ''{0}'', starting character ''{1}''", sType, (char)c);
+					throw new ParseException(this, "Unrecognized syntax for class type '%s', starting character '%s'", sType, (char)c);
 				}
 			} else {
 				String s = parsePlainScalar(r, 0);
@@ -364,7 +364,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 					return cast(m2, pMeta, eType);
 				if (nn(sType.getProxyInvocationHandler()))
 					return newBeanMap(outer, sType.inner()).load(m2).getBean();
-				throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+				throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 			}
 		}
 		if (sType.isObject())
@@ -422,7 +422,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 					return cast(m2, pMeta, eType);
 				if (nn(sType.getProxyInvocationHandler()))
 					return newBeanMap(outer, sType.inner()).load(m2).getBean();
-				throw new ParseException(this, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", cn(sType), sType.getNotABeanReason());
+				throw new ParseException(this, "Class '%s' could not be instantiated.  Reason: '%s'", cn(sType), sType.getNotABeanReason());
 			}
 		}
 
@@ -466,7 +466,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 		} else if (sType.canCreateNewInstanceFromString(outer)) {
 			return sType.newInstanceFromString(outer, s);
 		} else {
-			throw new ParseException(this, "Unrecognized syntax for class type ''{0}'', value ''{1}''", sType, s);
+			throw new ParseException(this, "Unrecognized syntax for class type '%s', value '%s'", sType, s);
 		}
 	}
 
@@ -771,7 +771,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 
 			c = r.read(); // Should be ':'
 			if (c != ':')
-				throw new ParseException(this, "Expected ':' after key in YAML block mapping, found ''{0}''", (char)c);
+				throw new ParseException(this, "Expected ':' after key in YAML block mapping, found '%s'", (char)c);
 
 			c = r.peek();
 			if (c == ' ')
@@ -984,7 +984,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 
 				c = r.read(); // Should be ':'
 				if (c != ':')
-					throw new ParseException(this, "Expected ':' after attribute name in YAML block mapping, found ''{0}''", (char)c);
+					throw new ParseException(this, "Expected ':' after attribute name in YAML block mapping, found '%s'", (char)c);
 
 				if (! currAttr.equals(getBeanTypePropertyName((ClassMeta<?>) m.getBeanInfo()))) {
 					var pm = m.getPropertyMeta(currAttr);
@@ -1152,7 +1152,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 						break;
 					}
 					default:
-						throw new ParseException(this, "Invalid escape sequence '\\{0}' in YAML string.", (char)c);
+						throw new ParseException(this, "Invalid escape sequence '\\%s' in YAML string.", (char)c);
 				}
 				// @formatter:on
 			} else if (c == '"') {
@@ -1240,7 +1240,7 @@ public class YamlParserSession extends ReaderParserSession implements RecordRead
 			} else if (c == ' ' || c == '\t') {
 				continue;
 			} else {
-				throw new ParseException(this, "Unexpected character ''{0}'' in YAML block scalar indicator.", (char)c);
+				throw new ParseException(this, "Unexpected character '%s' in YAML block scalar indicator.", (char)c);
 			}
 		}
 
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
index abcd86efd4..79a57bb990 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
@@ -269,7 +269,7 @@ public class ComboRoundTrip_Tester<T> {
 		for (var v : verify) {
 			var s = v.apply(o);
 			if (ine(s)) {
-				throw new BasicAssertionError("Verification failed on test {0}/{1}: {2}", label, testName, s);
+				throw new BasicAssertionError("Verification failed on test %s/%s: %s", label, testName, s);
 			}
 		}
 	}
@@ -292,14 +292,14 @@ public class ComboRoundTrip_Tester<T> {
 				System.out.println(r);
 			}
 
-			assertEquals(exp, r, fs("{0}/{1} serialize-normal failed.", label, testName));
+			assertEquals(exp, r, fs("%s/%s serialize-normal failed.", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -316,14 +316,14 @@ public class ComboRoundTrip_Tester<T> {
 			o = postConvert.apply((T)o);
 			r = s.serializeToString(o);
 
-			assertEquals(exp, r, fs("{0}/{1} parse-normal failed", label, testName));
+			assertEquals(exp, r, fs("%s/%s parse-normal failed", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Throwable e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -344,7 +344,7 @@ public class ComboRoundTrip_Tester<T> {
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -359,14 +359,14 @@ public class ComboRoundTrip_Tester<T> {
 			var r = s.serializeToString(in.get());
 			var o = p.parse(r, type);
 			r = jsonForEquivalency.serialize(o);
-			assertEquals(exp, r, fs("{0}/{1} parse-normal failed on JSON equivalency", label, testName));
+			assertEquals(exp, r, fs("%s/%s parse-normal failed on JSON equivalency", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -375,4 +375,4 @@ public class ComboRoundTrip_Tester<T> {
 	public String toString() {
 		return "ComboRoundTripTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboSerialize_Tester.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboSerialize_Tester.java
index 7eaef6b9b2..b6da5c9870 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboSerialize_Tester.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/ComboSerialize_Tester.java
@@ -204,14 +204,14 @@ public class ComboSerialize_Tester<T> {
 				}
 			}
 
-			assertEquals(exp, r, fs("{0}/{1} serialize-normal failed.", label, testName));
+			assertEquals(exp, r, fs("%s/%s serialize-normal failed.", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -220,4 +220,4 @@ public class ComboSerialize_Tester<T> {
 	public String toString() {
 		return "ComboSerializeTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MarshalledConfig_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MarshalledConfig_Test.java
index 11da245424..f166d91c42 100755
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MarshalledConfig_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MarshalledConfig_Test.java
@@ -80,17 +80,17 @@ class MarshalledConfig_Test extends TestBase {
 		var pm1 = bc.toBeanMap(p1);
 		Map<?,?> pm1AsMap = pm1; // Compare as Map to avoid dissimilar type comparison
 
-		assertEquals(pm1.size(), m1.size(), fs("Bean Map size failed for: {0} / {1} / {2}", p1, pm1.size(), m1.size()));
-		assertEquals(pm1.keySet(), m1.keySet(), fs("Bean Map key set equality failed for: {0} / {1} / {2}", p1, pm1.keySet() , m1.keySet()));
-		assertEquals(m1.keySet(), pm1.keySet(), fs("Bean Map key set reverse equality failed for: {0} / {1} / {2}", p1, pm1.keySet(), m1.keySet()));
-		assertEquals(pm1AsMap, m1, fs("Bean Map equality failed for: {0} / {1} / {2}", p1, pm1, m1));
+		assertEquals(pm1.size(), m1.size(), fs("Bean Map size failed for: %s / %s / %s", p1, pm1.size(), m1.size()));
+		assertEquals(pm1.keySet(), m1.keySet(), fs("Bean Map key set equality failed for: %s / %s / %s", p1, pm1.keySet() , m1.keySet()));
+		assertEquals(m1.keySet(), pm1.keySet(), fs("Bean Map key set reverse equality failed for: %s / %s / %s", p1, pm1.keySet(), m1.keySet()));
+		assertEquals(pm1AsMap, m1, fs("Bean Map equality failed for: %s / %s / %s", p1, pm1, m1));
 		assertThrows(BeanRuntimeException.class, ()->bc.newBeanMap(Address.class));  // Address returned as a new bean type, but shouldn't be since it doesn't have a default constructor.
 		assertNull(bc.newBeanMap(java.lang.Integer.class), "java.lang.Integer incorrectly designated as bean type.");
 		assertNull(bc.newBeanMap(java.lang.Class.class), "java.lang.Class incorrectly designated as bean type.");
 
 		var bm1 = bc.toBeanMap(new Address("street", "city", "state", "zip"));
 
-		assertEquals(bm1.size(), m2.size(), fs("Bean Adapter map's key set has wrong size: {0} / {1} / {2}", a, bm1.size(), m2.size()));
+		assertEquals(bm1.size(), m2.size(), fs("Bean Adapter map's key set has wrong size: %s / %s / %s", a, bm1.size(), m2.size()));
 
 		var iter = bm1.keySet().iterator();
 		var temp = new HashSet<>();
@@ -100,15 +100,15 @@ class MarshalledConfig_Test extends TestBase {
 			count++;
 		}
 
-		assertEquals(count, m2.size(), fs("Iteration count over bean adpater key set failed: {0} / {1} / {2}", a, count, m2.size()));
-		assertEquals(m2.keySet(), temp, fs("Iteration over bean adpater key set failed: {0} / {1} / {2}", a, bm1.keySet(), m2.keySet()));
-		assertNotNull(bc.toBeanMap(p2), fs("Failed to identify class as bean type: {0}", p2.getClass()));
+		assertEquals(count, m2.size(), fs("Iteration count over bean adpater key set failed: %s / %s / %s", a, count, m2.size()));
+		assertEquals(m2.keySet(), temp, fs("Iteration over bean adpater key set failed: %s / %s / %s", a, bm1.keySet(), m2.keySet()));
+		assertNotNull(bc.toBeanMap(p2), fs("Failed to identify class as bean type: %s", p2.getClass()));
 
 		var m5 = bc.toBeanMap(p2);
 		var es1 = (Set)m5.entrySet();
 
-		assertEquals(es1, m3.entrySet(), fs("Entry set equality failed: {0} / {1} / {2}", p2, es1, m3.entrySet()));
-		assertEquals(m3.entrySet(), es1, fs("Entry set reverse equality failed: {0} / {1} / {2}", p2, es1, m3.entrySet()));
+		assertEquals(es1, m3.entrySet(), fs("Entry set equality failed: %s / %s / %s", p2, es1, m3.entrySet()));
+		assertEquals(m3.entrySet(), es1, fs("Entry set reverse equality failed: %s / %s / %s", p2, es1, m3.entrySet()));
 
 		iter = es1.iterator();
 		temp = new HashSet<>();
@@ -118,8 +118,8 @@ class MarshalledConfig_Test extends TestBase {
 			count++;
 		}
 
-		assertEquals(count, m3.size(), fs("Iteration count over bean adpater entry set failed: {0} / {1} / {2}", a, count, m3.size()));
-		assertEquals(m3.entrySet(), temp, fs("Iteration over bean adpater entry set failed: {0} / {1} / {2}", a, es1, m3.entrySet()));
+		assertEquals(count, m3.size(), fs("Iteration count over bean adpater entry set failed: %s / %s / %s", a, count, m3.size()));
+		assertEquals(m3.entrySet(), temp, fs("Iteration over bean adpater entry set failed: %s / %s / %s", a, es1, m3.entrySet()));
 	}
 
 	public static class Person {
@@ -139,7 +139,7 @@ class MarshalledConfig_Test extends TestBase {
 
 		@Override /* Overridden from Object */
 		public String toString() {
-			return f("Person(name: {0}, age: {1})", name, age);
+			return f("Person(name: %s, age: %s)", name, age);
 		}
 	}
 
@@ -176,7 +176,7 @@ class MarshalledConfig_Test extends TestBase {
 
 		@Override /* Overridden from Object */
 		public String toString() {
-			return f("Address(street: {0}, city: {1}, state: {2}, zip: {3})", street, city, state, zip);
+			return f("Address(street: %s, city: %s, state: %s, zip: %s)", street, city, state, zip);
 		}
 	}
 
@@ -334,7 +334,7 @@ class MarshalledConfig_Test extends TestBase {
 
 		@Override /* Overridden from Object */
 		public String toString() {
-			return f("toString():name={0},age={1}", name, age);
+			return f("toString():name=%s,age=%s", name, age);
 		}
 	}
 
@@ -364,7 +364,7 @@ class MarshalledConfig_Test extends TestBase {
 
 		@Override /* Overridden from Object */
 		public String toString() {
-			return f("toString():name={0},age={1}", name, age);
+			return f("toString():name=%s,age=%s", name, age);
 		}
 	}
 
@@ -405,10 +405,10 @@ class MarshalledConfig_Test extends TestBase {
 		var f1 = (A) Proxy.newProxyInstance(this.getClass().getClassLoader(), a(A.class), new AHandler());
 
 		var bm1 = session.toBeanMap(f1);
-		assertNotNull(bm1, fs("Failed to obtain bean adapter for proxy: {0}", f1));
+		assertNotNull(bm1, fs("Failed to obtain bean adapter for proxy: %s", f1));
 
 		var bm2 = session.newBeanMap(A.class);
-		assertNotNull(bm2, fs("Failed to create dynamic proxy bean for interface: {0}", A.class.getName()));
+		assertNotNull(bm2, fs("Failed to create dynamic proxy bean for interface: %s", A.class.getName()));
 
 		bm2.put("a", "Hello");
 		bm2.put("b", Integer.valueOf(50));
@@ -416,8 +416,8 @@ class MarshalledConfig_Test extends TestBase {
 		f1.setB(50);
 
 		assertBean(bm2, "a,b", "Hello,50");
-		assertEquals(bm1, bm2, fs("Failed equality test of dynamic proxies beans: {0} / {1}", bm1, bm2));
-		assertEquals(bm2, bm1, fs("Failed reverse equality test of dynamic proxies beans: {0} / {1}", bm1, bm2));
+		assertEquals(bm1, bm2, fs("Failed equality test of dynamic proxies beans: %s / %s", bm1, bm2));
+		assertEquals(bm2, bm1, fs("Failed reverse equality test of dynamic proxies beans: %s / %s", bm1, bm2));
 	}
 
 	public interface A {
@@ -667,4 +667,4 @@ class MarshalledConfig_Test extends TestBase {
 		assertEquals(false, (boolean)bc.convertToType("", boolean.class));
 		assertEquals(null, bc.convertToType("", Boolean.class));
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MaxIndent_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MaxIndent_Test.java
index f7ac568eff..4336e74f5c 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MaxIndent_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/MaxIndent_Test.java
@@ -226,7 +226,7 @@ class MaxIndent_Test extends TestBase {
 				return;
 			}
 
-			assertEquals(expected, r, fs("{0}/{1} parse-normal failed", input.label, testName));
+			assertEquals(expected, r, fs("%s/%s parse-normal failed", input.label, testName));
 
 		} catch (AssertionError e) {
 			throw e;
@@ -235,4 +235,4 @@ class MaxIndent_Test extends TestBase {
 			throw new AssertionError(input.label + "/" + testName + " failed.  exception=" + e.getLocalizedMessage());
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
index c4d465888b..1849eb05b3 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/cp/Messages_Test.java
@@ -157,4 +157,12 @@ class Messages_Test extends TestBase {
 		var x = Messages.of(Test2.class);
 		assertString("{file=Test2.properties,yyy=bar}", x);
 	}
+
+	@Test void a14_getString_messageFormatPlaceholder() {
+		// Regression: .properties-sourced MessageFormat {0} messages must still render through
+		// Messages.getString (now routed through mf() rather than f()).
+		var x = Messages.of(MessageBundleTest1.class);
+		assertEquals("foo bar", x.getString("foo", "bar"));
+		assertEquals("fooja bar", x.forLocale(JAPAN).getString("foo", "bar"));
+	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ClassMetaRuntimeException_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ClassMetaRuntimeException_Test.java
index 4e58a1ea6e..5543c763a5 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ClassMetaRuntimeException_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/ClassMetaRuntimeException_Test.java
@@ -58,7 +58,7 @@ class ClassMetaRuntimeException_Test {
 
 	// Varargs constructor with format args
 	@Test void a06_message_with_args() {
-		var e = new ClassMetaRuntimeException("value={0}", 42);
+		var e = new ClassMetaRuntimeException("value=%s", 42);
 		assertTrue(e.getMessage().contains("42"));
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/BasicHtml_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/BasicHtml_Test.java
index 78ecc17db8..c2b2ed150f 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/BasicHtml_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/BasicHtml_Test.java
@@ -2554,7 +2554,7 @@ class BasicHtml_Test extends TestBase {
 	void a1_serializeNormal(Input input) {
 		try {
 			var r = s1.serialize(input.in);
-			assertEquals(input.e1, r, fs("{0} serialize-normal failed", input.label));
+			assertEquals(input.e1, r, fs("%s serialize-normal failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -2569,7 +2569,7 @@ class BasicHtml_Test extends TestBase {
 			var r = s1.serialize(input.in);
 			var o = parser.parse(r, input.type);
 			r = s1.serialize(o);
-			assertEquals(input.e1, r, fs("{0} parse-normal failed", input.label));
+			assertEquals(input.e1, r, fs("%s parse-normal failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -2596,7 +2596,7 @@ class BasicHtml_Test extends TestBase {
 	void b1_serializeReadable(Input input) {
 		try {
 			var r = s2.serialize(input.in);
-			assertEquals(input.e2, r, fs("{0} serialize-readable failed", input.label));
+			assertEquals(input.e2, r, fs("%s serialize-readable failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -2611,7 +2611,7 @@ class BasicHtml_Test extends TestBase {
 			var r = s2.serialize(input.in);
 			var o = parser.parse(r, input.type);
 			r = s2.serialize(o);
-			assertEquals(input.e2, r, fs("{0} parse-readable failed", input.label));
+			assertEquals(input.e2, r, fs("%s parse-readable failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -2638,7 +2638,7 @@ class BasicHtml_Test extends TestBase {
 	void c1_serializeAbridged(Input input) {
 		try {
 			var r = s3.serialize(input.in);
-			assertEquals(input.e3, r, fs("{0} serialize-addRootType failed", input.label));
+			assertEquals(input.e3, r, fs("%s serialize-addRootType failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -2653,7 +2653,7 @@ class BasicHtml_Test extends TestBase {
 			var r = s3.serialize(input.in);
 			var o = parser.parse(r, input.type);
 			r = s3.serialize(o);
-			assertEquals(input.e3, r, fs("{0} parse-addRootType failed", input.label));
+			assertEquals(input.e3, r, fs("%s parse-addRootType failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -3116,7 +3116,7 @@ class BasicHtml_Test extends TestBase {
 
 	private static void assertInstancesOf(Class<?> c, Object...values) {
 		for (var i = 0; i < values.length; i++) {
-			assertInstanceOf(c, values[i], fs("Object {0} not expected type.  Expected={1}, Actual={2}", i, c, cns(values[i])));
+			assertInstanceOf(c, values[i], fs("Object %s not expected type.  Expected=%s, Actual=%s", i, c, cns(values[i])));
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/SchemaValidationException_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/SchemaValidationException_Test.java
index b515c2ce00..b27f60811b 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/SchemaValidationException_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/httppart/SchemaValidationException_Test.java
@@ -31,7 +31,7 @@ class SchemaValidationException_Test extends TestBase {
 	}
 
 	@Test void a02_withArgs() {
-		var x = new SchemaValidationException("Test {0} {1}", "foo", "bar");
+		var x = new SchemaValidationException("Test %s %s", "foo", "bar");
 		assertTrue(x.getMessage().contains("Test foo bar"));
 	}
 
@@ -75,4 +75,4 @@ class SchemaValidationException_Test extends TestBase {
 
 		assertTrue(x.getMessage().contains("Updated message"));
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/json/JsonParserEdgeCases_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/json/JsonParserEdgeCases_Test.java
index e9ac0b808c..8bb72a014b 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/json/JsonParserEdgeCases_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/json/JsonParserEdgeCases_Test.java
@@ -452,12 +452,12 @@ class JsonParserEdgeCases_Test extends TestBase {
 	private static void assertParseError(Input input, Throwable t) {
 		if (t instanceof ParseException t2) {
 			if (input.errorText != null)
-				assertTrue(t2.getRootCause().getMessage().contains(input.errorText), fs("Got ParseException but didn't contain expected text ''{0}''.  Test={1}, Input={2}, Message={3}", input.errorText, input.name, input.jsonReadable, t2.getRootCause().getMessage()));
+				assertTrue(t2.getRootCause().getMessage().contains(input.errorText), fs("Got ParseException but didn't contain expected text '%s'.  Test=%s, Input=%s, Message=%s", input.errorText, input.name, input.jsonReadable, t2.getRootCause().getMessage()));
 		} else if (t instanceof IOException t2) {
 			if (input.errorText != null)
-				assertTrue(t2.getMessage().contains(input.errorText), fs("Got IOException but didn't contain expected text ''{0}''.  Test={1}, Input={2}, Message={3}", input.errorText, input.name, input.jsonReadable, t2.getMessage()));
+				assertTrue(t2.getMessage().contains(input.errorText), fs("Got IOException but didn't contain expected text '%s'.  Test=%s, Input=%s, Message=%s", input.errorText, input.name, input.jsonReadable, t2.getMessage()));
 		} else {
 			fail("Expected ParseException.  Test="+input.name+", Input=" + input.jsonReadable + ", Exception=" + cn(t) + "," + t.getLocalizedMessage());
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/objecttools/PathTraversal_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/objecttools/PathTraversal_Test.java
index 4c9735f582..11542cb9d4 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/objecttools/PathTraversal_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/objecttools/PathTraversal_Test.java
@@ -1236,7 +1236,7 @@ class PathTraversal_Test extends TestBase {
 
 	@Test void p02_causeConstructor() {
 		var cause = new RuntimeException("boom");
-		var x = new PathTraversalException(cause, 500, "Failed {0}", "x");
+		var x = new PathTraversalException(cause, 500, "Failed %s", "x");
 		assertSame(cause, x.getCause());
 		assertEquals(500, x.getStatus());
 		assertEquals("Failed x", x.getMessage());
@@ -1245,7 +1245,7 @@ class PathTraversal_Test extends TestBase {
 	@Test void p03_covariantSetMessage() {
 		var x = new PathTraversalException(400, "orig");
 		// setMessage is covariantly typed to return PathTraversalException and returns the same instance.
-		PathTraversalException y = x.setMessage("new {0}", "msg");
+		PathTraversalException y = x.setMessage("new %s", "msg");
 		assertSame(x, y);
 		assertEquals("new msg", x.getMessage());
 	}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/serializer/UriResolution_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/serializer/UriResolution_Test.java
index ce7c68f6e0..c83d1ffaf6 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/serializer/UriResolution_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/serializer/UriResolution_Test.java
@@ -63,7 +63,7 @@ class UriResolution_Test extends TestBase {
 					System.out.println(r);
 				}
 
-				assertEquals(expected, r, fs("{0}/{1} serialize-normal failed", label, cns(s)));
+				assertEquals(expected, r, fs("%s/%s serialize-normal failed", label, cns(s)));
 
 			} catch (AssertionError e) {
 				throw e;
@@ -80,7 +80,7 @@ class UriResolution_Test extends TestBase {
 				var m = p.parse(r, TreeMap.class, String.class, String.class);
 
 				var r2 = Json5Serializer.DEFAULT.toString(m);
-				assertEquals(r2, results.json, fs("{0}/{1} parse failed", label, cns(s)));
+				assertEquals(r2, results.json, fs("%s/%s parse failed", label, cns(s)));
 
 			} catch (AssertionError e) {
 				throw e;
@@ -757,4 +757,4 @@ class UriResolution_Test extends TestBase {
 		var s = MsgPackSerializer.create().uriContext(t.input.context).uriResolution(t.input.resolution).uriRelativity(t.input.relativity).applyAnnotations(TestURIc.Config.class).build();
 		t.testParse(s, MsgPackParser.DEFAULT.copy().applyAnnotations(TestURIc.Config.class).build(), new TestURIc());
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/OneWayStringSwap_Tester.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/OneWayStringSwap_Tester.java
index 78de40bb5d..c222987c88 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/OneWayStringSwap_Tester.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/OneWayStringSwap_Tester.java
@@ -94,11 +94,11 @@ public class OneWayStringSwap_Tester<T> {
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		} catch (Exception e) {
 			if (exceptionMsg == null)
 				throw new AssertionError("Test [" + label + " swap] failed with exception: " + e.getLocalizedMessage(), e);
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		}
 	}
 
@@ -106,4 +106,4 @@ public class OneWayStringSwap_Tester<T> {
 	public String toString() {
 		return "OneWayStringSwapTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/RoundTripObjectSwap_Tester.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/RoundTripObjectSwap_Tester.java
index ca9e1aa233..a9115a357a 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/RoundTripObjectSwap_Tester.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/RoundTripObjectSwap_Tester.java
@@ -87,11 +87,11 @@ public class RoundTripObjectSwap_Tester<T,S> {
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		} catch (Exception e) {
 			if (exceptionMsg == null)
 				throw new AssertionError("Test [" + label + " swap] failed with exception: " + e.getLocalizedMessage(), e);
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		}
 	}
 
@@ -108,11 +108,11 @@ public class RoundTripObjectSwap_Tester<T,S> {
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		} catch (Exception e) {
 			if (exceptionMsg == null)
 				throw new AssertionError("Test [" + label + " unswap] failed with exception: " + e.getLocalizedMessage(), e);
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		}
 	}
 
@@ -120,4 +120,4 @@ public class RoundTripObjectSwap_Tester<T,S> {
 	public String toString() {
 		return "RoundTripObjectSwapTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/StringSwap_Tester.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/StringSwap_Tester.java
index e16ac4e638..5ec70c48d3 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/StringSwap_Tester.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/transforms/StringSwap_Tester.java
@@ -91,11 +91,11 @@ public class StringSwap_Tester<T> {
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		} catch (Exception e) {
 			if (exceptionMsg == null)
 				throw new AssertionError("Test [" + label + " swap] failed with exception: " + e.getLocalizedMessage(), e);
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		}
 	}
 
@@ -113,11 +113,11 @@ public class StringSwap_Tester<T> {
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		} catch (Exception e) {
 			if (exceptionMsg == null)
 				throw new AssertionError("Test [" + label + " unswap] failed with exception: " + e.getLocalizedMessage(), e);
-			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: {0}, but was {1}.", exceptionMsg, e.getMessage()));
+			assertTrue(e.getMessage().contains(exceptionMsg), fs("Expected exception message to contain: %s, but was %s.", exceptionMsg, e.getMessage()));
 		}
 	}
 
@@ -125,4 +125,4 @@ public class StringSwap_Tester<T> {
 	public String toString() {
 		return "StringSwapTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/BasicXml_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/BasicXml_Test.java
index 3baa5bc472..6cb8ee4898 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/BasicXml_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/BasicXml_Test.java
@@ -1185,7 +1185,7 @@ class BasicXml_Test extends TestBase {
 	void a01_serializeNormal(Input input) {
 		try {
 			var r = s1.serialize(input.in);
-			assertEquals(input.e1, r, fs("{0} serialize-normal failed", input.label));
+			assertEquals(input.e1, r, fs("%s serialize-normal failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -1201,7 +1201,7 @@ class BasicXml_Test extends TestBase {
 			var c = input.in == null ? Object.class : input.in.getClass();
 			var o = parser.parse(r, c);
 			r = s1.serialize(o);
-			assertEquals(input.e1, r, fs("{0} parse-normal failed", input.label));
+			assertEquals(input.e1, r, fs("%s parse-normal failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -1214,7 +1214,7 @@ class BasicXml_Test extends TestBase {
 	void a03_serializeReadable(Input input) {
 		try {
 			var r = s2.serialize(input.in);
-			assertEquals(input.e2, r, fs("{0} serialize-readable failed", input.label));
+			assertEquals(input.e2, r, fs("%s serialize-readable failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -1230,7 +1230,7 @@ class BasicXml_Test extends TestBase {
 			var c = input.in == null ? Object.class : input.in.getClass();
 			var o = parser.parse(r, c);
 			r = s2.serialize(o);
-			assertEquals(input.e2, r, fs("{0} parse-readable failed", input.label));
+			assertEquals(input.e2, r, fs("%s parse-readable failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -1243,7 +1243,7 @@ class BasicXml_Test extends TestBase {
 	void a05_serializeNsEnabled(Input input) {
 		try {
 			var r = s3.serialize(input.in);
-			assertEquals(input.e3, r, fs("{0} serialize-ns-enabled failed", input.label));
+			assertEquals(input.e3, r, fs("%s serialize-ns-enabled failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -1259,7 +1259,7 @@ class BasicXml_Test extends TestBase {
 			var c = input.in == null ? Object.class : input.in.getClass();
 			var o = parser.parse(r, c);
 			r = s3.serialize(o);
-			assertEquals(input.e3, r, fs("{0} parse-ns-enabled failed", input.label));
+			assertEquals(input.e3, r, fs("%s parse-ns-enabled failed", input.label));
 		} catch (AssertionError e) {
 			throw e;
 		} catch (Throwable e) {
@@ -1775,4 +1775,4 @@ class BasicXml_Test extends TestBase {
 			return this;
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/XmlIgnoreComments_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/XmlIgnoreComments_Test.java
index 218d5ec99c..f40f7fbf7a 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/XmlIgnoreComments_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/xml/XmlIgnoreComments_Test.java
@@ -704,14 +704,14 @@ class XmlIgnoreComments_Test extends TestBase {
 	@MethodSource("input")
 	void a01_noComment(Input input) throws Exception {
 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", ""), input.type);
-		assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
+		assertEquals(json(actual), json(input.expected), fs("Test '%s' failed with comparison error", input.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("input")
 	void a02_normalComment(Input input) throws Exception {
 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", "<!--x-->"), input.type);
-		assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
+		assertEquals(json(actual), json(input.expected), fs("Test '%s' failed with comparison error", input.label));
 	}
 
 	@ParameterizedTest
@@ -719,7 +719,7 @@ class XmlIgnoreComments_Test extends TestBase {
 	void a03_commentWithWhitespace(Input input) throws Exception {
 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", " \n <!-- \n x \n --> \n "), input.type);
 		if (! input.skipWsTests)
-			assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
+			assertEquals(json(actual), json(input.expected), fs("Test '%s' failed with comparison error", input.label));
 	}
 
 	@ParameterizedTest
@@ -727,7 +727,7 @@ class XmlIgnoreComments_Test extends TestBase {
 	void a04_doubleCommentsWithWhitespace(Input input) throws Exception {
 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", " \n <!-- \n x \n --> \n \n <!-- \n x \n --> \n "), input.type);
 		if (! input.skipWsTests)
-			assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
+			assertEquals(json(actual), json(input.expected), fs("Test '%s' failed with comparison error", input.label));
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -1234,4 +1234,4 @@ class XmlIgnoreComments_Test extends TestBase {
 			return this;
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextResolutionCombo_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextResolutionCombo_Test.java
index 3b939160c9..1fa714f3c6 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextResolutionCombo_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextResolutionCombo_Test.java
@@ -1097,7 +1097,7 @@ class UriContextResolutionCombo_Test extends TestBase {
 	@MethodSource("testers")
 	void a01_testAbsoluteResource(Tester t) {
 		var x = UriResolver.of(ABSOLUTE, RESOURCE, UriContext.of(t.input.authority, t.input.context, t.input.resource, t.input.path)).resolve(t.input.uri);
-		assertEquals(t.results.aResource, x, fs("{0}: testAbsolute() failed", t.label));
+		assertEquals(t.results.aResource, x, fs("%s: testAbsolute() failed", t.label));
 	}
 
 	@ParameterizedTest
@@ -1176,4 +1176,4 @@ class UriContextResolutionCombo_Test extends TestBase {
 		var x = UriResolver.of(NONE, PATH_INFO, UriContext.of(t.input.authority, t.input.context, t.input.resource, t.input.path)).append(new StringBuilder(), t.input.uri);
 		assertString(t.results.nPathInfo, x);
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextUriCombo_Test.java b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextUriCombo_Test.java
index 0ae11139a9..3d22491446 100644
--- a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextUriCombo_Test.java
+++ b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/utils/UriContextUriCombo_Test.java
@@ -239,42 +239,42 @@ class UriContextUriCombo_Test extends TestBase {
 	@ParameterizedTest
 	@MethodSource("data")
 	void a01_testAbsoluteAuthority(Data d) {
-		assertEquals(d.r.eAbsoluteAuthority, d.in.uriContext.getAbsoluteAuthority(), fs("{0}: testAbsoluteAuthority() failed", d.label));
+		assertEquals(d.r.eAbsoluteAuthority, d.in.uriContext.getAbsoluteAuthority(), fs("%s: testAbsoluteAuthority() failed", d.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("data")
 	void a02_testAbsoluteContext(Data d) {
-		assertEquals(d.r.eAbsoluteContext, d.in.uriContext.getAbsoluteContextRoot(), fs("{0}: testAbsoluteContext() failed", d.label));
+		assertEquals(d.r.eAbsoluteContext, d.in.uriContext.getAbsoluteContextRoot(), fs("%s: testAbsoluteContext() failed", d.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("data")
 	void a03_testAbsoluteResource(Data d) {
-		assertEquals(d.r.eAbsoluteResource, d.in.uriContext.getAbsoluteServletPath(), fs("{0}: testAbsoluteResource() failed", d.label));
+		assertEquals(d.r.eAbsoluteResource, d.in.uriContext.getAbsoluteServletPath(), fs("%s: testAbsoluteResource() failed", d.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("data")
 	void a04_testAbsolutePath(Data d) {
-		assertEquals(d.r.eAbsolutePath, d.in.uriContext.getAbsolutePathInfo(), fs("{0}: testAbsolutePath() failed", d.label));
+		assertEquals(d.r.eAbsolutePath, d.in.uriContext.getAbsolutePathInfo(), fs("%s: testAbsolutePath() failed", d.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("data")
 	void a05_testRootRelativeContext(Data d) {
-		assertEquals(d.r.eRootRelativeContext, d.in.uriContext.getRootRelativeContextRoot(), fs("{0}: testRootRelativeContext() failed", d.label));
+		assertEquals(d.r.eRootRelativeContext, d.in.uriContext.getRootRelativeContextRoot(), fs("%s: testRootRelativeContext() failed", d.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("data")
 	void a06_testRootRelativeResource(Data d) {
-		assertEquals(d.r.eRootRelativeResource, d.in.uriContext.getRootRelativeServletPath(), fs("{0}: testRootRelativeResource() failed", d.label));
+		assertEquals(d.r.eRootRelativeResource, d.in.uriContext.getRootRelativeServletPath(), fs("%s: testRootRelativeResource() failed", d.label));
 	}
 
 	@ParameterizedTest
 	@MethodSource("data")
 	void a07_testRootRelativePath(Data d) {
-		assertEquals(d.r.eRootRelativePath, d.in.uriContext.getRootRelativePathInfo(), fs("{0}: testRootRelativePath() failed", d.label));
+		assertEquals(d.r.eRootRelativePath, d.in.uriContext.getRootRelativePathInfo(), fs("%s: testRootRelativePath() failed", d.label));
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-test-utils/src/main/java/org/apache/juneau/BasicTestUtils.java b/juneau-core/juneau-test-utils/src/main/java/org/apache/juneau/BasicTestUtils.java
index 2ca13c9e7d..3646f389d2 100644
--- a/juneau-core/juneau-test-utils/src/main/java/org/apache/juneau/BasicTestUtils.java
+++ b/juneau-core/juneau-test-utils/src/main/java/org/apache/juneau/BasicTestUtils.java
@@ -55,7 +55,7 @@ public abstract class BasicTestUtils extends Shorts {
 	 */
 	public static void assertEqualsAll(Object...values) {
 		for (var i = 1; i < values.length; i++) {
-			assertEquals(values[0], values[i], fs("Elements at index {0} and {1} did not match. {0}={2}, {1}={3}", 0, i, r(values[0]), r(values[i])));
+			assertEquals(values[0], values[i], fs("Elements at index %1$s and %2$s did not match. %1$s=%3$s, %2$s=%4$s", 0, i, r(values[0]), r(values[i])));
 		}
 	}
 
@@ -68,7 +68,7 @@ public abstract class BasicTestUtils extends Shorts {
 	public static void assertNotEqualsAny(Object actual, Object...values) {
 		assertNotNull(actual, "Value was null.");
 		for (var i = 0; i < values.length; i++) {
-			assertNotEquals(values[i], actual, fs("Element at index {0} unexpectedly matched.  expected={1}, actual={2}", i, values[i], s(actual)));
+			assertNotEquals(values[i], actual, fs("Element at index %s unexpectedly matched.  expected=%s, actual=%s", i, values[i], s(actual)));
 		}
 	}
 
@@ -84,7 +84,7 @@ public abstract class BasicTestUtils extends Shorts {
 	public static <T extends Throwable> T assertThrowsWithMessage(Class<T> expectedType, List<String> expectedSubstrings, org.junit.jupiter.api.function.Executable executable) {
 		var exception = Assertions.assertThrows(expectedType, executable);
 		var messages = getMessages(exception);
-		expectedSubstrings.forEach(x -> assertTrue(messages.contains(x), fs("Expected message to contain: {0}.\nActual:\n{1}", x, messages)));
+		expectedSubstrings.forEach(x -> assertTrue(messages.contains(x), fs("Expected message to contain: %s.\nActual:\n%s", x, messages)));
 		return exception;
 	}
 
@@ -100,7 +100,7 @@ public abstract class BasicTestUtils extends Shorts {
 	public static <T extends Throwable> T assertThrowsWithMessage(Class<T> expectedType, String expectedSubstring, org.junit.jupiter.api.function.Executable executable) {
 		var exception = Assertions.assertThrows(expectedType, executable);
 		var messages = getMessages(exception);
-		assertTrue(messages.contains(expectedSubstring), fs("Expected message to contain: {0}.\nActual:\n{1}", expectedSubstring, messages));
+		assertTrue(messages.contains(expectedSubstring), fs("Expected message to contain: %s.\nActual:\n%s", expectedSubstring, messages));
 		return exception;
 	}
 
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicate.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicate.java
index f949b3e712..1d5e33982f 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicate.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicate.java
@@ -18,7 +18,6 @@ package org.apache.juneau.test.assertions;
 
 import static org.apache.juneau.commons.utils.Shorts.*;
 
-import java.text.*;
 import java.util.function.*;
 
 import org.apache.juneau.commons.utils.*;
@@ -44,7 +43,7 @@ import org.apache.juneau.commons.utils.*;
  * 	<jc>// AssertionError with specified message is thrown otherwise.</jc>
  * 	Predicate&lt;MyBean&gt; <jv>predicate</jv> = <jk>new</jk> AssertionPredicate&lt;MyBean&gt;(
  * 		<jv>x</jv> -&gt; <jv>x</jv>.getFoo().equals(<js>"bar"</js>),
- * 		<js>"Foo did not equal bar.  Bean was=''{0}''"</js>,
+ * 		<js>"Foo did not equal bar.  Bean was='%s'"</js>,
  * 		<jsf>VALUE</jsf>
  * 	);
  * 	<jsm>assertObject</jsm>(<jv>myBean</jv>).is(<jv>predicate</jv>);
@@ -209,7 +208,7 @@ public class AssertionPredicate<T> implements Predicate<T> {
 	 * @param inner The predicate test.
 	 * @param message
 	 * 	The error message if predicate fails.
-	 * 	<br>Supports {@link MessageFormat}-style arguments.
+	 * 	<br>Supports printf-style arguments.
 	 * @param args
 	 * 	Optional message arguments.
 	 * 	<br>Can contain {@link #VALUE} to specify the value itself as an argument.
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicates.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicates.java
index 5c871d3a71..2f09ecf954 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicates.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/AssertionPredicates.java
@@ -21,7 +21,6 @@ import static org.apache.juneau.commons.utils.Shorts.*;
 import static org.apache.juneau.commons.utils.StringUtils.*;
 import static org.apache.juneau.test.assertions.AssertionPredicate.*;
 
-import java.text.*;
 import java.util.*;
 import java.util.function.*;
 import java.util.regex.*;
@@ -107,7 +106,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string contains the specified substring.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not contain expected.  Expected='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not contain expected.  Expected='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -124,7 +123,7 @@ public class AssertionPredicates {
 	 * Uses standard Java equality for testing.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match expected.  Expected='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match expected.  Expected='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -138,7 +137,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified value.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match expected.  Expected='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match expected.  Expected='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -152,7 +151,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string does not match the specified value ignoring case.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match expected.  Expected='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match expected.  Expected='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -166,7 +165,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value is exactly specified type.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value was not expected type.  Expected='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value was not expected type.  Expected='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param type The specified type.
@@ -195,7 +194,7 @@ public class AssertionPredicates {
 	 * Match pattern can contain the <js>"*"</js> meta-character.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match pattern.  Pattern='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match pattern.  Pattern='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -211,7 +210,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value does not match the specified value.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value unexpectedly matched.  Value='{0}'."</js>.
+	 * Assertion error message is <js>"Value unexpectedly matched.  Value='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -225,7 +224,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string does not match the specified value.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value unexpectedly matched.  Value='{0}'."</js>.
+	 * Assertion error message is <js>"Value unexpectedly matched.  Value='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The specified value.
@@ -281,7 +280,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match pattern.  Pattern='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match pattern.  Pattern='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param value The regular expression to match.
@@ -296,7 +295,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match pattern.  Pattern='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match pattern.  Pattern='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param expression The regular expression to match.
@@ -312,7 +311,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value did not match pattern.  Pattern='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value did not match pattern.  Pattern='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param expression The regular expression to match.
@@ -341,7 +340,7 @@ public class AssertionPredicates {
 	 * <p>
 	 * If the predicate extends from {@link AssertionPredicate}, the assertion error
 	 * message is <js>"Value did not pass test."</js> followed by the inner assertion error.
-	 * Otherwise the message is <js>"Value did not pass test.  Value='{0}'."</js>
+	 * Otherwise the message is <js>"Value did not pass test.  Value='%s'."</js>
 	 *
 	 * @param <T> The object type being tested.
 	 * @param predicate The predicate to run.
@@ -357,13 +356,13 @@ public class AssertionPredicates {
 	 * <p>
 	 * If the message specified is <jk>null</jk> and the predicate extends from {@link AssertionPredicate}, the assertion error
 	 * message is <js>"Value did not pass test."</js> followed by the inner assertion error.
-	 * Otherwise the message is <js>"Value did not pass test.  Value='{0}'."</js>
+	 * Otherwise the message is <js>"Value did not pass test.  Value='%s'."</js>
 	 *
 	 * @param <T> The object type being tested.
 	 * @param predicate The predicate to run.
 	 * @param msg
 	 * 	The error message if predicate fails.
-	 * 	<br>Supports {@link MessageFormat}-style arguments.
+	 * 	<br>Supports printf-style arguments.
 	 * @param args
 	 * 	Optional message arguments.
 	 * 	<br>Can contain {@code #VALUE} to specify the value itself as an argument.
@@ -378,7 +377,7 @@ public class AssertionPredicates {
 	 * Predicate that returns <jk>true</jk> if the tested value is the specified or child type.
 	 *
 	 * <p>
-	 * Assertion error message is <js>"Value was not expected type.  Expected='{0}', Actual='{1}'."</js>.
+	 * Assertion error message is <js>"Value was not expected type.  Expected='%s', Actual='%s'."</js>.
 	 *
 	 * @param <T> The object type being tested.
 	 * @param type The specified type.
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/BasicAssertionError.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/BasicAssertionError.java
index 412aaf6aa9..1e6ee2fdbe 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/BasicAssertionError.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/assertions/BasicAssertionError.java
@@ -18,10 +18,8 @@ package org.apache.juneau.test.assertions;
 
 import static org.apache.juneau.commons.utils.Shorts.*;
 
-import java.text.*;
-
 /**
- * An extension of {@link AssertionError} with helper constructors for messages with message-style arguments.
+ * An extension of {@link AssertionError} with helper constructors for messages with printf-style arguments.
  */
 public class BasicAssertionError extends AssertionError {
 
@@ -30,8 +28,8 @@ public class BasicAssertionError extends AssertionError {
 	/**
 	 * Constructor.
 	 *
-	 * @param message The {@link MessageFormat}-style message.
-	 * @param args Optional {@link MessageFormat}-style arguments.
+	 * @param message The printf-style message.
+	 * @param args Optional printf-style arguments.
 	 */
 	public BasicAssertionError(String message, Object...args) {
 		super(f(message, args));
@@ -41,8 +39,8 @@ public class BasicAssertionError extends AssertionError {
 	 * Constructor.
 	 *
 	 * @param cause The cause of this exception.
-	 * @param message The {@link MessageFormat}-style message.
-	 * @param args Optional {@link MessageFormat}-style arguments.
+	 * @param message The printf-style message.
+	 * @param args Optional printf-style arguments.
 	 */
 	public BasicAssertionError(Throwable cause, String message, Object...args) {
 		super(f(message, args), cause);
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BasicBeanConverter.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BasicBeanConverter.java
index 0be8c5f984..32237bc1e5 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BasicBeanConverter.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BasicBeanConverter.java
@@ -803,7 +803,7 @@ public class BasicBeanConverter implements BeanConverter {
 			.stream()
 			.filter(x -> x.canExtract(this, o, name))
 			.findFirst()
-			.orElseThrow(() -> rex("Could not find extractor for object of type {0}", cn(o))).extract(this, o, name);
+			.orElseThrow(() -> rex("Could not find extractor for object of type %s", cn(o))).extract(this, o, name);
 		// @formatter:on
 	}
 
@@ -836,7 +836,7 @@ public class BasicBeanConverter implements BeanConverter {
 			.computeIfAbsent(c, this::findListifier)
 			.map(x -> (Listifier)x)
 			.map(x -> (List<Object>)x.apply(this, o2))
-			.orElseThrow(() -> iaex("Object of type {0} could not be converted to a list.", cns(o2)));
+			.orElseThrow(() -> iaex("Object of type %s could not be converted to a list.", cns(o2)));
 		// @formatter:on
 	}
 
@@ -901,7 +901,7 @@ public class BasicBeanConverter implements BeanConverter {
 		if (isEmpty.isPresent())
 			return isTrue(isEmpty.get()) ? 0 : 1;
 
-		throw iaex("Object of type {0} does not have a determinable size.", cns(o));
+		throw iaex("Object of type %s does not have a determinable size.", cns(o));
 	}
 
 	@Override
@@ -1047,4 +1047,4 @@ public class BasicBeanConverter implements BeanConverter {
 			return cns(t) + ": " + t.getMessage();
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctAssertions.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctAssertions.java
index e29dca7530..b4f98f1548 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctAssertions.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctAssertions.java
@@ -238,7 +238,7 @@ public class BctAssertions {
 	 *    <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"name,age"</js>, <js>"John,30"</js>, () -> <js>"User validation failed"</js>);
 	 *
 	 *    <jc>// With formatted message using Shorts.fs() for convenient message suppliers with arguments</jc>
-	 *    <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"name,age"</js>, <js>"John,30"</js>, <jsm>fs</jsm>(<js>"User {0} validation failed"</js>, <js>"John"</js>));
+	 *    <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"name,age"</js>, <js>"John,30"</js>, <jsm>fs</jsm>(<js>"User %s validation failed"</js>, <js>"John"</js>));
 	 * </p>
 	 *
 	 * <h5 class='section'>Nested Property Testing:</h5>
@@ -386,7 +386,7 @@ public class BctAssertions {
 	 *
 	 * @param message Optional custom error message supplier. If provided, will be composed with the default assertion message.
 	 *                Use {@link Shorts#fs(String, Object...) Shorts.fs()} to conveniently
-	 *                create message suppliers with format arguments (e.g., <code>fs("User {0} validation failed", userName)</code>).
+	 *                create message suppliers with format arguments (e.g., <code>fs("User %s validation failed", userName)</code>).
 	 * @param actual The bean object to test. Must not be null.
 	 * @param fields Comma-delimited list of property names to test. Supports nested syntax with {}.
 	 * @param expected Comma-delimited list of expected values. Must match the order of fields.
@@ -496,7 +496,7 @@ public class BctAssertions {
 				var e = converter.stringify(expected[i]);
 				var a = tokens.stream().map(x -> converter.getNested(actualList.get(i2), x)).collect(joining(","));
 				if (neq(e, a)) {
-					errors.add(assertEqualsFailed(e, a, composeMessage(message, "Bean at row <{0}> did not match.", i)));
+					errors.add(assertEqualsFailed(e, a, composeMessage(message, "Bean at row <%s> did not match.", i)));
 				}
 			}
 		}
@@ -511,7 +511,7 @@ public class BctAssertions {
 
 		throw assertEqualsFailed(Stream.of(expected).map(StringUtils::escapeForJava).collect(joining(JOINER_comma_space, "\"", "\"")),
 			actualStrings.stream().map(StringUtils::escapeForJava).collect(joining(JOINER_comma_space, "\"", "\"")),
-			composeMessage(message, "{0} bean assertions failed:\n{1}", errors.size(), errors.stream().map(x -> x.getMessage()).collect(joining("\n"))));
+			composeMessage(message, "%s bean assertions failed:\n%s", errors.size(), errors.stream().map(x -> x.getMessage()).collect(joining("\n"))));
 	}
 
 	/**
@@ -560,7 +560,7 @@ public class BctAssertions {
 		assertNotNull(actual, MSG_value_was_null);
 
 		var a = BctConfiguration.getConverter().stringify(actual);
-		assertTrue(a.contains(expected), composeMessage(message, "String did not contain expected substring.  ==> expected: <{0}> but was: <{1}>", expected, a));
+		assertTrue(a.contains(expected), composeMessage(message, "String did not contain expected substring.  ==> expected: <%s> but was: <%s>", expected, a));
 	}
 
 	/**
@@ -611,7 +611,7 @@ public class BctAssertions {
 
 		for (var e : expected) {
 			if (! a.contains(e)) {
-				errors.add(assertEqualsFailed(true, false, composeMessage(message, "String did not contain expected substring.  ==> expected: <{0}> but was: <{1}>", e, a)));
+				errors.add(assertEqualsFailed(true, false, composeMessage(message, "String did not contain expected substring.  ==> expected: <%s> but was: <%s>", e, a)));
 			}
 		}
 
@@ -629,7 +629,7 @@ public class BctAssertions {
 		}
 
 		throw assertEqualsFailed(missingSubstrings.stream().map(StringUtils::escapeForJava).collect(joining(JOINER_comma_space, "\"", "\"")), escapeForJava(a),
-			composeMessage(message, "{0} substring assertions failed:\n{1}", errors.size(), errors.stream().map(x -> x.getMessage()).collect(joining("\n"))));
+			composeMessage(message, "%s substring assertions failed:\n%s", errors.size(), errors.stream().map(x -> x.getMessage()).collect(joining("\n"))));
 	}
 
 	/**
@@ -694,7 +694,7 @@ public class BctAssertions {
 	public static void assertEmpty(Supplier<String> message, Object value) {
 		assertNotNull(value, MSG_value_was_null);
 		var size = BctConfiguration.getConverter().size(value);
-		assertEquals(0, size, composeMessage(message, "Value was not empty. Size=<{0}>", size));
+		assertEquals(0, size, composeMessage(message, "Value was not empty. Size=<%s>", size));
 	}
 
 	/**
@@ -786,16 +786,16 @@ public class BctAssertions {
 				var e = expected[i];
 				if (e instanceof String e2) {
 					if (neq(e2, converter.stringify(x))) {
-						errors.add(assertEqualsFailed(e2, converter.stringify(x), composeMessage(message, "Element at index {0} did not match.", i)));
+						errors.add(assertEqualsFailed(e2, converter.stringify(x), composeMessage(message, "Element at index %s did not match.", i)));
 					}
 				} else if (e instanceof Predicate<?> p) {
 					Predicate<Object> e2 = (Predicate<Object>) p;
 					if (! e2.test(x)) {
-						errors.add(new AssertionFailedError(composeMessage(message, "Element at index {0} did not pass predicate.  ==> actual: <{1}>", i, converter.stringify(x)).get()));
+						errors.add(new AssertionFailedError(composeMessage(message, "Element at index %s did not pass predicate.  ==> actual: <%s>", i, converter.stringify(x)).get()));
 					}
 				} else {
 					if (neq(e, x)) {
-						errors.add(assertEqualsFailed(e, x, composeMessage(message, "Element at index {0} did not match.  ==> expected: <{1}({2})> but was: <{3}({4})>", i, e, cns(e), x, cns(x))));
+						errors.add(assertEqualsFailed(e, x, composeMessage(message, "Element at index %s did not match.  ==> expected: <%s(%s)> but was: <%s(%s)>", i, e, cns(e), x, cns(x))));
 					}
 				}
 			}
@@ -814,7 +814,7 @@ public class BctAssertions {
 
 		throw assertEqualsFailed(Stream.of(expected).map(converter::stringify).map(StringUtils::escapeForJava).collect(joining(JOINER_comma_space, "[\"", "\"]")),
 			actualStrings.stream().map(StringUtils::escapeForJava).collect(joining(JOINER_comma_space, "[\"", "\"]")),
-			composeMessage(message, "{0} list assertions failed:\n{1}", errors.size(), errors.stream().map(x -> x.getMessage()).collect(joining("\n"))));
+			composeMessage(message, "%s list assertions failed:\n%s", errors.size(), errors.stream().map(x -> x.getMessage()).collect(joining("\n"))));
 	}
 
 	/**
@@ -1006,7 +1006,7 @@ public class BctAssertions {
 
 		var v = BctConfiguration.getConverter().stringify(value);
 		var m = StringUtils.getGlobMatchPattern(pattern).matcher(v);
-		assertTrue(m.matches(), composeMessage(message, "Pattern didn''t match. ==> pattern: <{0}> but was: <{1}>", pattern, v));
+		assertTrue(m.matches(), composeMessage(message, "Pattern didn't match. ==> pattern: <%s> but was: <%s>", pattern, v));
 	}
 
 	/**
@@ -1185,8 +1185,8 @@ public class BctAssertions {
 		if (customMessage == null) {
 			return fs(defaultMessage, defaultArgs);
 		}
-		return fs("{0}, Caused by: {1}", customMessage.get(), f(defaultMessage, defaultArgs));
+		return fs("%s, Caused by: %s", customMessage.get(), f(defaultMessage, defaultArgs));
 	}
 
 	private BctAssertions() {}
-}
\ No newline at end of file
+}
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctConfigExtension.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctConfigExtension.java
index ba6db96016..6c9bce19f5 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctConfigExtension.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctConfigExtension.java
@@ -53,7 +53,7 @@ public class BctConfigExtension implements BeforeEachCallback, AfterEachCallback
 			var c = x.getDeclaredConstructor();
 			c.setAccessible(true);
 			set(c.newInstance());
-		}, e -> rex(e, "Failed to instantiate BeanConverter: {0}. It must have a no-arg constructor.", x.getName())); // HTT - requires invalid converter without no-arg constructor
+		}, e -> rex(e, "Failed to instantiate BeanConverter: %s. It must have a no-arg constructor.", x.getName())); // HTT - requires invalid converter without no-arg constructor
 	}
 
 	@Override
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctUtils.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctUtils.java
index 42c0739077..88612ba0df 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctUtils.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/BctUtils.java
@@ -50,7 +50,7 @@ public class BctUtils {
 	 * <h5 class='section'>Example:</h5>
 	 * <p class='bjava'>
 	 *   <jk>if</jk> (!<jsm>eq</jsm>(<jv>expected</jv>, <jv>actual</jv>)) {
-	 *       <jk>throw</jk> <jsm>assertEqualsFailed</jsm>(<jv>expected</jv>, <jv>actual</jv>, () -&gt; <js>"Custom context message with arg {0}"</js>, <jv>arg</jv>);
+	 *       <jk>throw</jk> <jsm>assertEqualsFailed</jsm>(<jv>expected</jv>, <jv>actual</jv>, () -&gt; <js>"Custom context message with arg %s"</js>, <jv>arg</jv>);
 	 *   }
 	 * </p>
 	 *
diff --git a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/package-info.java b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/package-info.java
index d16a9f141a..febc08900a 100644
--- a/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/package-info.java
+++ b/juneau-core/juneau-test/src/main/java/org/apache/juneau/test/bct/package-info.java
@@ -210,7 +210,7 @@
  *    <jsm>assertBean</jsm>(() -> <js>"User validation failed"</js>, <jv>user</jv>, <js>"name,age"</js>, <js>"Alice,25"</js>);
  *
  *    <jc>// Formatted message using Shorts.fs() for convenient message suppliers with arguments</jc>
- *    <jsm>assertBean</jsm>(<jsm>fs</jsm>(<js>"User {0} validation failed"</js>, <js>"Alice"</js>), <jv>user</jv>, <js>"name,age"</js>, <js>"Alice,25"</js>);
+ *    <jsm>assertBean</jsm>(<jsm>fs</jsm>(<js>"User %s validation failed"</js>, <js>"Alice"</js>), <jv>user</jv>, <js>"name,age"</js>, <js>"Alice,25"</js>);
  * </p>
  *
  * <h5 class='section'>Customizing the Default Converter:</h5>
diff --git a/juneau-core/juneau-test/src/main/resources/org/apache/juneau/test/assertions/Messages.properties b/juneau-core/juneau-test/src/main/resources/org/apache/juneau/test/assertions/Messages.properties
index 5b2ba571ae..10d9fe5387 100644
--- a/juneau-core/juneau-test/src/main/resources/org/apache/juneau/test/assertions/Messages.properties
+++ b/juneau-core/juneau-test/src/main/resources/org/apache/juneau/test/assertions/Messages.properties
@@ -13,105 +13,105 @@
 # ***************************************************************************************************************************
 
 AssertionPredicate.valueDidNotPassTest = Value did not pass test.
-AssertionPredicate.valueDidNotPassTestWithValue = Value did not pass test.\n\tValue=''{0}''.
-AssertionPredicate.predicateTestFailed = Predicate test #{0} failed.
+AssertionPredicate.valueDidNotPassTestWithValue = Value did not pass test.\n\tValue='%s'.
+AssertionPredicate.predicateTestFailed = Predicate test #%s failed.
 AssertionPredicate.noPredicateTestsPassed = No predicate tests passed.
 AssertionPredicate.predicateTestsUnexpectedlyPassed = Predicate test unexpectedly passed.
 
 AssertionPredicates.valueWasNull = Value was null.
 AssertionPredicates.valueWasNotNull = Value was not null.
-AssertionPredicates.valueDidNotMatchExpected = Value did not match expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-AssertionPredicates.valueDidNotContainExpected = Value did not contain expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-AssertionPredicates.valueUnexpectedlyMatched = Value unexpectedly matched.\n\tValue=''{0}''.
-AssertionPredicates.valueWasNotExpectedType = Value was not expected type.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-AssertionPredicates.valueDidNotMatchPattern = Value did not match pattern.\n\tPattern=''{0}''.\n\tValue=''{1}''.
+AssertionPredicates.valueDidNotMatchExpected = Value did not match expected.\n\tExpect='%s'.\n\tActual='%s'.
+AssertionPredicates.valueDidNotContainExpected = Value did not contain expected.\n\tExpect='%s'.\n\tActual='%s'.
+AssertionPredicates.valueUnexpectedlyMatched = Value unexpectedly matched.\n\tValue='%s'.
+AssertionPredicates.valueWasNotExpectedType = Value was not expected type.\n\tExpect='%s'.\n\tActual='%s'.
+AssertionPredicates.valueDidNotMatchPattern = Value did not match pattern.\n\tPattern='%s'.\n\tValue='%s'.
 
-Assertions.argumentCannotBeNull = Argument ''{0}'' cannot be null.
-Assertions.exceptionNotOfExpectedType = Exception not of expected type.\n\tExpect=''{0}''.\n\tActual=''{1}''.
+Assertions.argumentCannotBeNull = Argument '%s' cannot be null.
+Assertions.exceptionNotOfExpectedType = Exception not of expected type.\n\tExpect='%s'.\n\tActual='%s'.
 
-FluentAnyAssertion.objectWasNotType = Object was not type ''{0}''.\n\tActual=''{1}''.
+FluentAnyAssertion.objectWasNotType = Object was not type '%s'.\n\tActual='%s'.
 
 FluentArrayAssertion.arrayWasNotEmpty = Array was not empty.
 FluentArrayAssertion.arrayWasEmpty = Array was empty.
-FluentArrayAssertion.arrayUnexpectedSize = Array did not have the expected size.\n\tExpect={0}.\n\tActual={1}.
-FluentArrayAssertion.arrayDidNotContainExpectedValue = Array did not contain expected value.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentArrayAssertion.arrayContainedUnexpectedValue = Array contained unexpected value.\n\tUnexpected=''{0}''.\n\tActual=''{1}''.
-FluentArrayAssertion.arrayDidNotContainExpectedValueAt = Array did not contain expected value at index {0}.\n\t{1}
-FluentArrayAssertion.arrayDidntContainAnyMatchingValue = Array did not contain any matching value.\n\tValue=''{0}''.
-FluentArrayAssertion.arrayContainedNonMatchingValueAt = Array contained non-matching value at index {0}.\n\t{1}
+FluentArrayAssertion.arrayUnexpectedSize = Array did not have the expected size.\n\tExpect=%s.\n\tActual=%s.
+FluentArrayAssertion.arrayDidNotContainExpectedValue = Array did not contain expected value.\n\tExpect='%s'.\n\tActual='%s'.
+FluentArrayAssertion.arrayContainedUnexpectedValue = Array contained unexpected value.\n\tUnexpected='%s'.\n\tActual='%s'.
+FluentArrayAssertion.arrayDidNotContainExpectedValueAt = Array did not contain expected value at index %s.\n\t%s
+FluentArrayAssertion.arrayDidntContainAnyMatchingValue = Array did not contain any matching value.\n\tValue='%s'.
+FluentArrayAssertion.arrayContainedNonMatchingValueAt = Array contained non-matching value at index %s.\n\t%s
 
 FluentBooleanAssertion.valueWasFalse = Value was false.
 FluentBooleanAssertion.valueWasTrue = Value was true.
 
 FluentCollectionAssertion.collectionWasNotEmpty = Collection was not empty.
-FluentCollectionAssertion.collectionDidNotContainExpectedValue = Collection did not contain expected value.\n\tExpect=''{0}''.\n\tValue=''{1}''.
-FluentCollectionAssertion.collectionDidNotContainTestedValue = Collection did not contain tested value.\n\tValue=''{0}''.
-FluentCollectionAssertion.collectionContainedUnexpectedValue = Collection contained unexpected value.\n\tUnexpected=''{0}''.\n\tValue=''{1}''.
+FluentCollectionAssertion.collectionDidNotContainExpectedValue = Collection did not contain expected value.\n\tExpect='%s'.\n\tValue='%s'.
+FluentCollectionAssertion.collectionDidNotContainTestedValue = Collection did not contain tested value.\n\tValue='%s'.
+FluentCollectionAssertion.collectionContainedUnexpectedValue = Collection contained unexpected value.\n\tUnexpected='%s'.\n\tValue='%s'.
 FluentCollectionAssertion.collectionWasEmpty = Collection was empty.
-FluentCollectionAssertion.collectionDidNotHaveExpectedSize = Collection did not have the expected size.\n\tExpect={0}.\n\tActual={1}.
+FluentCollectionAssertion.collectionDidNotHaveExpectedSize = Collection did not have the expected size.\n\tExpect=%s.\n\tActual=%s.
 
-FluentComparableAssertion.valueWasNotGreaterThanExpected = Value was not greater than expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentComparableAssertion.valueWasNotGreaterOrEqualsToExpected = Value was not greater than or equals to expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentComparableAssertion.valueWasNotLessThanExpected = Value was not less than expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentComparableAssertion.valueWasNotLessOrEqualsToExpected = Value was not less than or equals to expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
+FluentComparableAssertion.valueWasNotGreaterThanExpected = Value was not greater than expected.\n\tExpect='%s'.\n\tActual='%s'.
+FluentComparableAssertion.valueWasNotGreaterOrEqualsToExpected = Value was not greater than or equals to expected.\n\tExpect='%s'.\n\tActual='%s'.
+FluentComparableAssertion.valueWasNotLessThanExpected = Value was not less than expected.\n\tExpect='%s'.\n\tActual='%s'.
+FluentComparableAssertion.valueWasNotLessOrEqualsToExpected = Value was not less than or equals to expected.\n\tExpect='%s'.\n\tActual='%s'.
 
-FluentDateAssertion.unexpectedValue = Unexpected value.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentDateAssertion.valueWasNotAfterExpected = Value was not after expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentDateAssertion.valueWasNotBeforeExpected = Value was not before expected.\n\tExpect=\''{0}''.\n\tActual=''{1}''.
+FluentDateAssertion.unexpectedValue = Unexpected value.\n\tExpect='%s'.\n\tActual='%s'.
+FluentDateAssertion.valueWasNotAfterExpected = Value was not after expected.\n\tExpect='%s'.\n\tActual='%s'.
+FluentDateAssertion.valueWasNotBeforeExpected = Value was not before expected.\n\tExpect='%s'.\n\tActual='%s'.
 
-FluentListAssertion.listDidNotContainExpectedValueAt = List did not contain expected value at index {0}.\n\t{1}
+FluentListAssertion.listDidNotContainExpectedValueAt = List did not contain expected value at index %s.\n\t%s
 
 FluentMapAssertion.mapWasNotEmpty = Map was not empty.
-FluentMapAssertion.mapDidNotContainExpectedKey = Map did not contain expected key.\n\tExpected key=''{0}''.\n\tValue=''{1}''.
-FluentMapAssertion.mapContainedUnexpectedKey = Map contained unexpected key.\n\tUnexpected key=''{0}''.\n\tValue=''{1}''.
+FluentMapAssertion.mapDidNotContainExpectedKey = Map did not contain expected key.\n\tExpected key='%s'.\n\tValue='%s'.
+FluentMapAssertion.mapContainedUnexpectedKey = Map contained unexpected key.\n\tUnexpected key='%s'.\n\tValue='%s'.
 FluentMapAssertion.mapWasEmpty = Map was empty.
-FluentMapAssertion.mapDidNotHaveTheExpectedSize = Map did not have the expected size.\n\tExpect={0}.\n\tActual={1}.
+FluentMapAssertion.mapDidNotHaveTheExpectedSize = Map did not have the expected size.\n\tExpect=%s.\n\tActual=%s.
 
-FluentObjectAssertion.unexpectedType = Unexpected type.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentObjectAssertion.unexpectedComparison = Unexpected comparison.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentObjectAssertion.unexpectedValue = Unexpected value.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentObjectAssertion.unexpectedValueDidNotExpect = Unexpected value.\n\tDid not expect=''{0}''.\n\tActual=''{1}''.
-FluentObjectAssertion.notTheSameValue = Not the same value.\n\tExpect=''{0}({1})''.\n\tActual=''{2}({3})''.
+FluentObjectAssertion.unexpectedType = Unexpected type.\n\tExpect='%s'.\n\tActual='%s'.
+FluentObjectAssertion.unexpectedComparison = Unexpected comparison.\n\tExpect='%s'.\n\tActual='%s'.
+FluentObjectAssertion.unexpectedValue = Unexpected value.\n\tExpect='%s'.\n\tActual='%s'.
+FluentObjectAssertion.unexpectedValueDidNotExpect = Unexpected value.\n\tDid not expect='%s'.\n\tActual='%s'.
+FluentObjectAssertion.notTheSameValue = Not the same value.\n\tExpect='%s(%s)'.\n\tActual='%s(%s)'.
 FluentObjectAssertion.valueWasNull = Value was null.
 FluentObjectAssertion.valueWasNotNull = Value was not null.
-FluentObjectAssertion.expectedValueNotFound = Expected value not found.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentObjectAssertion.unexpectedValueFound = Unexpected value found.\n\tUnexpected=''{0}''.\n\tActual=''{1}''.
-FluentObjectAssertion.unexpectedValue2 = Unexpected value: ''{0}''.
+FluentObjectAssertion.expectedValueNotFound = Expected value not found.\n\tExpect='%s'.\n\tActual='%s'.
+FluentObjectAssertion.unexpectedValueFound = Unexpected value found.\n\tUnexpected='%s'.\n\tActual='%s'.
+FluentObjectAssertion.unexpectedValue2 = Unexpected value: '%s'.
 
-FluentPrimitiveArrayAssertion.objectWasNotAnArray = Object was not an array.\n\tActual=''{0}''.
+FluentPrimitiveArrayAssertion.objectWasNotAnArray = Object was not an array.\n\tActual='%s'.
 FluentPrimitiveArrayAssertion.arrayWasNotEmpty = Array was not empty.
 FluentPrimitiveArrayAssertion.arrayWasEmpty = Array was empty.
-FluentPrimitiveArrayAssertion.arrayDidNotHaveExpectedSize = Array did not have the expected size.\n\tExpect={0}.\n\tActual={1}.
-FluentPrimitiveArrayAssertion.arrayDidNotContainExpectedValue = Array did not contain expected value.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentPrimitiveArrayAssertion.arrayDidNotContainExpectedValueAt = Array did not contain expected value at index {0}.\n\t{1}
-FluentPrimitiveArrayAssertion.arrayContainedUnexpectedValue = Array contained unexpected value.\n\tUnexpected=''{0}''.\n\tActual=''{1}''.
-FluentPrimitiveArrayAssertion.arrayDidntContainAnyMatchingValue = Array did not contain any matching value.\n\tValue=''{0}''.
-FluentPrimitiveArrayAssertion.arrayContainedNonMatchingValueAt = Array contained non-matching value at index {0}.\n\t{1}
-
-FluentStringAssertion.stringDifferedAtPosition = String differed at position {0}.\n\tExpect=''{1}''.\n\tActual=''{2}''.
-FluentStringAssertion.expectedStringHadDifferentNumbersOfLines = Expected string had different numbers of lines.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentStringAssertion.expectedStringHadDifferentValuesAtLine = Expected string had different values at line {0}.\n\tExpect=''{1}''.\n\tActual=''{2}''.
-FluentStringAssertion.unexpectedValue = Unexpected value.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentStringAssertion.stringEqualedUnexpected = String equaled unexpected.\n\tValue=''{0}''.
-FluentStringAssertion.stringDidNotContainExpectedSubstring = String did not contain expected substring.\n\tSubstring=''{0}''.\n\tValue=''{1}''.
-FluentStringAssertion.stringContainedUnexpectedSubstring = String contained unexpected substring.\n\tSubstring=''{0}''.\n\tValue=''{1}''.
-FluentStringAssertion.stringWasNotEmpty = String was not empty.\n\tValue=''{0}''.
+FluentPrimitiveArrayAssertion.arrayDidNotHaveExpectedSize = Array did not have the expected size.\n\tExpect=%s.\n\tActual=%s.
+FluentPrimitiveArrayAssertion.arrayDidNotContainExpectedValue = Array did not contain expected value.\n\tExpect='%s'.\n\tActual='%s'.
+FluentPrimitiveArrayAssertion.arrayDidNotContainExpectedValueAt = Array did not contain expected value at index %s.\n\t%s
+FluentPrimitiveArrayAssertion.arrayContainedUnexpectedValue = Array contained unexpected value.\n\tUnexpected='%s'.\n\tActual='%s'.
+FluentPrimitiveArrayAssertion.arrayDidntContainAnyMatchingValue = Array did not contain any matching value.\n\tValue='%s'.
+FluentPrimitiveArrayAssertion.arrayContainedNonMatchingValueAt = Array contained non-matching value at index %s.\n\t%s
+
+FluentStringAssertion.stringDifferedAtPosition = String differed at position %s.\n\tExpect='%s'.\n\tActual='%s'.
+FluentStringAssertion.expectedStringHadDifferentNumbersOfLines = Expected string had different numbers of lines.\n\tExpect='%s'.\n\tActual='%s'.
+FluentStringAssertion.expectedStringHadDifferentValuesAtLine = Expected string had different values at line %s.\n\tExpect='%s'.\n\tActual='%s'.
+FluentStringAssertion.unexpectedValue = Unexpected value.\n\tExpect='%s'.\n\tActual='%s'.
+FluentStringAssertion.stringEqualedUnexpected = String equaled unexpected.\n\tValue='%s'.
+FluentStringAssertion.stringDidNotContainExpectedSubstring = String did not contain expected substring.\n\tSubstring='%s'.\n\tValue='%s'.
+FluentStringAssertion.stringContainedUnexpectedSubstring = String contained unexpected substring.\n\tSubstring='%s'.\n\tValue='%s'.
+FluentStringAssertion.stringWasNotEmpty = String was not empty.\n\tValue='%s'.
 FluentStringAssertion.stringWasNull = String was null.
 FluentStringAssertion.stringWasEmpty = String was empty.
-FluentStringAssertion.stringDidNotMatchExpectedPattern = String did not match expected pattern.\n\tPattern=''{0}''.\n\tValue=''{1}''.
-FluentStringAssertion.stringDidNotStartWithExpected = String did not start with expected substring.\n\tSubstring=''{0}''.\n\tValue=''{1}''.
-FluentStringAssertion.stringDidNotEndWithExpected = String did not end with expected substring.\n\tSubstring=''{0}''.\n\tValue=''{1}''.
+FluentStringAssertion.stringDidNotMatchExpectedPattern = String did not match expected pattern.\n\tPattern='%s'.\n\tValue='%s'.
+FluentStringAssertion.stringDidNotStartWithExpected = String did not start with expected substring.\n\tSubstring='%s'.\n\tValue='%s'.
+FluentStringAssertion.stringDidNotEndWithExpected = String did not end with expected substring.\n\tSubstring='%s'.\n\tValue='%s'.
 
-FluentThrowableAssertion.exceptionWasNotExpectedType = Exception was not expected type.\n\tExpect=''{0}''.\n\tActual=''{1}''.
+FluentThrowableAssertion.exceptionWasNotExpectedType = Exception was not expected type.\n\tExpect='%s'.\n\tActual='%s'.
 FluentThrowableAssertion.exceptionWasNotThrown = Exception was not thrown.
 FluentThrowableAssertion.exceptionWasThrown = Exception was thrown.
-FluentThrowableAssertion.causedByExceptionNotExpectedType = Caused-by exception not of expected type.\n\tExpected=''{0}''.\n\tActual=''{1}''.
+FluentThrowableAssertion.causedByExceptionNotExpectedType = Caused-by exception not of expected type.\n\tExpected='%s'.\n\tActual='%s'.
 
-FluentZonedDateTimeAssertion.unexpectedValue = Unexpected value.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentZonedDateTimeAssertion.valueWasNotAfterExpected = Value was not after expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
-FluentZonedDateTimeAssertion.valueWasNotBeforeExpected = Value was not before expected.\n\tExpect=''{0}''.\n\tActual=''{1}''.
+FluentZonedDateTimeAssertion.unexpectedValue = Unexpected value.\n\tExpect='%s'.\n\tActual='%s'.
+FluentZonedDateTimeAssertion.valueWasNotAfterExpected = Value was not after expected.\n\tExpect='%s'.\n\tActual='%s'.
+FluentZonedDateTimeAssertion.valueWasNotBeforeExpected = Value was not before expected.\n\tExpect='%s'.\n\tActual='%s'.
 
-Verify.unexpectedType = Expected type ''{0}'' but was ''{1}''.
-Verify.unexpectedValue = Expected ''{0}'' but was ''{1}''.
+Verify.unexpectedType = Expected type '%s' but was '%s'.
+Verify.unexpectedValue = Expected '%s' but was '%s'.
 
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/AnyAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/AnyAssertion_Test.java
index 9cdc42a170..f81a37a7ea 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/AnyAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/AnyAssertion_Test.java
@@ -61,8 +61,8 @@ class AnyAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		assertThrowsWithMessage(BasicAssertionError.class, "Foo 1", ()->test(null).setMsg("Foo {0}", 1).isExists());
-		assertThrowsWithMessage(RuntimeException.class, "Foo 1", ()->test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class).isExists());
+		assertThrowsWithMessage(BasicAssertionError.class, "Foo 1", ()->test(null).setMsg("Foo %s", 1).isExists());
+		assertThrowsWithMessage(RuntimeException.class, "Foo 1", ()->test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class).isExists());
 	}
 
 	@Test void a02_stdout() {
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ArrayAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ArrayAssertion_Test.java
index b27a6829cf..12108f3759 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ArrayAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ArrayAssertion_Test.java
@@ -47,9 +47,9 @@ public class ArrayAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Assertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Assertion_Test.java
index 653b70e286..2abc102ccf 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Assertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Assertion_Test.java
@@ -48,7 +48,7 @@ class Assertion_Test extends TestBase {
 
 	public static class A extends StringAssertion {
 		public A(Object text) { super(text); }
-		public A doError() { throw error(new A1("foo", null), "bar {0}", "baz"); }
+		public A doError() { throw error(new A1("foo", null), "bar %s", "baz"); }
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanAssertion_Test.java
index 8741188783..8b9e4be013 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanAssertion_Test.java
@@ -50,9 +50,9 @@ class BeanAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanListAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanListAssertion_Test.java
index 6b1a305757..02fbbec0f6 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanListAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BeanListAssertion_Test.java
@@ -53,9 +53,9 @@ class BeanListAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BooleanAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BooleanAssertion_Test.java
index cdd1c5a797..cece13b336 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BooleanAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/BooleanAssertion_Test.java
@@ -39,9 +39,9 @@ class BooleanAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("A {0}", 1);
+		var assertion1 = test(null).setMsg("A %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "A 1");
-		var assertion2 = test(null).setMsg("A {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("A %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "A 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ByteArrayAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ByteArrayAssertion_Test.java
index 87e5abd354..ea0c877e67 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ByteArrayAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ByteArrayAssertion_Test.java
@@ -39,9 +39,9 @@ class ByteArrayAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("A {0}", 1);
+		var assertion1 = test(null).setMsg("A %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "A 1");
-		var assertion2 = test(null).setMsg("A {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("A %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "A 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/CollectionAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/CollectionAssertion_Test.java
index e3348c5769..faa7018009 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/CollectionAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/CollectionAssertion_Test.java
@@ -42,9 +42,9 @@ class CollectionAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("A {0}", 1);
+		var assertion1 = test(null).setMsg("A %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "A 1");
-		var assertion2 = test(null).setMsg("A {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("A %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "A 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ComparableAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ComparableAssertion_Test.java
index 843ac7bf96..edcb69c45c 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ComparableAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ComparableAssertion_Test.java
@@ -39,9 +39,9 @@ class ComparableAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("A {0}", 1);
+		var assertion1 = test(null).setMsg("A %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "A 1");
-		var assertion2 = test(null).setMsg("A {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("A %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "A 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/DateAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/DateAssertion_Test.java
index cff838f8c3..b3d6f6a7b7 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/DateAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/DateAssertion_Test.java
@@ -56,9 +56,9 @@ class DateAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("A {0}", 1);
+		var assertion1 = test(null).setMsg("A %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "A 1");
-		var assertion2 = test(null).setMsg("A {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("A %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "A 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/IntegerAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/IntegerAssertion_Test.java
index 13f1c3f909..d81fe31454 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/IntegerAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/IntegerAssertion_Test.java
@@ -40,9 +40,9 @@ class IntegerAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ListAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ListAssertion_Test.java
index 77117599cb..2d52417596 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ListAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ListAssertion_Test.java
@@ -43,9 +43,9 @@ class ListAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/LongAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/LongAssertion_Test.java
index 0d95f848ae..d8670a4134 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/LongAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/LongAssertion_Test.java
@@ -39,9 +39,9 @@ class LongAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/MapAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/MapAssertion_Test.java
index d174c439f0..887685bf69 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/MapAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/MapAssertion_Test.java
@@ -42,9 +42,9 @@ class MapAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ObjectAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ObjectAssertion_Test.java
index dfc3036d11..bfb23092ab 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ObjectAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ObjectAssertion_Test.java
@@ -52,9 +52,9 @@ class ObjectAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/PrimitiveArrayAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/PrimitiveArrayAssertion_Test.java
index c7cf5bfc5a..f41c0f4acf 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/PrimitiveArrayAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/PrimitiveArrayAssertion_Test.java
@@ -44,9 +44,9 @@ class PrimitiveArrayAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = byteArray(null).setMsg("Foo {0}", 1);
+		var assertion1 = byteArray(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = byteArray(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = byteArray(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringAssertion_Test.java
index df2ed17595..c216b0807c 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringAssertion_Test.java
@@ -41,9 +41,9 @@ class StringAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringListAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringListAssertion_Test.java
index 3b70d34917..5b71fc1c25 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringListAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/StringListAssertion_Test.java
@@ -42,9 +42,9 @@ class StringListAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ThrowableAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ThrowableAssertion_Test.java
index 4c86e36205..6b0f820588 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ThrowableAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ThrowableAssertion_Test.java
@@ -52,9 +52,9 @@ class ThrowableAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Verify_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Verify_Test.java
index fa4c633c75..66bfaf57c4 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Verify_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/Verify_Test.java
@@ -67,10 +67,10 @@ class Verify_Test extends TestBase {
 		test(verify(Boolean.FALSE).isFalse()).isNull();
 		test(x1.is("foo")).isNull();
 
-		test(verify("foo").msg("bar{0}", "baz").is("foo")).isNull();
-		test(verify("foo").msg("bar{0}", "baz").is("bar")).is("barbaz");
-		test(verify("foo").msg("bar{0}", "baz").isType(Integer.class)).is("barbaz");
-		test(verify(null).msg("bar{0}", "baz").is("bar")).is("barbaz");
-		test(verify("foo").msg("bar{0}", "baz").is(null)).is("barbaz");
+		test(verify("foo").msg("bar%s", "baz").is("foo")).isNull();
+		test(verify("foo").msg("bar%s", "baz").is("bar")).is("barbaz");
+		test(verify("foo").msg("bar%s", "baz").isType(Integer.class)).is("barbaz");
+		test(verify(null).msg("bar%s", "baz").is("bar")).is("barbaz");
+		test(verify("foo").msg("bar%s", "baz").is(null)).is("barbaz");
 	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/VersionAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/VersionAssertion_Test.java
index e4262648a2..4423962558 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/VersionAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/VersionAssertion_Test.java
@@ -40,9 +40,9 @@ class VersionAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ZonedDateTimeAssertion_Test.java b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ZonedDateTimeAssertion_Test.java
index 1b7e2e3557..df1973a336 100644
--- a/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ZonedDateTimeAssertion_Test.java
+++ b/juneau-core/juneau-test/src/test/java/org/apache/juneau/test/assertions/ZonedDateTimeAssertion_Test.java
@@ -53,9 +53,9 @@ class ZonedDateTimeAssertion_Test extends TestBase {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	@Test void a01_msg() {
-		var assertion1 = test(null).setMsg("Foo {0}", 1);
+		var assertion1 = test(null).setMsg("Foo %s", 1);
 		assertThrows(BasicAssertionError.class, assertion1::isExists, "Foo 1");
-		var assertion2 = test(null).setMsg("Foo {0}", 1).setThrowable(RuntimeException.class);
+		var assertion2 = test(null).setMsg("Foo %s", 1).setThrowable(RuntimeException.class);
 		assertThrows(RuntimeException.class, assertion2::isExists, "Foo 1");
 	}
 
diff --git a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/BeanExample.java b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/BeanExample.java
index b2c7e342f2..ef99ac0bf0 100644
--- a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/BeanExample.java
+++ b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/BeanExample.java
@@ -24,9 +24,8 @@ import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
 import java.net.*;
 
 import org.apache.juneau.commons.http.*;
-import org.apache.juneau.marshall.html.*;
 import org.apache.juneau.marshall.json.*;
-import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Sample class which shows the usage of DTO module which is a
@@ -78,7 +77,7 @@ public class BeanExample {
 				)
 			);
 
-		var html = HtmlSerializer.DEFAULT.serialize(mytable);
+		var html = Html.of(mytable);
 
 		var mainJsp =
 			form().action("main.jsp").method("GET")
@@ -99,7 +98,7 @@ public class BeanExample {
 		 * <button type='reset'>Reset</button>
 		 * </form>
 		 */
-		html = HtmlSerializer.DEFAULT.serialize(mainJsp);
+		html = Html.of(mainJsp);
 
 		/**
 		 * Produces
@@ -113,7 +112,7 @@ public class BeanExample {
 		 *    ]
 		 * }
 		 */
-		html = Json5Serializer.DEFAULT.serialize(mainJsp);
+		html = Json5.of(mainJsp);
 
 		var feed =
 			feed("tag:foo.org", "Title", CONST_timestamp)
diff --git a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/atom/AtomJsonExample.java b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/atom/AtomJsonExample.java
index d32e154301..a0a17dc834 100644
--- a/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/atom/AtomJsonExample.java
+++ b/juneau-examples/juneau-examples-core/src/main/java/org/apache/juneau/examples/bean/atom/AtomJsonExample.java
@@ -16,7 +16,7 @@
  */
 package org.apache.juneau.examples.bean.atom;
 
-import org.apache.juneau.marshall.json5.*;
+import org.apache.juneau.marshall.marshaller.*;
 
 /**
  * Atom feed JSON example.
@@ -37,8 +37,8 @@ public class AtomJsonExample {
 
 		var feed = AtomFeed.getAtomFeed();
 
-		// Get JSON serializer with readable output.
-		var s = Json5Serializer.DEFAULT_READABLE;
+		// Get JSON marshaller with readable output.
+		var s = Json5.DEFAULT_READABLE;
 
 		// Serialize to ATOM/JSON
 		//Produces
@@ -119,6 +119,6 @@ public class AtomJsonExample {
 		 *  ]
 		 *  }
 		 */
-		var atomJson = s.serialize(feed);
+		var atomJson = s.write(feed);
 	}
 }
\ No newline at end of file
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/BasicRuntimeException_Test.java b/juneau-integration-tests/src/test/java/org/apache/juneau/BasicRuntimeException_Test.java
index ff17beef1f..0244cbd63c 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/BasicRuntimeException_Test.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/BasicRuntimeException_Test.java
@@ -40,7 +40,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -52,7 +52,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -64,7 +64,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -76,7 +76,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -88,7 +88,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -100,7 +100,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -112,7 +112,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -124,7 +124,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -136,7 +136,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertTrue(x.getMessage().contains("New message"));
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertTrue(x.getMessage().contains("Message arg1"));
 	}
 
@@ -148,7 +148,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
 
@@ -160,7 +160,7 @@ class BasicRuntimeException_Test extends TestBase {
 		assertEquals("New message", x.getMessage());
 
 		// Test setMessage with args
-		assertSame(x, x.setMessage("Message {0}", "arg1"));
+		assertSame(x, x.setMessage("Message %s", "arg1"));
 		assertEquals("Message arg1", x.getMessage());
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/ComboInput.java b/juneau-integration-tests/src/test/java/org/apache/juneau/ComboInput.java
index 05f871be96..5880d64848 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/ComboInput.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/ComboInput.java
@@ -296,8 +296,8 @@ public class ComboInput<T> {
 		for (var f : verify) {
 			var s = f.apply(o);
 			if (ine(s)) {
-				throw new BasicAssertionError("Verification failed on test {0}/{1}: {2}", label, testName, s);
+				throw new BasicAssertionError("Verification failed on test %s/%s: %s", label, testName, s);
 			}
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java b/juneau-integration-tests/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
index b007eb2e23..0269c4d66a 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/ComboRoundTrip_Tester.java
@@ -318,7 +318,7 @@ public class ComboRoundTrip_Tester<T> {
 		for (var v : verify) {
 			var s = v.apply(o);
 			if (ine(s)) {
-				throw new BasicAssertionError("Verification failed on test {0}/{1}: {2}", label, testName, s);
+				throw new BasicAssertionError("Verification failed on test %s/%s: %s", label, testName, s);
 			}
 		}
 	}
@@ -341,14 +341,14 @@ public class ComboRoundTrip_Tester<T> {
 				System.out.println(r);
 			}
 
-			assertEquals(exp, r, fs("{0}/{1} serialize-normal failed.", label, testName));
+			assertEquals(exp, r, fs("%s/%s serialize-normal failed.", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -365,14 +365,14 @@ public class ComboRoundTrip_Tester<T> {
 			o = postConvert.apply((T)o);
 			r = s.serializeToString(o);
 
-			assertEquals(exp, r, fs("{0}/{1} parse-normal failed", label, testName));
+			assertEquals(exp, r, fs("%s/%s parse-normal failed", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Throwable e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -393,7 +393,7 @@ public class ComboRoundTrip_Tester<T> {
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -408,14 +408,14 @@ public class ComboRoundTrip_Tester<T> {
 			var r = s.serializeToString(in.get());
 			var o = p.parse(r, type);
 			r = jsonForEquivalency.serialize(o);
-			assertEquals(exp, r, fs("{0}/{1} parse-normal failed on JSON equivalency", label, testName));
+			assertEquals(exp, r, fs("%s/%s parse-normal failed on JSON equivalency", label, testName));
 		} catch (AssertionError e) {
 			if (exceptionMsg == null)
 				throw e;
 			assertContains(exceptionMsg, e.getMessage());
 		} catch (Exception e) {
 			if (exceptionMsg == null)
-				throw new BasicAssertionError(e, "{0}/{1} failed.  exception={2}", label, testName, e.getLocalizedMessage());
+				throw new BasicAssertionError(e, "%s/%s failed.  exception=%s", label, testName, e.getLocalizedMessage());
 			assertContains(exceptionMsg, e.getMessage());
 		}
 	}
@@ -424,4 +424,4 @@ public class ComboRoundTrip_Tester<T> {
 	public String toString() {
 		return "ComboRoundTripTester: " + label;
 	}
-}
\ No newline at end of file
+}
diff --git a/juneau-integration-tests/src/test/java/org/apache/juneau/ComboSerialize_Tester.java b/juneau-integration-tests/src/test/java/org/apache/juneau/ComboSerialize_Tester.java
index 95c7a44158..ad58e12aa9 100644
--- a/juneau-integration-tests/src/test/java/org/apache/juneau/ComboSerialize_Tester.java
+++ b/juneau-integration-tests/src/test/java/org/apache/juneau/ComboSerialize_Tester.java
... 4512 lines suppressed ...